Matplotlib多图例置于轴外被截断,savefig的bbox_extra_artists参数失效
解决Matplotlib多轴外图例截断问题
我完全懂你遇到的困扰——按照官方文档的方法用add_artist()添加了多个坐标轴外的图例,结果哪怕设置了bbox_extra_artists参数,还是有部分图例被截断,这在处理多图例场景时确实容易踩坑。下面给你几个针对性的解决方案,亲测有效:
核心问题:确保所有图例都被纳入布局计算
很多时候截断的原因是你只把部分图例传入了bbox_extra_artists,Matplotlib默认只会计算坐标轴内的元素,轴外的图例必须全部明确告诉它要考虑尺寸。
示例代码(修正版)
import matplotlib.pyplot as plt fig, ax = plt.subplots() # 绘制示例曲线 line1, = ax.plot([1,2,3], label='Line 1') line2, = ax.plot([3,2,1], label='Line 2') line3, = ax.plot([2,1,3], label='Line 3') line4, = ax.plot([1,3,2], label='Line 4') # 创建两个轴外图例 leg1 = ax.legend([line1, line2], ['Line 1', 'Line 2'], loc='upper left', bbox_to_anchor=(1.02, 1)) leg2 = ax.legend([line3, line4], ['Line 3', 'Line 4'], loc='upper left', bbox_to_anchor=(1.02, 0.7)) # 关键:把被覆盖的第一个图例重新添加回坐标轴 ax.add_artist(leg1) # 重要:将所有图例都传入bbox_extra_artists # 保存图像时确保包含所有图例 plt.savefig('multi_legend.png', bbox_extra_artists=(leg1, leg2), bbox_inches='tight') # 如果要在plt.show()时也正常显示,用tight_layout预留空间并传入所有图例 plt.tight_layout(rect=[0, 0, 0.8, 1], extra_artists=(leg1, leg2)) plt.show()
关键细节拆解
ax.add_artist(leg1)不能忘:当你创建第二个图例时,Matplotlib会自动移除第一个图例,必须手动把它加回坐标轴,否则第一个图例根本不会显示。bbox_extra_artists要包含所有图例:不管是1个还是N个轴外图例,都要把它们全部放进这个参数的元组里,这样Matplotlib才会计算所有图例的尺寸,调整图像边界。bbox_inches='tight'是保存时的必备项:这个参数会让savefig()根据bbox_extra_artists里的元素自动扩展图像边界,否则哪怕设置了bbox_extra_artists也会截断。tight_layout的rect参数:用rect=[0,0,0.8,1]可以给右侧预留20%的空间放图例,你可以根据图例数量和大小调整这个数值(比如改成0.7预留30%)。
备选方案:用fig.legend()统一管理多图例
如果你的图例数量较多,位置复杂,也可以直接用fig.legend()创建图例,这样不需要手动调用add_artist,布局管理更省心:
import matplotlib.pyplot as plt fig, ax = plt.subplots() line1, = ax.plot([1,2,3], label='Line 1') line2, = ax.plot([3,2,1], label='Line 2') line3, = ax.plot([2,1,3], label='Line 3') line4, = ax.plot([1,3,2], label='Line 4') # 直接在画布层面创建多个图例 leg1 = fig.legend([line1, line2], ['Line 1', 'Line 2'], loc='upper left', bbox_to_anchor=(1.02, 1)) leg2 = fig.legend([line3, line4], ['Line 3', 'Line 4'], loc='upper left', bbox_to_anchor=(1.02, 0.7)) # 同样需要把所有图例传入bbox_extra_artists保存 plt.savefig('fig_legend.png', bbox_extra_artists=(leg1, leg2), bbox_inches='tight') plt.tight_layout(rect=[0,0,0.8,1]) plt.show()
最后一个小技巧
如果调整完还是有轻微截断,可以微调bbox_to_anchor的数值,比如把1.02改成1.05,给图例和坐标轴之间多留一点空隙,避免边缘被裁掉。
内容的提问来源于stack exchange,提问作者Circular
相关产品推荐
相关产品推荐

