在单个循环中使用子图绘制多个图形

Posted

技术标签:

【中文标题】在单个循环中使用子图绘制多个图形【英文标题】:Plotting on multiple figures with subplots in a single loop 【发布时间】:2018-03-16 08:40:15 【问题描述】:

我正在绘制两个数字,每个数字都有多个子图。我需要在一个循环中执行此操作。当我只有一个人物时,我会这样做:

fig, ax = plt.subplots(nrows=6,ncols=6,figsize=(20, 20))
fig.subplots_adjust(hspace=.5,wspace=0.4)
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)

for x in range(1,32):
    plt.subplot(6,6,x)
    plt.title('day='+str(x))
    plt.scatter(x1,y1)
    plt.scatter(x2,y2)
    plt.colorbar().set_label('Distance from ocean',rotation=270)
plt.savefig('Plots/everyday_D color.png')    
plt.close()

现在我知道当您有多个数字时,您需要执行以下操作:

fig1, ax1 = plt.subplots()
fig2, ax2 = plt.subplots()

但我不知道如何在循环中绘制,每个子图都在它的位置(因为如果有两个数字,你就不能继续做 plt.scatter )。请具体说明我需要做什么(关于是否是fig1.scatter,ax1.scatter,fig.subplots_adjust,...以及最后如何保存和关闭)

【问题讨论】:

【参考方案1】:

每个pyplot函数在面向对象API中都有对应的方法。如果您真的想同时遍历两个图形的轴,则如下所示:

import numpy as np
import matplotlib.pyplot as plt

x1 = x2 = np.arange(10)
y1 = y2 = c = np.random.rand(10,6)

fig1, axes1 = plt.subplots(nrows=2,ncols=3)
fig1.subplots_adjust(hspace=.5,wspace=0.4)

fig2, axes2 = plt.subplots(nrows=2,ncols=3)
fig2.subplots_adjust(hspace=.5,wspace=0.4)

for i, (ax1,ax2) in enumerate(zip(axes1.flatten(), axes2.flatten())):
    ax1.set_title('day='+str(i))
    ax2.set_title('day='+str(i))
    sc1 = ax1.scatter(x1,y1[:,i], c=c[:,i])
    sc2 = ax2.scatter(x2,y2[:,i], c=c[:,i])
    fig1.colorbar(sc1, ax=ax1)
    fig2.colorbar(sc2, ax=ax2)

plt.savefig("plot.png") 
plt.show()   
plt.close()

在这里,您循环遍历两个展平的轴数组,这样ax1ax2 就是要绘制到的matplotlib axes。 fig1fig2 是 matplotlib 数字 (matplotlib.figure.Figure)。

为了也获得索引,使用enumerate。所以这条线

for i, (ax1,ax2) in enumerate(zip(axes1.flatten(), axes2.flatten())):
    # loop code

在这里等价于

for i in range(6):
    ax1 = axes1.flatten()[i]
    ax2 = axes2.flatten()[i]
    # loop code

i = 0
for ax1,ax2 in zip(axes1.flatten(), axes2.flatten()):
    # loop code
    i += 1

两者都写得更长。

此时您可能会对以下事实感兴趣:尽管上述使用面向对象 API 的解决方案肯定更通用且更可取,但纯 pyplot 解决方案仍然是可能的。这看起来像

import numpy as np
import matplotlib.pyplot as plt

x1 = x2 = np.arange(10)
y1 = y2 = c = np.random.rand(10,6)

plt.figure(1)
plt.subplots_adjust(hspace=.5,wspace=0.4)

plt.figure(2)
plt.subplots_adjust(hspace=.5,wspace=0.4)

for i in range(6):
    plt.figure(1)
    plt.subplot(2,3,i+1)
    sc1 = plt.scatter(x1,y1[:,i], c=c[:,i])
    plt.colorbar(sc1)

    plt.figure(2)
    plt.subplot(2,3,i+1)
    sc2 = plt.scatter(x1,y1[:,i], c=c[:,i])
    plt.colorbar(sc2)

plt.savefig("plot.png") 
plt.show()   
plt.close()

【讨论】:

感谢您的回答。我知道枚举基本上在 for 循环中创建索引。那么 ax1 和 ax2 只是索引吗?你能解释一下这个例子中的 ax1、axes1 和 fig1 是什么类型的对象吗? ax1ax2 是 matplotlib 轴。 enumerate 是一种在循环中获取索引的简单方法。也许this 有助于更好地理解枚举。我也更新了答案。【参考方案2】:

这里的版本显示了如何在两个不同的图形上运行散点图。基本上,您引用使用 plt.subplots 创建的轴。

import matplotlib.pyplot as plt
import numpy as np

x1 = y1 = range(10)
x2 = y2 = range(5)

nRows = nCols = 6
fig1, axesArray1 = plt.subplots(nrows=nRows,ncols=nCols,figsize=(20, 20))
fig1.subplots_adjust(hspace=.5,wspace=0.4)
fig1.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)

fig2, axesArray2 = plt.subplots(nrows=nRows,ncols=nCols,figsize=(20, 20))
fig2.subplots_adjust(hspace=.5,wspace=0.4)
fig2.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)

days = range(1, 32)
dayRowCol = np.array([i + 1 for i in range(nRows * nCols)]).reshape(nRows, nCols)
for day in days:
    rowIdx, colIdx = np.argwhere(dayRowCol == day)[0]

    axis1 = axesArray1[rowIdx, colIdx]
    axis1.set_title('day=' + str(day))
    axis1.scatter(x1, y1)

    axis2 = axesArray2[rowIdx, colIdx]
    axis2.set_title('day=' + str(day))
    axis2.scatter(x2, y2)

    # This didn't run in the original script, so I left it as is
    # plt.colorbar().set_label('Distance from ocean',rotation=270)

fig1.savefig('plots/everyday_D1_color.png')
fig2.savefig('plots/everyday_D2_color.png')
plt.close('all')

当我从plt.colorbar() 帖子中获取原始代码时引发了一个错误,所以我在答案中省略了它。如果您有一个 colorbar 打算如何工作的示例,我们可以看看如何在两个数字上实现这一点,但其余代码应该按预期工作!

请注意,如果day each 没有出现在dayRolCol numpy 中会引发错误,您可以自行决定如何处理这种情况。此外,使用 numpy 绝对不是唯一的方法,只是我喜欢的一种方法 - 你真正需要做的就是找到一种方法将某一天/情节与 (x, y) 的索引联系起来您要绘制的轴。

【讨论】:

如果您回答一个已经有答案的问题,最好明确说明您的不同之处。仅仅有两次相同的解决方案是没有用的。另一个答案还显示了如何使用颜色条,所以我认为说“我们”可以看看它是如何工作的是没有意义的——如果你愿意,你自己可以看看。 感谢您的回复。一个问题是axis1和axis2是从哪里来的。与您之前介绍的 axesArray1 似乎没有任何联系(或者这只是一个错误)? @ImportanceOfBeingErnest 你是对的,在我写答案时出现了另一个答案,直到之后我才看到它 @Drproctor axis1 是从 axesArray1 创建的,如下所示:axis1 = axesArray1[rowIdx, colIdx]axis2 以类似的方式制作

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

如何在seaborn中将多个图形绘制为数据框的子图和多列?

通过循环和函数填充 matplotlib 子图

python 循环绘制子图时,设置共享xy轴

使用绘图子图时绘制自定义误差线

在matlab中绘制一个有很多子图的大图

使用 Pandas 在多个子图行中绘制条形图