【问题标题】:How to get constant distance between legend and axes even when the figure is resized?即使调整图形大小,如何在图例和轴之间获得恒定距离?
【发布时间】:2019-03-17 11:32:58
【问题描述】:

当使用bbox_to_anchor 将图例放置在坐标轴之外时,如this 答案中所示,调整图形大小时坐标轴和图例之间的空间会发生变化。对于静态导出的图,这很好;您可以简单地调整数字,直到正确为止。但是对于您可能想要调整大小的交互式绘图,这是一个问题。从这个例子可以看出:

import numpy as np
from matplotlib import pyplot as plt

x = np.arange(5)
y = np.random.randn(5)

fig, ax = plt.subplots(tight_layout=True)
ax.plot(x, y, label='data1')
ax.plot(x, y-1, label='data2')
legend = ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05), ncol=2)
plt.show()

结果:

即使调整图形大小,如何确保图例与轴的距离相同?

【问题讨论】:

    标签: python matplotlib legend


    【解决方案1】:

    图例与边界框边缘的距离由borderaxespad 参数设置。 borderaxespad 以字体大小的倍数为单位 - 使其自动独立于轴大小。 所以在这种情况下,

    import matplotlib.pyplot as plt
    import numpy as np
    x = np.arange(5)
    y = np.random.randn(5)
    
    fig, ax = plt.subplots(constrained_layout=True)
    ax.plot(x, y, label='data1')
    ax.plot(x, y-1, label='data2')
    legend = ax.legend(loc="upper center", bbox_to_anchor=(0.5,0), borderaxespad=2)
    
    plt.show()
    


    Place title at the bottom of the figure of an axes? 中提出了关于在坐标轴下方以恒定距离显示标题的类似问题

    【讨论】:

    • 不错!我不知道borderaxespad。这比我的回答简单得多。
    【解决方案2】:

    您可以使用画布的调整大小事件在每次更新时更新bbox_to_anchor 中的值。要计算新值,您可以使用轴变换的逆 (Bbox.inverse_transformed(ax.transAxes)),它将屏幕坐标(以像素为单位)转换为通常在 bbox_to_anchor 中使用的轴坐标。

    这是一个支持将图例放置在轴的所有四个边上的示例:

    import numpy as np
    from matplotlib import pyplot as plt
    from matplotlib.transforms import Bbox
    
    
    class FixedOutsideLegend:
        """A legend placed at a fixed offset (in pixels) from the axes."""
    
        def __init__(self, ax, location, pixel_offset, **kwargs):
            self._pixel_offset = pixel_offset
    
            self.location = location
            if location == 'right':
                self._loc = 'center left'
            elif location == 'left':
                self._loc = 'center right'
            elif location == 'upper':
                self._loc = 'lower center'
            elif location == 'lower':
                self._loc = 'upper center'
            else:
                raise ValueError('Unknown location: {}'.format(location))
    
            self.legend = ax.legend(
                loc=self._loc, bbox_to_anchor=self._get_bbox_to_anchor(), **kwargs)
            ax.figure.canvas.mpl_connect('resize_event', self.on_resize)
    
        def on_resize(self, event):
            self.legend.set_bbox_to_anchor(self._get_bbox_to_anchor())
    
        def _get_bbox_to_anchor(self):
            """
            Find the lengths in axes units that correspond to the specified
            pixel_offset.
            """
            screen_bbox = Bbox.from_bounds(
                0, 0, self._pixel_offset, self._pixel_offset)
            try:
                ax_bbox = screen_bbox.inverse_transformed(ax.transAxes)
            except np.linagl.LinAlgError:
                ax_width = 0
                ax_height = 0
            else:
                ax_width = ax_bbox.width
                ax_height = ax_bbox.height
    
            if self.location == 'right':
                return (1 + ax_width, 0.5)
            elif self.location == 'left':
                return (-ax_width, 0.5)
            elif self.location == 'upper':
                return (0.5, 1 + ax_height)
            elif self.location == 'lower':
                return (0.5, -ax_height)
    
    
    x = np.arange(5)
    y = np.random.randn(5)
    
    fig, ax = plt.subplots(tight_layout=True)
    ax.plot(x, y, label='data1')
    ax.plot(x, y-1, label='data2')
    legend = FixedOutsideLegend(ax, 'lower', 20, ncol=2)
    plt.show()
    

    结果:

    【讨论】:

    • 对于问题中的简单用例来说,这似乎非常复杂。参照。另一个答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多