Skip to content

第 7 章 标题、标签与图例

学习目标

  • 掌握 set_title / set_xlabel / set_ylabel 的样式控制
  • 会用 ax.set(...) 一次性设置多个元素
  • 掌握 ax.legend 的位置、列数、字号等参数
  • 会控制图例里出现哪些条目

7.1 标题与轴标签的样式

第 3 章已经用过 set_titleset_xlabelset_ylabel。这一章把它们讲透。三个方法都接受样式参数:fontsize(字号)、fontweight(字重)、color(颜色),set_title 还支持 loc(标题位置):

python
import matplotlib.pyplot as plt
import numpy as np

days = np.arange(1, 8)
high = np.array([28, 31, 33, 30, 29, 32, 34])
low  = np.array([19, 21, 22, 20, 19, 21, 23])
mean = (high + low) / 2

fig, ax = plt.subplots()
ax.plot(days, high, marker="o")
ax.set_title("一周最高气温", fontsize=16, fontweight="bold", loc="left")
ax.set_xlabel("日期", fontsize=12)
ax.set_ylabel("气温(°C)", fontsize=12)
plt.show()

图 7-1 真实输出:loc="left" 让标题靠左对齐(默认居中);轴标签的字号调大一点在投影时更清晰:

图 7-1 标题与轴标签的样式

7.2 图例:legend

图例(legend)把每条数据的「颜色 + 样式」与它的含义对应起来。前提是画线时给了 label,然后调用 ax.legend():

python
ax.plot(days, high, label="最高气温")
ax.plot(days, low,  label="最低气温")
ax.plot(days, mean, label="平均气温")
ax.legend(loc="lower right", ncol=3, fontsize=9)

图 7-2 真实输出,常用参数:

参数作用
loc位置:"best""upper right""lower left""center"
ncol图例排成几列
fontsize图例字号
frameon是否显示边框(True/False)
title给图例加一个小标题

图 7-2 图例:位置、三列、小字号

loc="best" 是默认值:Matplotlib 会选一个与数据重叠最少的位置。数据会动,图例位置也得试。

7.3 控制图例里出现哪些条目

默认情况下,图例收集所有「有 label 的画线对象」。想只让部分条目进图例,用 handleslabels 两个参数手动指定:

python
line_high,  = ax.plot(days, high, marker="o")   # 画线返回元组,解包出 Line2D
line_low,   = ax.plot(days, low, marker="s")
line_mean,  = ax.plot(days, mean, marker="^", linestyle="--")

ax.legend(handles=[line_high, line_mean],
          labels=["最高气温", "平均气温"])

图 7-3 真实输出:三条线都画了,但图例里只有两条——handles 指定「引用哪些对象」,labels 指定「显示什么名字」:

图 7-3 用 handles/labels 控制图例条目

注意 ax.plot 返回的是一个列表(可能有多条线),用 line_high, = ax.plot(...)(带逗号)解包出唯一一条。

7.4 set:一次性设置多个元素

set_titleset_xlabelset_ylabel 都是 Axes 的 set_xxx 家族。它们共用一个捷径:ax.set(参数名=值, ...) 可以一次设置多个:

python
ax.set(xlabel="日期", ylabel="平均气温(°C)", title="7.4 set 一次性设置多个标签")

等价于分别调用三个 set_xxx。图 7-4 真实输出:

图 7-4 用 set 一次性设置多个标签

这个技巧在循环批量设置子图时尤其省事(第 9 章会用到)。

7.5 读懂警告:图例找不到带标签的艺术家

画线时忘了写 label,直接 ax.legend(),会出现一条 UserWarning:

UserWarning: No artists with labels found to put in legend.  Note that artists
whose label start with an underscore are ignored when legend() is called with no
argument.

解读:图例要在所有画图对象里找「带 label 的艺术家(artist)」,一个都没找到,所以图例是空的。修法:给要进图例的线加 label=...;不想进图例的线,要么不给 label,要么用 _ 开头(下划线开头的 label 会被忽略)。

动手实践

  1. 画一周气温图,设置粗体、16 号、靠左的标题,复现图 7-1。
  2. 画三条线(高/低/平均气温),把图例放到左下角、排成 3 列,复现图 7-2。
  3. handles/labels 只把其中两条线放进图例,复现图 7-3。
  4. ax.set(xlabel=..., ylabel=..., title=...) 重写一次 7.2 的图。
  5. 故意不加 label 就调用 ax.legend(),阅读警告信息并修复。

常见错误

错误写法现象原因
没写 labellegend()UserWarning: No artists with labels found图例只收有 label 的对象
legend() 的位置与数据重叠图例挡住曲线loc 或设 frameon=False
忘了 , 解包 plot 返回值line_high 是列表line, = ax.plot(...) 解包
set_title 忘记 fontweight标题不够醒目fontweight="bold"
多个 set_xxx 重复书写代码冗长ax.set(...) 合并

章末练习

基础

  1. 画一张图,设置标题为「成绩趋势」、粗体、16 号、居中。
  2. 画两条线并加图例,把图例放在右上角。
  3. ax.set 一次设置标题与两个轴标签。

提高

  1. 画三条线,用 handles/labels 让图例只包含其中两条,并给图例加 title
  2. 让图例排成 2 列、去掉边框(frameon=False),说明 ncolframeon 的作用。

挑战

  1. 画四组数据的四条线,用 loc="best"ncol=2,再尝试其他 loc,对比哪种布局更优,并说明判断依据。
  2. 思考并实验:同一函数里调用两次 ax.legend() 会发生什么?多次 ax.plot 带相同 label 会怎样?用代码验证,并在图例条目去重的话题上给出结论。

章末自测

每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。

  1. 设置标题的方法?
    • A. ax.title()
    • B. ax.set_title()
    • C. plt.set_title()
    • D. ax.label()
  2. set_title(..., loc="left") 表示?
    • A. 标题靠左
    • B. 标题靠右
    • C. 标题居中
    • D. 隐藏标题
  3. 图例要显示某条线,画线时必须?
    • A. 设置 label
    • B. 设置 color
    • C. 设置 legend=True
    • D. 什么都不用
  4. ax.legend(loc="lower right") 把图例放在?
    • A. 左上
    • B. 右下
    • C. 左下
    • D. 右上
  5. ncol=3 的作用是?
    • A. 图例有三列
    • B. 图例有三行
    • C. 有三条线
    • D. 图例字号为 3
  6. 想只让部分对象进图例,用?
    • A. ax.legend(loc=...)
    • B. ax.legend(handles=[...], labels=[...])
    • C. ax.legend(ncol=1)
    • D. ax.legend(frameon=False)
  7. ax.set(xlabel=..., ylabel=..., title=...) 的作用是?
    • A. 创建三个坐标系
    • B. 一次设置多个标签
    • C. 设置三个图例
    • D. 设置数据范围
  8. line_high, = ax.plot(...) 中的逗号作用?
    • A. 设置线型
    • B. 从返回的列表里解包出唯一一条线
    • C. 换行
    • D. 删除线
  9. 没写 labellegend() 会?
    • A. 报错
    • B. 出现 UserWarning,图例为空
    • C. 图例显示全部线
    • D. 程序退出
  10. _ 开头的 label 会被图例?
    • A. 优先显示
    • B. 忽略
    • C. 显示为下划线
    • D. 报错