7.1 Figure、Axes 与面向对象 API
第 6 章已经把清洗后的观测转换成可比较变量。可视化会再做一次转换:数值变成位置、长度、颜色、形状和文字。选择图表之前,先要理解 Matplotlib 把这些视觉对象放在哪里。
把 Matplotlib 图看成对象层级
图形(Figure)是顶层容器,也就是最终显示或保存的完整画布。绘图区(Axes)是 Figure 内的一个绘图面板;尽管英文名称以 s 结尾,一个 Axes 仍然是单数对象。普通二维 Axes 包含 x 轴与 y 轴,它们分别由 Axis 对象管理尺度、刻度和刻度标签。
折线、点、柱、文字、图例、图像,甚至 Axes 本身,都是 Matplotlib 能绘制的 Artist 对象。可以把实用层级理解为:
Figure
└── 一个或多个 Axes
├── xaxis 与 yaxis
├── 数据 Artist:折线、点集、图形块、图像
└── 解释 Artist:标题、标签、图例、注释创建对象后保留显式引用:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 4.5), layout="constrained")
line, = ax.plot(
daily["date"],
daily["revenue"],
marker="o",
)
ax.set(
title="每日收入",
xlabel="日期",
ylabel="收入(元)",
)
fig.suptitle("门店运营")figsize 的单位是英寸。Figure 管理整图标题与布局;Axes 管理数据坐标系和面板标签。ax.plot 创建 Line2D Artist,并把它添加到这个 Axes。line, = ... 中的尾随逗号会拆出 plot 返回的单元素列表。
这种写法通常称为面向对象 API(object-oriented API),当前 Matplotlib 文档也称它为显式 Axes 接口。另一种 plt.plot(...) 会使用隐式“当前 Axes”。它适合一次性探索,但当 notebook 有多个面板或辅助函数时,隐藏状态很容易把内容画错位置。
把 Artist 当作可配置、可测试的结果
绘图方法会返回它创建的 Artist。后续代码需要配置或验证时,应保存这些引用:
actual_line, = ax.plot(x, actual, label="实际", zorder=3)
target_line, = ax.plot(
x,
target,
label="目标",
linestyle="--",
zorder=2,
)
band = ax.fill_between(
x,
target * 0.95,
target * 1.05,
alpha=0.15,
label="目标 ±5%",
zorder=1,
)zorder 控制绘制层级,数值越大越靠上。背景区间通常应位于主数据线下方;透明度有帮助,但不能代替正确图层顺序。
可复用绘图函数应接收 Axes,而不是自行创建 Figure 或调用 plt.gca():
def plot_target(ax, x, actual, target):
band = ax.fill_between(
x, target * 0.95, target * 1.05,
alpha=0.15, label="目标 ±5%", zorder=1,
)
actual_line, = ax.plot(
x, actual, marker="o", label="实际", zorder=3,
)
target_line, = ax.plot(
x, target, linestyle="--", label="目标", zorder=2,
)
return {
"band": band,
"actual": actual_line,
"target": target_line,
}这样,调用者可以决定布局、图例、保存和显示,也能做结构化测试:
artists = plot_target(ax, weeks, actual, target)
assert artists["actual"].axes is ax
assert artists["band"].get_zorder() < artists["actual"].get_zorder()除非精确渲染本身就是需求,否则不要默认逐像素比较输出。字体与栅格化会因后端和操作系统而变化。优先测试绑定数据、标签、范围、尺度、Artist 数量和所属关系;只在外观确实构成契约时增加少量视觉回归测试。
管理 Figure 生命周期
notebook 可能自动显示最后一个 Figure。脚本通常调用 plt.show() 打开交互窗口,或用 fig.savefig(...) 生成文件。循环或服务批量生成图时,保存后要关闭 Figure:
fig.savefig("daily-revenue.svg", bbox_inches="tight")
plt.close(fig)关闭操作会释放 GUI 与渲染资源,不会删除已保存文件。下一节将使用这套对象模型,根据分析问题选择并构建折线图、柱状图、散点图和分布图。