Matplotlib自动图例放置在图形外部

33

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

这是我根据这个例子制作的非常基本的图表:

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() 中的最后 2 个数字是什么意思?

2个回答

43

编辑:

我强烈建议使用ImportanceOfBeingErnest的答案:如何将图例放在图表外面

编辑结束

这个更容易理解:

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

1
谢谢。坐标不需要每次手动设置吗? - edesz
另外,数据系列标签对我来说太长了。这导致它们在图例中被截断。有没有什么方法可以避免这种情况? - edesz
1
如果您将“左上角”和例如(1,1.25)设置为图例,则图例位于图外。无论如何,图例应该很短。 - Moritz

9
内容翻译: 参数bbox_to_anchor使用的是Axes坐标系。matplotlib使用不同的坐标系来方便在屏幕上放置对象。当处理定位图例时,需要处理的关键坐标系是Axes坐标、Figure坐标和显示坐标(以像素为单位),如下所示:

matplotlib坐标系

如前所述,bbox_to_anchor使用的是Axes坐标系,不需要四元组参数来表示一个矩形。您可以只给它一个包含(xpos,ypos)的二元组,表示Axes坐标系中的位置。在这种情况下,loc参数将定义图例的锚点。因此,要将图例固定在轴的外部右侧,并与顶部对齐,您应该执行以下操作:
lgd = plt.legend(bbox_to_anchor=(1.01, 1), loc='upper left')

然而,这并不会重新定位轴相对于图形的位置,这可能会使图例偏离图形画布。为了自动重新定位图形画布以与轴和图例对齐,我使用了以下算法。

首先,在画布上绘制图例以分配实际像素坐标:

plt.gcf().canvas.draw()

然后定义从像素坐标到图形坐标的转换:
invFigure = plt.gcf().transFigure.inverted()

接下来,获取图例在像素中的范围,并转换为图表坐标系。提取x方向上最远的范围,因为这是我们需要调整的画布方向:

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 调整图形画布,以便坐标轴的一定比例移动以为图例腾出足够的空间适应于画布中:
shift = 1 - (lgd_xmax - ax_xmax)
plt.gcf().tight_layout(rect=(0, 0, shift, 1))

请注意,tight_layout函数中的rect参数以图形坐标为单位,并定义一个矩形,该矩形包含Axes的tight_layout边界,但不包括图例。因此,简单的tight_layout调用等效于设置rect的边界为(0, 0, 1, 1)。

1
这是一个很棒的答案。这是我尝试过的唯一一个程序上有效的方法。解释得非常好,做得好。如果图例放在上方或下方,有一个更普遍的答案将是很好的。 - shapiromatron
我喜欢你提供的坐标图。非常直观。 - KoalaJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接