如何居中Matplotlib误差棒图例的第二行标记?
解决Matplotlib误差棒图例第二行标记居中问题
尝试将Matplotlib图例第二行的标记居中显示,参考过相关方案但不适用于误差棒代码,推测是误差棒的图例handle结构或坐标轴生成方式导致。以下是问题分析及解决方案:
原示例代码
#EXAMPLE OF MY DATA x = [0, 2, 5, 10, 15] y1 = [1, 2, 4, 5, 2] dev1 = [0.2, 0.3, 0.4, 0.6, 0.4] y2 =[1, 2, 3, 4, 5] dev2 = [0.01, 0.2, 0.3, 0.4, 0.5] y3 =[2, 4, 0, 1, 5] dev3 = [0.1, 0.2, 0.2, 0.4, 0.5] y4 =[2, 2, 1, 1, 1] dev4 = [0.1, 0.1, 0.1, 0, 0] y5 =[2, 2, 1, 2, 2] dev5 = [0, 0, 0.1, 0, 0] ##### fig, ax = plt.subplots() ax.errorbar(x, y1, yerr=dev1, marker="^", markersize=4, linestyle=" ", capsize=4, capthick=2, color="darkorange", label='line1') ax.errorbar(x, y2, yerr=dev2, marker="s", markersize=4, linestyle=" ", capsize=4, capthick=2, color="green", label='line2') ax.errorbar(x, y3, yerr=dev3, marker="v", markersize=4, linestyle=" ", capsize=4, capthick=2, color="blue", label='line3') ax.errorbar(x, y4, yerr=dev4, marker="o", markersize=4, linestyle=" ", capsize=4, capthick=2, color="brown", label='line4') ax.errorbar(x, y5, yerr=dev5, marker="o", markersize=4, linestyle=" ", capsize=4, capthick=2, color="yellow", label='line5') handles1, labels1 = ax.get_legend_handles_labels() handles1 = [h[0] for h in handles1] nlines=6 ncols=3 handles1.insert(nlines//ncols, plt.plot([],[],color=(0,0,0,0))[0]) labels1.insert(nlines//ncols, " ") #--->I tried to insert this although it raises me an error (there are 6 handles and 5 labels)<---- ax.legend(handles=handles1, labels=labels1, ncol=ncols, framealpha=1)
问题分析
- 条目数量计算错误:原代码中
nlines设为6,但实际只有5个图例条目,导致插入空条目的索引计算错误,引发handles与labels数量不匹配的报错。 - 空条目插入位置错误:要让第二行2个标记居中,需在第二行开头插入空条目占位,而非第一行末尾。
- 空handle类型不合适:用
plt.plot生成空线条可能引入不必要的元素,更适合用透明Patch。
修正方案
- 动态计算需要插入的空条目数:根据总条目数和列数,计算第二行需要补充的空条目数量,确保有效标记居中。
- 正确插入空handle和label:在第二行起始位置插入透明Patch作为空handle,同时插入对应空label,保证数量一致。
- 保留误差棒handle的正确处理:
ax.errorbar返回的是(Line2D, ErrorbarContainer),取h[0]获取线条对象用于图例是正确的。
修正后完整代码
import matplotlib.pyplot as plt from matplotlib.patches import Patch # 示例数据 x = [0, 2, 5, 10, 15] y1 = [1, 2, 4, 5, 2] dev1 = [0.2, 0.3, 0.4, 0.6, 0.4] y2 =[1, 2, 3, 4, 5] dev2 = [0.01, 0.2, 0.3, 0.4, 0.5] y3 =[2, 4, 0, 1, 5] dev3 = [0.1, 0.2, 0.2, 0.4, 0.5] y4 =[2, 2, 1, 1, 1] dev4 = [0.1, 0.1, 0.1, 0, 0] y5 =[2, 2, 1, 2, 2] dev5 = [0, 0, 0.1, 0, 0] fig, ax = plt.subplots() # 绘制误差棒 ax.errorbar(x, y1, yerr=dev1, marker="^", markersize=4, linestyle=" ", capsize=4, capthick=2, color="darkorange", label='line1') ax.errorbar(x, y2, yerr=dev2, marker="s", markersize=4, linestyle=" ", capsize=4, capthick=2, color="green", label='line2') ax.errorbar(x, y3, yerr=dev3, marker="v", markersize=4, linestyle=" ", capsize=4, capthick=2, color="blue", label='line3') ax.errorbar(x, y4, yerr=dev4, marker="o", markersize=4, linestyle=" ", capsize=4, capthick=2, color="brown", label='line4') ax.errorbar(x, y5, yerr=dev5, marker="o", markersize=4, linestyle=" ", capsize=4, capthick=2, color="yellow", label='line5') handles1, labels1 = ax.get_legend_handles_labels() # 提取误差棒的Line2D对象作为图例handle handles1 = [h[0] for h in handles1] ncols = 3 total_entries = len(labels1) # 计算需要插入的空条目数:使第二行条目居中 empty_entries_needed = (ncols - (total_entries % ncols)) % ncols insert_index = ncols # 第二行起始索引 # 插入空条目占位 for _ in range(empty_entries_needed): handles1.insert(insert_index, Patch(color='none')) labels1.insert(insert_index, '') # 生成居中的图例 ax.legend(handles=handles1, labels=labels1, ncol=ncols, framealpha=1) plt.show()
效果说明
修正后,图例第二行的2个标记会自动居中显示,插入的空条目占据第二行第一个位置,让有效标记处于图例的中间列。
内容的提问来源于stack exchange,提问作者Djova
相关产品推荐
相关产品推荐

