【问题标题】:Dynamically add/create subplots in matplotlib在 matplotlib 中动态添加/创建子图
【发布时间】:2012-09-01 10:29:27
【问题描述】:

我想创建一个由多个共享 x/y 轴的子图组成的图。 从文档中看应该是这样的(尽管我的子图是散点图):(code here)

但我想动态创建子图!

所以子图的数量取决于前一个函数的输出。 (每个图表可能会有大约 3 到 15 个子图,每个子图都来自不同的数据集,具体取决于我的脚本的输入。)

谁能告诉我如何做到这一点?

【问题讨论】:

  • 你不能使用plt.subplots(numplots, sharex=True, sharey=True)numplots 一个变量吗?
  • @Tim - 您应该将其发布为答案。 :) (很多人不知道subplots。它相对较新。)
  • 嗯,它在上面链接的源代码中,所以我猜还有另一个问题。

标签: python matplotlib


【解决方案1】:

假设您知道要使用的子图总数总列

import matplotlib.pyplot as plt

# Subplots are organized in a Rows x Cols Grid
# Tot and Cols are known

Tot = number_of_subplots
Cols = number_of_columns

# Compute Rows required

Rows = Tot // Cols 
Rows += Tot % Cols

# Create a Position index

Position = range(1,Tot + 1)

Rows 的第一个实例仅考虑完全由子图填充的行,然后如果 1 或 2 或 ... Cols - 1 个子图仍需要位置,则再添加一个 Row。

然后创建图形并使用 for 循环添加子图

# Create main figure

fig = plt.figure(1)
for k in range(Tot):

  # add every single subplot to the figure with a for loop

  ax = fig.add_subplot(Rows,Cols,Position[k])
  ax.plot(x,y)      # Or whatever you want in the subplot

plt.show()

请注意,您需要范围 Position 才能将子图移动到正确的位置。

【讨论】:

  • 谢谢你,@matteos,我在我的代码中实现了你的建议!
  • 希望对您有所帮助! :)
  • 建议:Cols = int(Tot**0.5)(Tot 的平方根)
  • 导入应该是import matplotlib.pyplot as plt
【解决方案2】:

我发现不是自己计算行数和列数,而是先使用plt.subplots 创建子图更容易,然后遍历轴对象以添加图。

import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=3, ncols=2, figsize=(12, 8))
x_array = np.random.randn(6, 10)
y_array = np.random.randn(6, 10)

i = 0
for row in axes:
    for ax in row:
        x = x_array[i] 
        y = y_array[i]
        ax.scatter(x, y)
        ax.set_title("Plot " + str(i))
        i += 1
plt.tight_layout()
plt.show()

这里我使用 i 遍历 x_arrayy_array 的元素,但您同样可以轻松地遍历函数或数据框列以动态生成图形。

【讨论】:

  • 这个解决方案可以通过像这样循环轴来简化:for i, ax in enumerate(axes.flat): ax.scatter(x_array[i], y_array[i]); ax.set_title(f'Plot {i}')
【解决方案3】:

Based on this post,你想做的是这样的:

import matplotlib.pyplot as plt

# Start with one
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([1,2,3])

# Now later you get a new subplot; change the geometry of the existing
n = len(fig.axes)
for i in range(n):
    fig.axes[i].change_geometry(n+1, 1, i+1)

# Add the new
ax = fig.add_subplot(n+1, 1, n+1)
ax.plot([4,5,6])

plt.show() 

但是,Paul Hanswer 指向名为 gridspec 的子模块,这可能会使上述操作更容易。我把它作为练习留给读者^_~。

【讨论】:

  • 如果你有 x 个列,而不仅仅是一个列,你会怎么做?如果您将 change_geometry 中的 '1' 参数更改为其他内容,则第一个图将跨越所有列,而不是重新分配到单个列。
  • @DirkHaupt:我不知道答案,但我赞成你的问题!谢谢。
  • change_geometrydeprecated。我想出了一个新的解决方案here,基于set_subplotspec 函数。
  • 考虑到 OP 希望“动态创建子图”,这似乎是唯一的答案。
【解决方案4】:
import matplotlib.pyplot as plt
from pylab import *
import numpy as np

x = np.linspace(0, 2*np.pi, 400)
y = np.sin(x**2)

subplots_adjust(hspace=0.000)
number_of_subplots=3

for i,v in enumerate(xrange(number_of_subplots)):
    v = v+1
    ax1 = subplot(number_of_subplots,1,v)
    ax1.plot(x,y)

plt.show()

此代码有效,但您需要更正坐标轴。我曾经subplot 在同一列中绘制 3 个图。您需要做的就是为number_of_plots 变量分配一个整数。如果每个图的 X 和 Y 值不同,则需要为每个图分配它们。

subplot 的工作方式如下,例如,如果我的子图值为3,1,1。这将创建一个 3x1 网格并将绘图放置在第一个位置。在下一次交互中,如果我的subplot 值为3,1,2,它将再次创建一个 3x1 网格,但将绘图放置在第二个位置,依此类推。

【讨论】:

  • 感谢您的解释!我不了解文档中子图值的工作方式,但现在很清楚了。谢谢!但是有一个问题:使用for i,v in enumerate(xrange(number_of_subplots)) 而不是for i in range(number_of_subplots) 有什么好处?即使您需要两次相同的值(您的代码似乎不需要),您不能只使用两次 i 吗?还是我错过了什么? (我还是个初学者,所以很好奇。)
  • @Lastalda 您确实可以在您的情况下使用(xrange(number_if_plots))。实际上,您建议的方式要简单得多。我为将来的情况做了for i,v in enumerate(xrange(number_of_subplots)),比如说如果我需要同时检查一个列表,我所要做的就是取出xrange()。然后i 将成为列表中的值,v 将保持为整数。所以我可以使用v 变量定位绘图并使用i 分配x 和y 值。希望这是有道理的
  • meh 为什么不只是整理代码而不是保护它。 for i in range(3): ...
  • 尝试此代码时出现错误:NameError: name 'xrange' is not defined。抱歉,这应该是一些愚蠢的错误,但我是 Python 的绝对初学者。有什么想法吗?
  • @Harpal,如何为每个子图添加标题和整体图的图例?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-22
  • 2013-09-24
  • 1970-01-01
  • 2017-07-20
  • 2016-04-28
  • 1970-01-01
相关资源
最近更新 更多