【问题标题】:How to position and align a matplotlib figure legend?如何定位和对齐 matplotlib 图形图例?
【发布时间】:2012-12-03 09:06:07
【问题描述】:

我有一个图,其中有两个子图,分别为 2 行和 1 列。我可以添加一个漂亮的人物图例

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

但是,这个图例位于 figure 的中心,而不是我想要的 axes 中心的下方。现在,我可以使用

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

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

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

这可行,除了图例左对齐,以便 loc 指定图例框的左边缘/角而不是中心。我搜索了 alignhorizo​​ntalalignment 等关键字,但没有找到。我也尝试获取“图例位置”,但图例没有 *get_position()* 方法。我读到了 *bbox_to_anchor* 但在应用于图形图例时无法理解。这似乎是为轴传奇制作的。

或者:我应该改用移位轴图例吗?但是,为什么首先会有人物传说呢?并且以某种方式必须可以将图形图例“居中对齐”,因为 loc="lower center" 也可以。

感谢您的帮助,

马丁

【问题讨论】:

    标签: python matplotlib legend


    【解决方案1】:

    在这种情况下,您可以将坐标轴用于图形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()
    

    作为使用轴方法的示例,尝试如下操作:

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

    【讨论】:

    • 谢谢,乔。这是澄清。经过进一步思考,我想我最初的问题的答案应该是:“如果你想使用轴坐标,请使用 axes.legend。”然而 - 出于好奇,我仍然想知道 loc 关键字是否是控制图例框中文本对齐的唯一方法?在许多其他 matplotlib 对象中,您可以提取补丁、线条等(参见例如箱线图文档),并修改它们的属性。这似乎不适用于图例中的(文本对象),至少不是直截了当。我说的对吗?
    【解决方案2】:

    这是一个非常好的问题,接受的答案表示关键(即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.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)
    
    

    作为替代方案,我们还可以将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)
    
    

    【讨论】:

      猜你喜欢
      • 2017-10-05
      • 2013-10-18
      • 1970-01-01
      • 2020-12-19
      • 2017-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-14
      相关资源
      最近更新 更多