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

mas*_*chu 20 python matplotlib legend

我有一个带有两个子图的图,分为2行和1列.我可以添加一个漂亮的图形传奇

fig.legend((l1, l2), ['2011', '2012'], loc="lower center", 
           ncol=2, fancybox=True, shadow=True, prop={'size':'small'})
Run Code Online (Sandbox Code Playgroud)

但是,这个图例位于图形的中心,而不是像我想要的那样位于的中心之下.现在,我可以获得我的轴坐标

axbox = ax[1].get_position()
Run Code Online (Sandbox Code Playgroud)

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

fig.legend(..., loc=(axbox.x0+0.5*axbox.width, axbox.y0-0.08), ...)
Run Code Online (Sandbox Code Playgroud)

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

或者:我应该使用移位轴图例吗?但那么,为什么首先会有传说?并且不知何故,必须能够"居中对齐"图形图例,因为loc ="lower center"也是如此.

谢谢你的帮助,

马丁

Joe*_*ton 28

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

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

作为使用图例的示例:

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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

作为使用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()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Fei*_*Yao 6

这是一个非常好的问题,接受的答案表明了关键(即loc表示对齐并bbox_to_anchor表示位置)。我还尝试了一些代码,并想强调属性的重要性bbox_transform,有时可能需要明确指定这些属性才能达到预期的效果。下面我将向您展示我的发现fig.legendax.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)

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这基本上是令人满意的。但很容易发现图例与 的 x 轴刻度标签重叠ax2figsize当和/或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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

ax2所以你看,和传说中的差距还是很大的。那不是我们想要的。像提问者一样,我们想手动控制图例的位置。首先,我将使用 2 位数样式,bbox_to_anchor就像答案一样。

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])

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

差不多了!但这是完全错误的,因为传说的中心并不是我们真正含义的中心!解决这个问题的关键是我们需要显式地通知bbox_transformas fig.transFigure默认情况下 None,将使用 Axes 的 transAxes 变换。这是可以理解的,因为我们大多数时候都会使用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)

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

作为替代方案,我们还可以使用 4 位数bbox_to_anchor样式loc。这本质上是为图例指定一个真实的框,并且loc真正表示对齐!默认值bbox_to_anchor应该是[0,0,1,1],表示整个图形框!这四个数字x0,y0,width,height分别代表 。它与为共享颜色条指定 cax非常相似!因此,您可以轻松地将其更改y0为稍微低一点axbox.y0loc进行相应调整。

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)

Run Code Online (Sandbox Code Playgroud)

在此输入图像描述