【问题标题】:Can you copy only some subplots to a new figure?您可以仅将一些子图复制到新图形吗?
【发布时间】:2019-08-20 13:00:56
【问题描述】:

有没有办法将轴(子图)复制到新图形? 这在其他语言中很简单,但我知道即使是深拷贝也不能与 python 的 matplotlib 一起使用。 例如。如果我有一个包含 6 个子图的图形,我如何将其中的 2 个子图复制到一个新图形,并设置所有设置?标签、刻度线、图例、网格等。

我发现了这个 answer ,它实际上是二合一:第一个不再有效(不推荐使用的语法),而我无法让第二个在我的情况下工作。

我设法重新创建了一个新图形并删除了我不想要的子图,但我留下了一个 3x2 网格的子图,其中 2 个被绘制,4 个为空。 有什么建议吗?

我在下面整理了一个玩具示例;当然,我的图表会随着设置的增加而变得更加复杂。

请注意,我使用了 seaborn,但它应该无关紧要 - 我相信这是一个 matplotlib 问题,无论是否使用 seaborn,答案都是一样的。

更新:按照@Earnest 的提示,我可以更改新图形的几何形状,使其只有两个子图,这样做:

axes.change_geometry(1,2,2)

我不知道该怎么做是移动子图。回顾一下:

  • 我从 3x2 网格中的 6 个子图开始。
  • 我腌制到记忆,然后解封到一个新的数字。
  • 在新图中,我只保留子图 1 和 2,即由 [rows, columns] [0,1] 和 [1,0] 标识的子图;其他 4 个子图现在是空格。
  • 我想要一个 [1x2] 网格布局;如果我这样做 axes.change_geometry(1,2,2) 然后我得到了那个布局,但是我的两个子图之一消失了。

有什么建议吗?

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib
    import seaborn as sns
    import pickle
    import io


    sns.set(style='darkgrid')

    n=int(100)
    x=np.arange(0,n)

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

    for i,a in enumerate(ax.flatten() ):
        y= np.random.rand(n)
        sns.lineplot( x, y , ax =a )
        a.set_title('Chart # ' + str(i+1))
        a.set_xlabel('my x')
        a.set_ylabel('my y')

    fig2, ax2 = plt.subplots(1,2)

    buf = io.BytesIO()
    pickle.dump(fig, buf)
    buf.seek(0)

    fig2=pickle.load(buf)

    tokeep=[1,2]

    # note that i == 1correponds to a[0,1]
    for i,a in enumerate(fig2.axes):
        if not i in(tokeep):
            fig2.delaxes(a)
        else:
            axes=a

【问题讨论】:

  • 在深入研究之前,您为什么不使用该答案中的第二种方法,即在新图中从头开始创建图?
  • 因为就我而言,它们确实非常复杂。我有 60 多行代码可以选择要绘制的内容、在哪个子图中、如何对其进行缩放、如何标记所有内容、在对数刻度上绘制哪个子图等。对于一个非常简单的图,设置它的次数不多重新绘制它并重新应用您拥有的任何设置可能会更容易,但这不是我的情况。
  • 也许这是一个糟糕的设计选择?可以简单地将每种绘图放入一个函数中,该函数将有关绘图的内容和位置的必要信息作为参数。关于问题中的代码,您可能需要创建一个新的网格规范并使用ax.set_position() 将轴定位在该新网格上。
  • 嗯,我的设计并不理想,但是所有的子图都共享一些设置;在绘制单独子图的每个函数中执行相同的格式设置也不理想。至于答案的其余部分,您所说的新网格规范到底是什么意思?创造一个新形象?或者删除一些子图(我在我的玩具示例中这样做)?
  • 听起来不错。请注意,在您的代码中,您只保留一个 axes(其中 tokeep 是 2)。您将需要存储两个轴并为两者执行change_geometry

标签: python matplotlib seaborn


【解决方案1】:

这真的是@Ernest 的回答;他给我指出了正确的方向。我在这里输入这个作为将来参考的答案,希望它对其他人有用。基本上我必须在删除不需要的子图后使用 change_geometry。我认为 R 宇宙中的 ggplot 有一个更清晰的实现,但是,总的来说,这似乎还可以 - 不太麻烦。 我已经评论了下面的代码 - 希望它足够清楚:

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pickle
import io

sns.set(style='darkgrid')

#create the subplots
n=int(100)
x=np.arange(0,n)
fig, ax = plt.subplots(3,2)

for i,a in enumerate(ax.flatten() ):
    y= np.random.rand(n)
    sns.lineplot( x, y , ax =a )
    a.set_title('Chart # ' + str(i+1))
    a.set_xlabel('my x')
    a.set_ylabel('my y')

# pickle the figure, then unpickle it to a new figure
buf = io.BytesIO()
pickle.dump(fig, buf)
buf.seek(0)
fig2=pickle.load(buf)

# sets which subplots to keep
# note that i == 1correponds to a[0,1]
tokeep=[1,2]
axestokeep=[]

for i,a in enumerate(fig2.axes):
    if not i in(tokeep):
        fig2.delaxes(a)
    else:
        axestokeep.extend([a])

axestokeep[0].change_geometry(1,2,1)
axestokeep[1].change_geometry(1,2,2)

【讨论】:

    猜你喜欢
    • 2021-07-26
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多