如何在多个子图中绘图

Posted

技术标签:

【中文标题】如何在多个子图中绘图【英文标题】:How to plot in multiple subplots 【发布时间】:2022-01-21 13:04:45 【问题描述】:

我对这段代码的工作原理有点困惑:

fig, axes = plt.subplots(nrows=2, ncols=2)
plt.show()

在这种情况下,无花果轴是如何工作的?它有什么作用?

还有为什么这不能做同样的事情:

fig = plt.figure()
axes = fig.subplots(nrows=2, ncols=2)

【问题讨论】:

【参考方案1】:

有几种方法可以做到这一点。 subplots 方法创建图形以及随后存储在 ax 数组中的子图。例如:

import matplotlib.pyplot as plt

x = range(10)
y = range(10)

fig, ax = plt.subplots(nrows=2, ncols=2)

for row in ax:
    for col in row:
        col.plot(x, y)

plt.show()

然而,这样的事情也可以,但它不是那么“干净”,因为你正在创建一个带有子图的图形,然后在它们之上添加:

fig = plt.figure()

plt.subplot(2, 2, 1)
plt.plot(x, y)

plt.subplot(2, 2, 2)
plt.plot(x, y)

plt.subplot(2, 2, 3)
plt.plot(x, y)

plt.subplot(2, 2, 4)
plt.plot(x, y)

plt.show()

【讨论】:

【参考方案2】:
import matplotlib.pyplot as plt

fig, ax = plt.subplots(2, 2)

ax[0, 0].plot(range(10), 'r') #row=0, col=0
ax[1, 0].plot(range(10), 'b') #row=1, col=0
ax[0, 1].plot(range(10), 'g') #row=0, col=1
ax[1, 1].plot(range(10), 'k') #row=1, col=1
plt.show()

【讨论】:

我知道ax 是什么,但不知道fig 是什么。它们是什么? ax 实际上是一个 numpy 数组。 fig 是matplotlib.figure.Figure 类,通过它您可以对绘制的图形进行大量操作。例如,您可以将颜色条添加到特定的子图,您可以更改所有子图后面的背景颜色。您可以修改这些子图的布局或为其添加新的小斧头。最好你可能想要一个可以通过fig.suptitle(title) 方法获得的所有子图的主标题。最后,一旦您对情节感到满意,您可以使用fig.savefig 方法保存它。 @Leevo【参考方案3】:

你也可以在 subplots 调用中解压坐标轴

并设置是否要在子图之间共享x轴和y轴

像这样:

import matplotlib.pyplot as plt
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True)
ax1.plot(range(10), 'r')
ax2.plot(range(10), 'b')
ax3.plot(range(10), 'g')
ax4.plot(range(10), 'k')
plt.show()

【讨论】:

【参考方案4】:

您可能对从 matplotlib 版本 2.1 开始该问题的第二个代码也可以正常工作这一事实感兴趣。

来自change log:

Figure 类现在有 subplots 方法 Figure 类现在有一个 subplots() 方法,其行为与 pyplot.subplots() 相同,但在现有图形上。

例子:

import matplotlib.pyplot as plt

fig = plt.figure()
axes = fig.subplots(nrows=2, ncols=2)

plt.show()

【讨论】:

【参考方案5】:

阅读文档:matplotlib.pyplot.subplots

pyplot.subplots() 返回一个元组 fig, ax,它使用符号解包在两个变量中

fig, axes = plt.subplots(nrows=2, ncols=2)

代码:

fig = plt.figure()
axes = fig.subplots(nrows=2, ncols=2)

不起作用,因为subplots()pyplot 中的一个函数,而不是Figure 对象的成员。

【讨论】:

【参考方案6】:

依次遍历所有子图:

fig, axes = plt.subplots(nrows, ncols)

for ax in axes.flatten():
    ax.plot(x,y)

访问特定索引:

for row in range(nrows):
    for col in range(ncols):
        axes[row,col].plot(x[row], y[col])

【讨论】:

【参考方案7】:

带有熊猫的子图

此答案适用于带有pandas 的子图,它使用matplotlib 作为默认绘图后端。 这里有四个选项来创建以pandas.DataFrame 开头的子图 实施 1. 和 2. 用于宽格式数据,为每列创建子图。 实现 3. 和 4. 适用于长格式数据,为列中的每个唯一值创建子图。 python 3.8.11pandas 1.3.2matplotlib 3.4.3seaborn 0.11.2中测试

进口和数据

import seaborn as sns  # data only
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# wide dataframe
df = sns.load_dataset('planets').iloc[:, 2:5]

   orbital_period   mass  distance
0         269.300   7.10     77.40
1         874.774   2.21     56.95
2         763.000   2.60     19.84
3         326.030  19.40    110.62
4         516.220  10.50    119.47

# long dataframe
dfm = sns.load_dataset('planets').iloc[:, 2:5].melt()

         variable    value
0  orbital_period  269.300
1  orbital_period  874.774
2  orbital_period  763.000
3  orbital_period  326.030
4  orbital_period  516.220

1。 subplots=Truelayout,对于每一列

pandas.DataFrame.plot中使用参数subplots=Truelayout=(rows, cols) 此示例使用kind='density',但kind 有不同的选项,这适用于所有选项。如果不指定kind,则默认使用折线图。 ax 是由 pandas.DataFrame.plot 返回的 AxesSubplot 数组 如果需要,请参阅How to get a Figure object。 How to save pandas subplots
axes = df.plot(kind='density', subplots=True, layout=(2, 2), sharex=False, figsize=(10, 6))

# extract the figure object; only used for tight_layout in this example
fig = axes[0][0].get_figure() 

# set the individual titles
for ax, title in zip(axes.ravel(), df.columns):
    ax.set_title(title)
fig.tight_layout()
plt.show()

2。 plt.subplots,对于每一列

使用matplotlib.pyplot.subplots 创建一个Axes 数组,然后将axes[i, j]axes[n] 传递给ax 参数。 此选项使用pandas.DataFrame.plot,但可以使用其他axes 级别绘图调用作为替代(例如sns.kdeplotplt.plot 等) 使用.ravel.flattenAxes 的子图数组折叠成一维是最简单的。见.ravel vs .flatten。 适用于每个axes 的任何需要迭代的变量都与.zip 组合在一起(例如colsaxescolorspalette 等)。每个对象的长度必须相同。
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 6))  # define the figure and subplots
axes = axes.ravel()  # array to 1D
cols = df.columns  # create a list of dataframe columns to use
colors = ['tab:blue', 'tab:orange', 'tab:green']  # list of colors for each subplot, otherwise all subplots will be one color

for col, color, ax in zip(cols, colors, axes):
    df[col].plot(kind='density', ax=ax, color=color, label=col, title=col)
    ax.legend()
    
fig.delaxes(axes[3])  # delete the empty subplot
fig.tight_layout()
plt.show()

1. 和 2. 的结果。

3。 plt.subplots,对于.groupby 中的每个组

这类似于 2.,不同之处在于它将 coloraxes 压缩到 .groupby 对象。
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 6))  # define the figure and subplots
axes = axes.ravel()  # array to 1D
dfg = dfm.groupby('variable')  # get data for each unique value in the first column
colors = ['tab:blue', 'tab:orange', 'tab:green']  # list of colors for each subplot, otherwise all subplots will be one color

for (group, data), color, ax in zip(dfg, colors, axes):
    data.plot(kind='density', ax=ax, color=color, title=group, legend=False)

fig.delaxes(axes[3])  # delete the empty subplot
fig.tight_layout()
plt.show()

4。 seaborn人物级剧情

使用seaborn 图形级图,并使用colrow 参数。 seabornmatplotlib 的高级 API。见seaborn: API reference
p = sns.displot(data=dfm, kind='kde', col='variable', col_wrap=2, x='value', hue='variable',
                facet_kws='sharey': False, 'sharex': False, height=3.5, aspect=1.75)
sns.move_legend(p, "upper left", bbox_to_anchor=(.55, .45))

【讨论】:

【参考方案8】:

其他答案很好,这个答案是一个可能有用的组合。

import numpy as np
import matplotlib.pyplot as plt

# Optional: define x for all the sub-plots
x = np.linspace(0,2*np.pi,100)

# (1) Prepare the figure infrastructure 
fig, ax_array = plt.subplots(nrows=2, ncols=2)

# flatten the array of axes, which makes them easier to iterate through and assign
ax_array = ax_array.flatten()

# (2) Plot loop
for i, ax in enumerate(ax_array):
  ax.plot(x , np.sin(x + np.pi/2*i))
  #ax.set_title(f'plot i')

# Optional: main title
plt.suptitle('Plots')

总结

    准备图基础设施 获取 ax_array,一个子图数组 展平数组以便在一个“for 循环”中使用它 绘图循环 循环平展的 ax_array 以更新子图 可选:使用枚举来跟踪子图号 一旦展平,每个ax_array 都可以从0nrows x ncols -1 单独索引(例如ax_array[0]ax_array[1]ax_array[2]ax_array[3])。

【讨论】:

【参考方案9】:

这是一个简单的解决方案

fig, ax = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=False)
for sp in fig.axes:
    sp.plot(range(10))

【讨论】:

【参考方案10】:

axes数组转换为一维

使用plt.subplots(nrows, ncols) 生成子图,其中both nrows 和ncols 均大于1,返回<AxesSubplot:> 对象的嵌套数组。 在nrows=1ncols=1 的情况下没有必要将axes 展平,因为axes 已经是一维的,这是默认参数squeeze=True 的结果 访问对象的最简单方法是使用.ravel().flatten().flat 将数组转换为一维。 .ravel vs. .flatten flatten 总是返回一个副本。 ravel 尽可能返回原始数组的视图。 axes 的数组转换为一维数组后,有多种绘图方法。
import matplotlib.pyplot as plt
import numpy as np  # sample data only

# example of data
rads = np.arange(0, 2*np.pi, 0.01)
y_data = np.array([np.sin(t*rads) for t in range(1, 5)])
x_data = [rads, rads, rads, rads]

# Generate figure and its subplots
fig, axes = plt.subplots(nrows=2, ncols=2)

# axes before
array([[<AxesSubplot:>, <AxesSubplot:>],
       [<AxesSubplot:>, <AxesSubplot:>]], dtype=object)

# convert the array to 1 dimension
axes = axes.ravel()

# axes after
array([<AxesSubplot:>, <AxesSubplot:>, <AxesSubplot:>, <AxesSubplot:>],
      dtype=object)
    遍历扁平数组 如果子图比数据多,这将导致IndexError: list index out of range 改用选项 3,或选择轴的子集(例如 axes[:-2]
for i, ax in enumerate(axes):
    ax.plot(x_data[i], y_data[i])
    按索引访问每个轴
axes[0].plot(x_data[0], y_data[0])
axes[1].plot(x_data[1], y_data[1])
axes[2].plot(x_data[2], y_data[2])
axes[3].plot(x_data[3], y_data[3])
    索引数据和坐标轴
for i in range(len(x_data)):
    axes[i].plot(x_data[i], y_data[i])
    zip 将坐标轴和数据放在一起,然后遍历元组列表
for ax, x, y in zip(axes, x_data, y_data):
    ax.plot(x, y)

输出

【讨论】:

【参考方案11】:

如果您真的想使用循环,请执行以下操作:

def plot(data):
    fig = plt.figure(figsize=(100, 100))
    for idx, k in enumerate(data.keys(), 1):
        x, y = data[k].keys(), data[k].values
        plt.subplot(63, 10, idx)
        plt.bar(x, y)  
    plt.show()

【讨论】:

以上是关于如何在多个子图中绘图的主要内容,如果未能解决你的问题,请参考以下文章

如何避免熊猫直方图子图中的绘图标题和轴标题之间的重叠? [复制]

R语言绘图如何让多个图像显示于同一图中

如何在子图中绘制多个 Seaborn 联合图

MATLAB - 如何一起缩放子图?

如何在 r 图中为多个图例自动定位图例?

更改绘图子图中的单轴