Python matplotlib:组合不同的图形并将它们放在一个共享一个共同图例的子图中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16748577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 23:33:13  来源:igfitidea点击:

matplotlib: combine different figures and put them in a single subplot sharing a common legend

pythonmatplotlib

提问by Saullo G. P. Castro

We have a code that creates figures from input.txt files. We need to combine 2 of these figures in a single subplot. The data from figure1 will be plotted in the left subplot and from figure2 in the right subplot, sharing the same legend and witht he same scale in axes x and y:

我们有一个从 input.txt 文件创建数字的代码。我们需要将这些数字中的 2 个组合在一个子图中。图 1 中的数据将绘制在左侧子图中,图 2 中的数据将绘制在右侧子图中,共享相同的图例,并且在 x 和 y 轴上具有相同的比例:

enter image description here

在此处输入图片说明

Here there is some example data:

这里有一些示例数据:

x  = [ 1, 2, 3, 5, 10, 100, 1000 ]
y1 = [ 1, 0.822, 0.763, 0.715, 0.680, 0.648, 0.645 ]
y2 = [ 1, 0.859, 0.812, 0.774, 0.746, 0.721, 0.718 ]

import matplotlib.pyplot as plt
# mode 01 from one case
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.plot( x, y1, label='mode 01' )
# mode 01 from other case
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.plot( x, y2, label='mode 01' )


EDIT: the method suggested by @nordev works. Now it would be really convenient to pass the ax1 and ax2 objects to the new figure, since they have much more information. It seems that there is no straightforward way to achieve that.

编辑:@nordev 建议的方法有效。现在将 ax1 和 ax2 对象传递给新图形会非常方便,因为它们有更多的信息。似乎没有直接的方法来实现这一目标

The real case has been made available here. To make it work, please run plot_both.py.

实际情况下,已提供在这里。要使其工作,请运行plot_both.py.



EDIT2: it was easier to change the routine that reads the input.txt files. Now it supports multiple plots. But the question is still valid because it would be great to treat the AxesSubplotas an easily interchangeable object among different figures, subplots and so forth...

EDIT2:更改读取 input.txt 文件的例程更容易。现在它支持多个绘图。但是这个问题仍然有效,因为将AxesSubplot视为不同图形、次要情节等之间易于互换的对象会很棒……

采纳答案by sodd

Does this solve your problem?

这能解决您的问题吗?

x  = [ 1, 2, 3, 5, 10, 100, 1000 ]
y1 = [ 1, 0.822, 0.763, 0.715, 0.680, 0.648, 0.645 ]
y2 = [ 1, 0.859, 0.812, 0.774, 0.746, 0.721, 0.718 ]

import matplotlib.pyplot as plt
from matplotlib.transforms import BlendedGenericTransform
# mode 01 from one case
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
line1, = ax1.plot( x, y1, label='mode 01' )
# mode 01 from other case
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
line2, = ax2.plot( x, y2, label='mode 01' )

# Create new figure and two subplots, sharing both axes
fig3, (ax3, ax4) = plt.subplots(1,2,sharey=True, sharex=True,figsize=(10,5))

# Plot data from fig1 and fig2
line3, = ax3.plot(line1.get_data()[0], line1.get_data()[1])
line4, = ax4.plot(line2.get_data()[0], line2.get_data()[1])
# If possible (easy access to plotting data) use
# ax3.plot(x, y1)
# ax4.lpot(x, y2)

ax3.set_ylabel('y-axis')
ax3.grid(True)
ax4.grid(True)

# Add legend
fig3.legend((line3, line4),
            ('label 3', 'label 4'),
            loc = 'upper center',
            bbox_to_anchor = [0.5, -0.05],
            bbox_transform = BlendedGenericTransform(fig3.transFigure, ax3.transAxes))
# Make space for the legend beneath the subplots
plt.subplots_adjust(bottom = 0.2)
# Show only fig3
fig3.show()

This gives output as seen below enter image description here

这给出了如下所示的输出 在此处输入图片说明

Edit

编辑

Looking at the code in your uploaded zip-file, I'd say most of the requested functionality is achieved?

查看您上传的 zip 文件中的代码,我想说大部分请求的功能都已实现?

I see you have changed the function creating the plots, making the solution to your problem radically different, as you are no longer trying to "merge" two subplots from different figures. Your solution is basically the same as the one I presented above, in the sense that both are creating both Axesinstances as subplots on the same figure (giving the desired layout), and thenplotting, rather than plotting, then extract/move the axes, as your question was concerning originally.

我看到您更改了创建绘图的功能,使您的问题的解决方案完全不同,因为您不再试图“合并”来自不同图形的两个子图。您的解决方案与我上面介绍的解决方案基本相同,从某种意义上说,两者都将两个Axes实例创建为同一图形上的子图(给出所需的布局),然后绘制,而不是绘制,然后提取/移动轴,因为你的问题最初是关于的。

As I suspected, the easiest and most trivial solution is to make the individual Axessubplots of the same figure instead of having them tied to separate figures, as moving one Axesinstance from one Figureto another is not easily accomplished (if at all possible), as specified in a comment. The "original" problem still seems to be very hard to accomplish, as simply adding an Axesinstance to the Figure's _axstackmakes it hard to customize to the desired layout.

正如我所怀疑的,最简单和最简单的解决方案是制作Axes同一图形的各个子图,而不是将它们绑定到单独的图形,因为将一个Axes实例从一个实例移动Figure到另一个实例并不容易(如果可能的话),如指定的那样在评论中。“原始”问题似乎仍然很难完成,因为简单地将Axes实例添加到Figure's_axstack很难自定义所需的布局。

One modification to the ax.legend(...of your current code, to make the legend centered horizontally, with the top just below the axes:

ax.legend(...对当前代码的 的一项修改,使图例水平居中,顶部位于轴下方:

# Add this line
from matplotlib.transforms import BlendedGenericTransform

# Edit the function call to use the BlendedGenericTransform
ax.legend(loc='upper center',
          ncol=7,
          labelspacing=-0.7,
          columnspacing=0.75,
          fontsize=8,
          handlelength=2.6,
          markerscale=0.75,
          bbox_to_anchor=(0.5, -0.05),
          bbox_transform=BlendedGenericTransform(fig.transFigure, ax.transAxes))

Here, the bbox_to_anchorargument should be customized to fit within the boundaries of our figure.

在这里,bbox_to_anchor应该自定义参数以适合我们图形的边界。

The BlendedGenericTransformallows the transforms of the x-axis and y-axis to be different, which can be very useful in many situations.

BlendedGenericTransform允许的x轴和y轴的变换是不同的,可以是在许多情况下是非常有用的。