《超简单:用 Python 让 Excel 飞起来》读书笔记:第7章 案例04 举一反三 添加图例
《超简单:用 Python 让 Excel 飞起来》读书笔记:第7章 案例04 举一反三 添加图例
- 1. 问题背景:为什么图例很重要
- 2. 适用场景:哪些图表必须加 legend
- 3. 最小可用:label + legend
- 4. legend 位置设置:loc 放对地方
- 5. 图例太大/太挤怎么办:fontsize + ncol
- 6. 组合图示例:柱形图 + 折线图加 legend
- 7. 图例遮挡数据的终极解决:放到图外
- 8. 常见问题与踩坑提醒
- 8.1 调用了 legend 但图例不显示
- 8.2 图例显示乱码
- 8.3 图例挡住关键数据
- 8.4 图例太多太乱
- 9. 我的总结提升
1. 问题背景:为什么图例很重要
这一篇继续整理《超简单:用 Python 让 Excel 飞起来》第 7 章中的数据可视化内容,主题是在 Matplotlib 图表中添加图例 legend。如果图表里只有一条线、一组柱子,图例不是必须的;但只要图表里出现两组以上数据,图例就变成了读图的关键。
我在做办公报表、运维趋势图、工单分析图时,最怕看到一种图:线很多、颜色很多,但没有任何说明。读者只能猜:这条线是网络工单还是软件工单?这根柱子代表当月数量还是移动平均?这块面积到底是哪一类?
图例 legend 的作用,就是把图表中的颜色、线型、柱子和真实业务含义对应起来。它不是装饰,而是多数据图表的导航栏。
这张图展示了图例的重要性:没有 legend 时,多数据图表很容易变成“猜谜游戏”。
从这张图中可以看出,同样是一张多数据图,有图例和没有图例的阅读体验完全不同。没有图例时,读者只能看见不同颜色的线,却不知道它们分别代表什么;有了图例之后,颜色和业务对象之间建立了明确关系。
只要图表中有两条以上数据序列,就不要省略图例。否则图表看似完整,实际表达是不完整的。
2. 适用场景:哪些图表必须加 legend
legend 最常见的使用场景,是一张图里同时展示多个对象。比如两条折线、多组柱子、柱线组合图、叠加面积图、多个散点序列等。
常见场景包括:
1. 双折线图:网络工单 vs 软件工单 2. 多折线图:多个产品或多个部门的趋势对比 3. 组合图:柱形图表示数量,折线图表示移动平均 4. 面积图:不同类别叠加展示结构变化 5. 多组柱形图:不同部门、月份、指标之间的交叉对比legend 的处理流程可以简单理解为:先给每组数据起名字,再让 Matplotlib 把这些名字显示出来。
推荐把 legend 当成图表交付前的必查项。图表不是给自己看的,而是给读者看的;只要读者需要猜,它就还不够清楚。
3. 最小可用:label + legend
Matplotlib 中添加图例最基础的方法只有两步:第一,绘图时给每组数据设置label;第二,绘图完成后调用plt.legend()显示图例。
这张图展示了 legend 的最小可用写法:先写label,再调用legend()。
从这张图中可以看出,label是图例内容的来源,legend()是让图例显示出来的动作。如果只写legend(),但前面没有设置label,图例就没有可显示的有效内容。
示例代码如下:
importmatplotlib.pyplotasplt plt.rcParams["font.sans-serif"]=["SimHei"]plt.rcParams["axes.unicode_minus"]=Falsemonths=["1月","2月","3月","4月","5月","6月"]net=[35,30,28,26,24,22]software=[40,45,50,55,52,58]plt.figure(figsize=(10,6))plt.plot(months,net,marker="o",label="网络工单")plt.plot(months,software,marker="o",label="软件工单")plt.title("双折线图:图例 legend 示例")plt.xlabel("月份")plt.ylabel("数量(单)")plt.legend()plt.grid(axis="y",linestyle="dashed",alpha=0.4)plt.tight_layout()plt.show()这里最关键的是这两行:
plt.plot(months,net,marker="o",label="网络工单")plt.plot(months,software,marker="o",label="软件工单")然后通过下面这句显示图例:
plt.legend()label 决定图例写什么,legend 决定图例是否显示。这是 Matplotlib legend 最基础、也是最常用的逻辑。
不要把 label 写成 data1、data2、line1 这种没有业务意义的名字。图例的目的不是证明你写了代码,而是让读者知道每条线代表什么。
4. legend 位置设置:loc 放对地方
legend 能显示出来只是第一步,放在哪里才是真正影响读图体验的地方。图例如果挡住了关键数据点,反而会降低图表质量。
这张图展示了loc参数对图例位置的控制效果,图例可以放在左上、右上、左下、右下等位置。
从这张图中可以看出,图例放对位置,读图效率会明显提升。图例如果压住曲线、数据点或关键峰值,就会让读者分心。
常用写法如下:
plt.legend(loc="upper left")常用位置可以直接记住下面几个:
| loc 参数 | 含义 | 适合场景 |
|---|---|---|
"upper left" | 左上角 | 右侧数据更密集时 |
"upper right" | 右上角 | 左侧数据更密集时 |
"lower left" | 左下角 | 上方数据密集时 |
"lower right" | 右下角 | 左下数据少时 |
"best" | 自动选择较优位置 | 初学者或快速出图时 |
我最常用的是:
plt.legend(loc="best")如果不确定放哪里,可以先用loc="best",让 Matplotlib 自动选择相对不遮挡的位置。后续再根据截图效果微调。
不要机械固定使用 upper left。如果左上角正好是数据变化最关键的位置,图例就会遮挡关键信息。
5. 图例太大/太挤怎么办:fontsize + ncol
当图表中的类别很多时,legend 容易变成一大长条。比如 8 个部门、10 个故障类型、20 个产品线,如果图例不优化,很容易占据大量画布空间。
这张图展示了图例过多时的优化思路:通过fontsize调整字体大小,通过ncol将图例分成多列。
从这张图中可以看出,优化前图例又长又挤,容易压缩图表主体;优化后图例分成多列,整体更规整,阅读也更轻松。
常用写法如下:
plt.legend(loc="upper left",fontsize=10,ncol=2)参数含义如下:
| 参数 | 作用 |
|---|---|
fontsize | 控制图例字体大小 |
ncol | 控制图例显示为几列 |
loc | 控制图例整体位置 |
如果类别更多,也可以尝试:
plt.legend(loc="upper left",fontsize=8,ncol=3)图例类别较多时,优先考虑 ncol 分列,而不是无限缩小字体。字体太小会降低可读性,尤其是截图放到博客或 PPT 之后,读者很难看清。
如果 legend 已经明显影响图表主体,就不要继续硬塞在图内。这种情况更适合把图例移动到图外。
6. 组合图示例:柱形图 + 折线图加 legend
组合图是 legend 最容易体现价值的场景之一。比如柱形图表示当月工单量,折线图表示 3 期移动平均。如果没有图例,读者很难判断柱子和折线分别代表什么。
下面这段代码演示了柱形图和折线图共用一个 legend 的写法:
importmatplotlib.pyplotaspltimportpandasaspd plt.rcParams["font.sans-serif"]=["SimHei"]plt.rcParams["axes.unicode_minus"]=Falsemonths=["1月","2月","3月","4月","5月","6月"]tickets=[120,98,135,110,150,160]ma3=pd.Series(tickets).rolling(3).mean().tolist()plt.figure(figsize=(10,6))plt.bar(months,tickets,label="当月工单量",edgecolor="black",alpha=0.85)plt.plot(months,ma3,marker="o",linewidth=2,label="3期移动平均")plt.title("组合图:柱形图 + 折线图 legend 示例")plt.xlabel("月份")plt.ylabel("数量(单)")plt.legend(loc="upper left")plt.grid(axis="y",linestyle="dashed",alpha=0.4)plt.tight_layout()plt.show()这段代码里,柱形图和折线图都设置了label:
plt.bar(months,tickets,label="当月工单量")plt.plot(months,ma3,label="3期移动平均")只要不同图形对象都设置 label,legend 就可以统一显示。这也是 Matplotlib 比较方便的一点,不管是柱子、线、散点,只要有 label,都能被 legend 管理。
组合图中必须加 legend。因为组合图通常表达的是不同类型指标,如果没有图例,读者无法准确理解图表含义。
7. 图例遮挡数据的终极解决:放到图外
有些图表数据区域非常满,legend 不管放左上、右上、左下还是右下,都会挡住一部分数据。这时不要继续在图内纠结位置,直接把图例放到图外更干净。
这张图展示了把图例移动到图外的效果,核心参数是bbox_to_anchor。
从这张图中可以看出,图例移到图外后,数据区域更加清晰,曲线不会被遮挡,图表主体也更适合截图和汇报。
常用写法如下:
plt.legend(loc="upper left",bbox_to_anchor=(1.02,1.0),borderaxespad=0)plt.tight_layout()这里重点解释两个参数:
| 参数 | 说明 |
|---|---|
loc="upper left" | 表示图例自身的左上角作为定位点 |
bbox_to_anchor=(1.02, 1.0) | 表示把图例锚定到坐标轴右侧稍微偏外的位置 |
如果你发现图例被裁剪,可以配合调整画布大小:
plt.figure(figsize=(12,6))保存图片时也可以这样写:
plt.savefig("legend_outside.png",dpi=200,bbox_inches="tight")正式交付的图表,如果 legend 遮挡数据,我更推荐直接放到图外。这比反复寻找一个“不太挡”的位置更稳定。
注意:legend 放到图外后,一定要检查保存出来的图片是否完整。如果没有使用bbox_inches="tight"或没有调整画布大小,图例可能会被裁掉。
8. 常见问题与踩坑提醒
8.1 调用了 legend 但图例不显示
最常见原因是绘图时没有写label。
plt.plot(months,net)plt.legend()上面这种写法没有给数据命名,legend 就没有有效内容。正确写法是:
plt.plot(months,net,label="网络工单")plt.legend()legend 不是自动猜业务含义,它只显示你通过 label 提供的信息。
8.2 图例显示乱码
如果图例中的中文显示为方块,通常是字体问题。Windows 环境下可以加入:
plt.rcParams["font.sans-serif"]=["SimHei"]plt.rcParams["axes.unicode_minus"]=False也可以尝试:
plt.rcParams["font.sans-serif"]=["Microsoft YaHei"]8.3 图例挡住关键数据
优先使用:
plt.legend(loc="best")如果还是挡住,再考虑:
plt.legend(loc="upper left",bbox_to_anchor=(1.02,1.0))8.4 图例太多太乱
优先减少类别数量,其次再优化显示形式。
plt.legend(fontsize=8,ncol=2)如果类别太多,图例优化只能缓解问题,不能从根上解决问题。图表表达本身也需要控制信息密度。
9. 我的总结提升
这一节的核心,不是简单记住plt.legend(),而是理解 legend 在图表表达中的位置。只要图表中存在多组数据,legend 就承担着“解释颜色、线型、柱子含义”的责任。
我把 legend 的使用总结成四句话:
1. 多数据图必须加 legend。 2. 先写 label,再调用 legend。 3. 图例不能遮挡关键数据。 4. 类别多时,要么分列显示,要么放到图外。图例的本质,是让图表脱离作者本人也能被正确理解。一张图如果只有你自己知道每条线代表什么,那它还没有达到交付标准。
后续写自动化报表时,我建议把 legend 位置、字体大小、图例列数这些参数统一封装进绘图函数。这样每次出图都能保持风格一致,也减少重复调参。
不要把图例当成可有可无的小组件。在多数据图表里,legend 直接决定读者能不能看懂图。
返回顶部