如何定位和对齐matplotlib图形图例?

时间:2012-12-15 17:11:38

标签: python matplotlib legend

我有一个带有两个子图的图,分为2行和1列。我可以用

添加漂亮的图形图例
fig.legend((l1, l2), ['2011', '2012'], loc="lower center", 
           ncol=2, fancybox=True, shadow=True, prop={'size':'small'})

但是,此图例位于数字的中心,而不是的中心,正如我想要的那样。现在,我可以用

获得我的轴坐标
axbox = ax[1].get_position()

理论上我应该能够通过使用元组指定 loc 关键字来定位图例:

fig.legend(..., loc=(axbox.x0+0.5*axbox.width, axbox.y0-0.08), ...)

之外,图例左对齐,以便 loc 指定图例框的左边/角,而不是中心。我搜索了诸如 align horizo​​ntalalignment 等关键字,但找不到任何关键字。我也尝试获取“图例位置”,但是图例没有* get_position()*方法。我读到了关于* bbox_to_anchor *但是在应用于图形图例时无法理解它。这似乎是针对轴传说。

或者:我应该使用移位轴图例吗?但那么,为什么首先出现这样的传说呢?并且不知何故,必须能够“居中对齐”图形图例,因为 loc =“lower center”也是如此。

感谢您的帮助,

马丁

2 个答案:

答案 0 :(得分:27)

在这种情况下,您可以将轴用于图legend方法。在任何一种情况下,bbox_to_anchor都是关键。正如您已经注意到bbox_to_anchor指定了一个坐标元组(或一个框)来放置图例。当您使用bbox_to_anchor时,请将location kwarg视为控制水平和垂直对齐。

不同之处在于坐标元组是否被解释为轴或图形坐标。

作为使用图例:

的示例
import numpy as np
import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)

x = np.linspace(0, np.pi, 100)

line1, = ax1.plot(x, np.cos(3*x), color='red')
line2, = ax2.plot(x, np.sin(4*x), color='green')

# The key to the position is bbox_to_anchor: Place it at x=0.5, y=0.5
# in figure coordinates.
# "center" is basically saying center horizontal alignment and 
# center vertical alignment in this case
fig.legend([line1, line2], ['yep', 'nope'], bbox_to_anchor=[0.5, 0.5], 
           loc='center', ncol=2)

plt.show()

enter image description here

作为使用axis方法的示例,请尝试以下方法:

import numpy as np
import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)

x = np.linspace(0, np.pi, 100)

line1, = ax1.plot(x, np.cos(3*x), color='red')
line2, = ax2.plot(x, np.sin(4*x), color='green')

# The key to the position is bbox_to_anchor: Place it at x=0.5, y=0
# in axes coordinates.
# "upper center" is basically saying center horizontal alignment and 
# top vertical alignment in this case
ax1.legend([line1, line2], ['yep', 'nope'], bbox_to_anchor=[0.5, 0], 
           loc='upper center', ncol=2, borderaxespad=0.25)

plt.show()

enter image description here

答案 1 :(得分:0)

这是一个非常好的问题,可接受的答案表示键(即loc表示对齐,bbox_to_anchor表示位置)。我还尝试了一些代码,并想强调 bbox_transform属性的重要性,有时可能需要明确指定该属性以实现所需的效果。下面,我将向您展示我在fig.legend上的发现。 ax.legend应该与loc非常相似,并且bbox_to_anchor的工作方式相同。

使用默认设置时,我们将具有以下内容。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(6,4), sharex=True)

x = np.linspace(0, np.pi, 100)
line1, = ax1.plot(x, np.cos(3*x), color='red')
line2, = ax2.plot(x, np.sin(4*x), color='green')

fig.legend([line1, line2], ['yep', 'nope'], loc='lower center', ncol=2)

enter image description here

这基本上是令人满意的。但是很容易发现图例覆盖了ax2的x轴刻度标签。当图中的figsize和/或dpi发生变化时,这个问题将变得更加严重,请参阅下文。

fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(6,12), sharex=True, facecolor='w', gridspec_kw={'hspace':0.01})

x = np.linspace(0, np.pi, 100)
line1, = ax1.plot(x, np.cos(3*x), color='red')
line2, = ax2.plot(x, np.sin(4*x), color='green')

fig.legend([line1, line2], ['yep', 'nope'], loc='lower center', ncol=2)

enter image description here

因此,您看到ax2与图例之间有很大的差距。那不是我们想要的。像发问者一样,我们想手动控制图例的位置。首先,我将像答案一样使用bbox_to_anchor的2位数样式。

fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(6,12), sharex=True, facecolor='w', gridspec_kw={'hspace':0.01})

x = np.linspace(0, np.pi, 100)
line1, = ax1.plot(x, np.cos(3*x), color='red')
line2, = ax2.plot(x, np.sin(4*x), color='green')

axbox = ax2.get_position()

# to place center point of the legend specified by loc at the position specified by bbox_to_anchor.
fig.legend([line1, line2], ['yep', 'nope'], loc='center', ncol=2,
           bbox_to_anchor=[axbox.x0+0.5*axbox.width, axbox.y0-0.05])

enter image description here

快到了!但这完全是错误的,因为传说的中心不在我们真正含义的中心!解决此问题的关键是我们需要将bbox_transform明确地通知为fig.transFigureBy default None, the Axes' transAxes transform will be used。这是可以理解的,因为在大多数情况下,我们将使用ax.legend()

fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(6,12), sharex=True, facecolor='w', gridspec_kw={'hspace':0.01})

x = np.linspace(0, np.pi, 100)
line1, = ax1.plot(x, np.cos(3*x), color='red')
line2, = ax2.plot(x, np.sin(4*x), color='green')

axbox = ax2.get_position()

# to place center point of the legend specified by loc at the position specified by bbox_to_anchor!
fig.legend([line1, line2], ['yep', 'nope'], loc='center', ncol=2,
           bbox_to_anchor=[axbox.x0+0.5*axbox.width, axbox.y0-0.05], bbox_transform=fig.transFigure)

enter image description here

作为替代方案,我们也可以对bbox_to_anchor使用4位数样式loc。这实际上是为图例指定一个真实的框,loc实际上表示对齐!默认的bbox_to_anchor应该只是[0,0,1,1],这意味着整个图形框!四个数字分别代表x0,y0,width,height。它与specifying a cax for a shared colorbar非常相似!因此,您可以轻松地将y0更改为比axbox.y0低一点,并相应地调整loc

fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(6,12), sharex=True, facecolor='w', gridspec_kw={'hspace':0.01})

x = np.linspace(0, np.pi, 100)
line1, = ax1.plot(x, np.cos(3*x), color='red')
line2, = ax2.plot(x, np.sin(4*x), color='green')

axbox = ax2.get_position()

# to place center point specified by loc at the position specified by bbox_to_anchor!
fig.legend([line1, line2], ['yep', 'nope'], loc='lower center', ncol=2,
           bbox_to_anchor=[0, axbox.y0-0.05,1,1], bbox_transform=fig.transFigure)

enter image description here