如何让Matplotlib图例跨越多张子图的绘图区域?
解决共享图例宽度匹配子图绘图区域的问题
核心问题原因
你遇到的图例不遵循指定bbox的问题,本质是没有明确指定图例的坐标系统,且未启用图例宽度填充模式。constrained布局下,子图位置是动态调整的,默认的axes坐标系统会让你的bbox计算值被错误转换,导致图例位置偏移、宽度失控。
解决方案步骤
- 切换到figure坐标系统:通过
bbox_transform=fig.transFigure让图例的bbox基于整个画布计算,不受子图坐标干扰。 - 获取子图的最终figure坐标:constrained布局会动态调整子图位置,需在绘制后获取子图的实际位置范围。
- 启用宽度填充模式:设置
mode='expand'强制图例宽度匹配你指定的bbox宽度。
修改后的示例代码
import matplotlib.pyplot as plt # 创建带constrained布局的子图 fig, axes = plt.subplots(2, 2, constrained_layout=True) # 绘制子图内容并收集线条对象 lines = [] for ax in axes.flat: line, = ax.plot([1, 2, 3], label=f'Line {ax._axes_number}') lines.append(line) # 先绘制一次,确保子图位置是constrained布局调整后的最终位置 plt.draw() # 获取所有子图的figure坐标范围 subplots_pos = [ax.get_position() for ax in axes.flat] x_left = min(p.x0 for p in subplots_pos) x_right = max(p.x1 for p in subplots_pos) y_bottom = min(p.y0 for p in subplots_pos) - 0.1 # 向下留出图例空间 # 创建匹配子图宽度的共享图例 fig.legend( lines, [l.get_label() for l in lines], bbox_to_anchor=(x_left, y_bottom, x_right - x_left, 0.08), # (左, 下, 宽, 高) loc='upper left', bbox_transform=fig.transFigure, # 关键:使用figure坐标 mode='expand', # 强制图例宽度填充指定的bbox宽度 borderaxespad=0 # 消除图例内部与边框的间距,让宽度完全匹配 ) plt.show()
关键细节说明
plt.draw():constrained布局会在第一次绘制时调整子图位置,提前调用它能确保你拿到的是子图的最终坐标,避免计算偏差。borderaxespad=0:消除图例内部元素与边框的默认间距,让图例宽度完全贴合你指定的bbox范围。- 若需要将图例放在子图上方,只需调整
y_bottom为max(p.y1 for p in subplots_pos) + 0.05即可。
内容的提问来源于stack exchange,提问作者BernhardWebstudio
相关产品推荐
相关产品推荐

