这是一个非常好的问题,接受的答案表示关键(即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)
这基本上是令人满意的。但很容易发现,图例与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)
所以你看到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])
快到了!但这是完全错误的,因为传说的中心并不是我们真正意思的中心!解决这个问题的关键是我们需要将bbox_transform明确告知fig.transFigure。 By 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)
作为替代方案,我们还可以将bbox_to_anchor 用于loc 的4 位数样式。这实际上是为图例指定一个真实的框,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)