第 1 章 认识 Matplotlib
学习目标
- 知道 Matplotlib 是什么、解决什么问题
- 完成 Matplotlib 的安装并验证版本
- 会用
import matplotlib.pyplot as plt绘制并保存第一张图 - 解决中文与负号显示问题
- 认识一张图的骨架:Figure、Axes、标题、标签、刻度
- 读懂第一条报错
1.1 Matplotlib 是什么
Matplotlib 是 Python 生态中最基础、使用最广的 2D 绘图库,核心能力是把数据变成图形:折线图、散点图、柱状图、直方图、饼图等。它解决一个具体问题:数据是数字,人眼不擅长读数字,擅长看图。一张图能在一瞬间传递表格里几千个数字才能表达的信息。
它有两个常用的入口:
matplotlib.pyplot:一个「状态机」风格的模块,约定简写为plt。你用plt.plot、plt.title一步步往「当前这张图」上添加内容,适合快速画图。- 面向对象接口:直接操作
Figure(画布)和Axes(坐标系)对象,适合复杂布局与精细控制。
本书两种写法都会用:前几章先用 pyplot,第 2 章正式讲清对象体系,之后以面向对象写法为主。所有示例基于 Matplotlib 3.x(写作时最新为 3.11.1),代码在交互环境(REPL)或脚本文件中运行,约定运行方式用 uv run python(见 1.2)。
1.2 安装 Matplotlib
1.2.1 用 uv 安装(推荐)
本书配套仓库使用 uv 管理 Python 环境。在项目根目录:
$ uv sync完成后验证:
$ uv run python -c "import matplotlib; print(matplotlib.__version__)"
3.11.11.2.2 用 pip 安装
如果你已有自己的 Python 环境,直接:
$ pip install matplotlib
$ python3 -c "import matplotlib; print(matplotlib.__version__)"输出 3.x.x 即安装成功。后续所有示例,把 uv run python 换成你自己的 python3 即可。
1.3 导入 pyplot 与第一张图
导入是用 import 语句把库加载进当前程序。Matplotlib 社区约定统一简写为 plt:
import matplotlib.pyplot as plt绘图从数据开始。假设你记录了某地一周每天的最高气温(单位 °C):
import matplotlib.pyplot as plt
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
temps = [28, 31, 33, 30, 29, 32, 34]
plt.plot(days, temps)
plt.title("Daily Max Temperature")
plt.xlabel("Weekday")
plt.ylabel("Temperature (C)")
plt.show()plt.plot(x, y) 把 x 与 y 一一对应连成一条折线;plt.title 设置标题;plt.xlabel / plt.ylabel 设置两个坐标轴的标签。plt.show() 在交互环境弹出图形窗口。
图 1-1 就是上面代码的真实输出(本书把 plt.show() 换成 plt.savefig() 后保存,用于嵌进正文):

观察这张图:横轴是星期,纵轴是气温,一条折线把 7 个点连起来。周四是低谷、周日是高峰——图比 [28, 31, 33, 30, 29, 32, 34] 这串数字直观得多。这就是 Matplotlib 的价值。
注意 plt.plot 的第一个参数如果省略,默认用 0, 1, 2, ... 作横坐标,只画 y:
import matplotlib.pyplot as plt
temps = [28, 31, 33, 30, 29, 32, 34]
plt.plot(temps)
plt.show()1.4 中文与负号:必须解决的第一步
上面的图用的是英文标签,因为 Matplotlib 的默认字体 DejaVu Sans 不含中文字形。直接用中文标签,会得到一个个「方框」(tofu):
import matplotlib.pyplot as plt
days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
temps = [28, 31, 33, 30, 29, 32, 34]
plt.plot(days, temps)
plt.title("一周最高气温")
plt.xlabel("星期")
plt.ylabel("气温(°C)")
plt.show()真实输出(注意标题与坐标轴标签处的方框):

解决办法是告诉 Matplotlib 使用一个含中文字形的字体。用 rcParams(全局配置,第 11 章展开)把中文字体加进「无衬线字体候选列表」:
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False
days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
temps = [28, 31, 33, 30, 29, 32, 34]
plt.plot(days, temps)
plt.title("一周最高气温")
plt.xlabel("星期")
plt.ylabel("气温(°C)")
plt.show()axes.unicode_minus = False 是配套设置:默认情况下负号会用一个特殊 Unicode 字符渲染,在多数中文字体里同样会变成方框;设为 False 后改用普通减号。图 1-3 是配置后的真实输出:

从本章起,所有示例都默认先做这两行配置(本书仓库自带 Noto Sans CJK SC 字体,_common 脚本已统一设置)。在你自己的电脑上,把字体名换成系统里实际存在的中文字体即可,例如 macOS 的 "PingFang SC"、Windows 的 "Microsoft YaHei"。
1.5 一张图的骨架:Figure 与 Axes
不管多复杂的图,骨架都是同一个:一张 Figure,里面有至少一个 Axes。
Figure(画布)是整张图的外壳,包含背景、标题栏、所有坐标系与图例;Axes(坐标系)是真正画数据、带坐标轴和刻度的那块区域。plt.plot 这类 pyplot 函数会「自动」在当前的 Figure 里创建/复用当前 Axes,所以前面的代码没提这两个概念也能画出来——但理解它们之后,你才能控制复杂的布局。
图 1-4 标注了这张图的各个部分:

各部分的名字与作用:
| 部分 | 作用 |
|---|---|
| Figure(画布) | 整张图的外壳,可以包含多个 Axes(第 9 章) |
| Axes(坐标系) | 画数据的区域,含坐标轴、刻度、网格 |
| 标题(title) | 说明这张图讲什么 |
| x / y 轴标签 | 说明横轴、纵轴各代表什么量、什么单位 |
| 刻度(tick) | 坐标轴上的数值记号与标注 |
| 数据线 | 用 plot 画的折线/散点等 |
1.6 保存图片:savefig 初见
交互环境用 plt.show() 弹窗;要让图片脱离程序存在(写报告、发网页),用 plt.savefig(路径) 把当前图保存成文件:
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False
days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
temps = [28, 31, 33, 30, 29, 32, 34]
plt.plot(days, temps, marker="o")
plt.title("一周最高气温")
plt.xlabel("星期")
plt.ylabel("气温(°C)")
plt.grid(True, alpha=0.3)
plt.savefig("week_temperature.png")
print("已保存")真实输出:
已保存并在当前目录生成 week_temperature.png,图 1-5 就是保存出的文件:

savefig 支持 PNG、PDF、SVG、EPS 等格式,也支持控制分辨率与空白边距——这是第 10 章的完整主题,这里先会用即可。
1.7 读懂第一条报错
plt.plot 最经典的报错是x 与 y 长度不一致。假设 x 有 7 个元素、y 只有 5 个:
>>> import matplotlib.pyplot as plt
>>> plt.plot([1, 2, 3, 4, 5, 6, 7], [10, 12, 11, 14, 13])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
...
File "matplotlib/axes/_axes.py", line 1792, in plot
lines = [*self._get_lines(self, *args, data=data, **kwargs)]
...
ValueError: x and y must have same first dimension, but have shapes (7,) and (5,)解读:
- 错误类型是
ValueError(值错误)。 - 关键信息在最后一行:
x and y must have same first dimension, but have shapes (7,) and (5,)(x 与 y 的第一维必须相同,但形状分别是 (7,) 和 (5,))。折线图是逐点连线,x[i]与y[i]必须一一对应,长度必须一致。
读 Matplotlib 报错三步:
- 看最后一行:错误类型 + 一句话说明。
- 看中间的行:出错的是哪条语句、哪个文件(通常是
matplotlib/...内部调用链)。 - 核对你传给函数的两个序列长度:用
print(len(x), len(y))确认。
动手实践
- 在项目根目录运行
uv run python进入交互环境,验证matplotlib.__version__。 - 用
plt.plot画出你自己的一周睡眠时长(7 个数字),设置英文标题与轴标签,plt.show()查看。 - 把第 2 步的标签换成中文,先不配置字体运行一次,观察方框;再按 1.4 配置字体后运行,对比前后。
- 用
plt.savefig("sleep.png")保存第 3 步的图,确认文件生成并可以打开。 - 故意让
plt.plot([1, 2, 3], [1, 2])运行,用「读报错三步」说出:错误类型是什么、两个序列的长度各是多少。
常见错误
| 错误写法 | 现象 | 原因 |
|---|---|---|
| 中文标签直接画 | 标题/标签变成方框 | 默认字体 DejaVu Sans 不含中文字形;需配置 font.sans-serif |
| 负号显示成方框 | 坐标轴负号异常 | 需设置 axes.unicode_minus = False |
plt.plot([1,2,3], [1,2]) | ValueError: x and y must have same first dimension | 两个序列长度必须一致 |
import matplotlib 后直接 plot(...) | NameError: name 'plot' is not defined | 绘图函数在 pyplot 子模块,需 import matplotlib.pyplot as plt |
忘写 plt.show()(交互环境) | 没有窗口弹出 | 交互环境需显式调用 plt.show() 显示图形 |
在无图形界面的服务器上 plt.show() | ImportError / 无反应 | 服务器没有显示后端;改用 plt.savefig() 保存文件 |
章末练习
基础
- 写一段代码:画一条 5 个点的折线
[3, 1, 4, 2, 5],设置标题与两个轴标签,并保存为line.png。 - 在交互环境打印
matplotlib.__version__,确认安装。 - 用中文标题画一张图,并完成 1.4 的两行字体配置。
提高
- 解释
Figure与Axes的区别,并用一句话说明plt.plot是怎么「自动」找到画布和坐标系的。 - 画两张对比图:一张用
plt.plot(temps)(只传一个参数),一张用plt.plot(days, temps),观察横坐标的区别,并解释plot单参数时的默认行为。
挑战
- 不运行代码,预测
plt.plot([1, 2, 3], [1, 2, 3, 4])会发生什么,再运行验证,并用「读报错三步」解释错误信息。 - 把
plt.show()换成plt.savefig()保存同一张图,再用os.path.getsize("文件名.png")查看文件大小;思考为什么同一张图保存两次大小可能不同。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
- Matplotlib 绘图最常用的导入写法是?
- A.
import matplotlib - B.
import matplotlib.pyplot as plt - C.
from matplotlib import * - D.
import pyplot
- A.
- 下面哪个函数用于「弹出窗口显示图形」?
- A.
plt.save() - B.
plt.show() - C.
plt.plot() - D.
plt.print()
- A.
- 整张图的外壳(可包含多个绘图区域)叫什么?
- A.
Axes - B.
Figure - C.
Canvas - D.
Plot
- A.
- 真正绘制数据、带坐标轴与刻度的区域叫什么?
- A.
Figure - B.
Axes - C.
Grid - D.
Legend
- A.
- 中文字体问题的解决方法是?
- A. 把文字全部改成拼音
- B. 配置
rcParams["font.sans-serif"]为含中文字形的字体 - C. 升级 Matplotlib
- D. 改用
plotly
axes.unicode_minus = False的作用是?- A. 关闭所有文字
- B. 让负号正常显示
- C. 只显示正数
- D. 加快绘图
plt.plot([1, 2, 3], [1, 2])会?- A. 自动补齐为相同长度
- B. 报
ValueError - C. 只画前两个点
- D. 返回
None
- 把图保存为 PNG 文件,应使用?
- A.
plt.show() - B.
plt.savefig("a.png") - C.
plt.export("a.png") - D.
plt.write("a.png")
- A.
plt.plot([3, 1, 4, 1, 5])只传一个参数时,横坐标默认是?- A. 从 1 开始的整数
- B. 从 0 开始的整数
- C. 随机数
- D. 空数组
- 关于 Matplotlib 的两种接口,正确的说法是?
- A.
pyplot是面向对象接口 - B.
pyplot是状态机风格,面向对象接口操作 Figure/Axes - C. 两者不能混用
- D. 面向对象接口不能保存图片
- A.
