You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib自定义图例:调整图例框大小与图例项间距求助

解决Matplotlib自定义圆形图例的两个问题

问题1:按圆边框设置相等间距

默认图例的labelspacing按条目中心计算,不同大小的圆形会导致视觉间距不均。我们可以通过自定义图例处理器,手动调整每个圆形的位置,确保相邻圆形的边框间距一致。

问题2:自定义图例框大小,让圆形完全在边框内

通过调整图例内边距或手动扩展边界框,避免大圆形超出灰色边框。

完整代码

import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.legend_handler import HandlerBase

class CircleHandler(HandlerBase):
    def __init__(self, spacing=8, **kwargs):
        self.spacing = spacing  # 圆形边框之间的目标间距(单位:点)
        super().__init__(**kwargs)
    
    def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans):
        # 获取原始marker的尺寸和样式
        markersize = orig_handle.get_markersize()
        radius = markersize / 2
        facecolor = orig_handle.get_color()
        edgecolor = orig_handle.get_markeredgecolor()
        
        # 创建自定义圆形(替代默认的Line2D marker)
        circle = plt.Circle(
            (xdescent + width/2, ydescent + height/2),
            radius,
            facecolor=facecolor,
            edgecolor=edgecolor,
            transform=trans
        )
        # 保存当前圆形的半径,用于后续间距调整
        self.radius = radius
        return [circle]

# 创建自定义线条(仅用于传递marker样式)
line1 = Line2D([0], [0], color="white", marker='o', markeredgecolor='k', markersize=40)
line2 = Line2D([0], [0], color="white", marker='o', markeredgecolor='k', markersize=32)
line3 = Line2D([0], [0], color="white", marker='o', markeredgecolor='k', markersize=24)

handles = [line1, line2, line3]
labels = ['Thing 1', 'Thing 2', 'Thing 3']

# 创建图例,使用自定义处理器
legend = plt.legend(
    handles=handles,
    labels=labels,
    numpoints=1,
    handler_map={Line2D: CircleHandler(spacing=8)},  # 指定自定义处理器
    handletextpad=1.5,  # 图标与文本的水平间距
    borderpad=2  # 图例框内边距(单位:字体大小倍数,确保圆形不超出边框)
)

# 调整每个圆形的垂直位置,实现边框等间距
legend_items = legend.get_children()[0].get_children()
prev_radius = None
for idx, item in enumerate(legend_items):
    if isinstance(item, list) and len(item) > 0:
        circle = item[0]
        current_radius = circle.get_radius()
        if idx > 0 and prev_radius is not None:
            # 计算需要调整的垂直偏移量:上圆半径 + 当前圆半径 + 目标间距
            total_offset = prev_radius + current_radius + 8
            # 获取当前条目的位置,调整y坐标
            item_bbox = item.get_window_extent()
            new_y = item_bbox.y0 - total_offset
            # 应用位置变换
            item.set_transform(plt.gca().transData + plt.transforms.Affine2D().translate(0, new_y))
        prev_radius = current_radius

plt.tight_layout()
plt.show()

代码说明

  1. 自定义CircleHandler:

    • 替代默认的Line2D处理器,直接创建圆形对象,方便获取和控制半径。
    • 保存每个圆形的半径,用于后续间距计算。
  2. 调整圆形位置:

    • 遍历图例的每个条目,计算相邻圆形的半径和加上目标间距,调整下一个圆形的y坐标,确保边框间距一致。
  3. 调整图例框大小:

    • 通过borderpad参数增加图例框的内边距,确保大圆形不会超出灰色边框;如果需要更精确控制,可以手动扩展图例的边界框。

内容的提问来源于stack exchange,提问作者Alex Mekx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:36:29