Matplotlib 自动图例外图

Matplotlib automatic legend outside plot

我正在尝试在 Python 的 matplotlib 图中使用关键字 bbox_to_anchor()

这是我制作的一个非常基本的情节based on this example。 :

import matplotlib.pyplot as plt
x = [1,2,3]
plt.subplot(211)
plt.plot(x, label="test1")
plt.plot([3,2,1], label="test2")
plt.legend(bbox_to_anchor=(0, -0.15, 1, 0), loc=2, ncol=2, mode="expand", borderaxespad=0)
plt.show()

我正在尝试使用 bbox_to_anchor() 自动将图例放置在绘图之外。在此示例中,bbox_to_anchor() 列出了 4 个参数。

在这个特定示例(上图)中,图例位于图下方,因此每次更改图(字体大小、轴标题已删除等)时都需要手动输入数字 -0.15。 是否可以针对以下场景自动计算这4个数字?:

  1. 情节下方的图例
  2. 情节上方的图例
  3. 情节右侧的图例

如果不是,是否可以很好地猜测这些数字,在 Python?

此外,在上面的示例代码中,我将 bbox_to_anchor() 中的最后 2 个数字设置为 1 和 0,因为我不明白它们是什么或它们是如何工作的。 bbox_to_anchor() 中的最后两个数字是什么意思?

编辑:

我强烈建议使用来自 ImportanceOfBeingErnest 的答案: How to put the legend out of the plot

这个比较容易理解:

import matplotlib.pyplot as plt
x = [1,2,3]
plt.subplot(211)
plt.plot(x, label="test1")
plt.plot([3,2,1], label="test2")
plt.legend(bbox_to_anchor=(0, 1), loc='upper left', ncol=1)
plt.show()

现在玩转坐标 (x,y)。对于 loc,您可以使用:

valid locations are:
right
center left
upper right
lower right
best
center
lower left
center right
upper left
upper center
lower center

bbox_to_anchor 的参数在轴坐标中。 matplotlib 使用不同的坐标系来简化屏幕上对象的放置。在处理定位图例时,要处理的关键坐标系是 Axes 坐标、Figure 坐标和 Display 坐标(以像素为单位),如下所示:

matplotlib coordinate systems

如前所述,bbox_to_anchor 在 Axes 坐标中并且不需要矩形的所有 4 个元组参数。您可以简单地给它一个包含 (xpos, ypos) 轴坐标的双参数元组。本例中的 loc 参数将定义图例的锚点。因此,要将图例固定到轴的右外侧并与顶部边缘对齐,您可以发出以下命令:

lgd = plt.legend(bbox_to_anchor=(1.01, 1), loc='upper left')

然而,这不会相对于图形重新定位轴,这可能会使图例脱离图形 canvas。为了自动重新定位图形 canvas 以与坐标轴和图例对齐,我使用了以下算法。

首先,在canvas上绘制图例,为其分配真实的像素坐标:

plt.gcf().canvas.draw()

然后定义从像素坐标到图形坐标的转换:

invFigure = plt.gcf().transFigure.inverted()

接下来,获取以像素为单位的图例范围并转换为图形坐标。在x方向拉出最远的范围,因为那是我们需要调整的canvas方向:

lgd_pos = lgd.get_window_extent()
lgd_coord = invFigure.transform(lgd_pos)
lgd_xmax = lgd_coord[1, 0]

对轴做同样的事情:

ax_pos = plt.gca().get_window_extent()
ax_coord = invFigure.transform(ax_pos)
ax_xmax = ax_coord[1, 0]

最后,使用 tight_layout 调整图 canvas 必须移动的轴的比例,以便为图例留出空间以适应 canvas:

shift = 1 - (lgd_xmax - ax_xmax)
plt.gcf().tight_layout(rect=(0, 0, shift, 1))

请注意,tight_layout 的 rect 参数在图形坐标中,并定义包含轴的 tight_layout 边界的矩形的左下角和右上角,其中不包括图例.所以一个简单的 tight_layout 调用相当于设置 (0, 0, 1, 1) 的矩形边界。