第 12 章 综合实践:数据可视化报告
学习目标
- 能把全书知识组合成完整程序(设计 → 实现 → 验证)
- 会阅读 AI 生成的 Matplotlib 代码,按固定顺序审查
- 会用「数据形态 → 图表类型」做设计决策
- 树立「理解并验证后再使用」的态度
12.1 综合实践的思路:拆解问题
面对真实可视化任务,先拆解再编码,任何任务都按三步走:
- 数据是什么形态? 时间序列、类别、分布、构成、关系?这一步决定图表类型(对照第 6 章 6.5 的选图表)。
- 要表达什么信息? 趋势、比较、分布、占比,还是讲一个故事?这一步决定布局与标注。
- 如何验证? 图形画出来「一眼可读」吗?数值标签对吗?中文显示正常吗?保存的分辨率够吗?
本章用两个完整项目演示,再用一套「AI 代码审查流程」收尾——它也是结业项目的评审标准。
12.2 项目一:一周天气可视化周报
问题:拿到一周的天气数据(高低温、降雨、湿度),做一页可视化周报。
第一步,看形态。 高低温是两条时间序列(折线 + 区间)、降雨量是逐日数值(柱状)、湿度逐日(柱状)、高低温的分布(箱线图)。四种形态,四种图。
第二步,选布局。 一页四图用 subplots(2, 2),总标题用 suptitle。
第三步,编码并验证。
import matplotlib.pyplot as plt
import numpy as np
days = np.array(["周一", "周二", "周三", "周四", "周五", "周六", "周日"])
high = np.array([28, 31, 33, 30, 29, 32, 34])
low = np.array([19, 21, 22, 20, 19, 21, 23])
rain = np.array([0, 2.5, 8, 1, 0, 0, 12])
humid = np.array([65, 70, 78, 72, 60, 58, 82])
fig, axes = plt.subplots(2, 2, figsize=(9.5, 7))
axes[0, 0].plot(days, high, marker="o", color="#d33f49", label="最高气温")
axes[0, 0].plot(days, low, marker="s", color="#11557c", label="最低气温")
axes[0, 0].fill_between(range(7), low, high, color="#9ca3af", alpha=0.25)
axes[0, 0].set_title("气温走势")
axes[0, 0].set_ylabel("气温(°C)")
axes[0, 0].legend()
axes[0, 1].bar(days, rain, color="#11557c")
axes[0, 1].set_title("每日降雨量")
axes[0, 1].set_ylabel("降雨量(mm)")
axes[1, 0].boxplot([high, low], tick_labels=["最高", "最低"], patch_artist=True,
boxprops=dict(facecolor="#11557c", alpha=0.5),
medianprops=dict(color="#d33f49"))
axes[1, 0].set_title("高低温分布")
axes[1, 0].set_ylabel("气温(°C)")
axes[1, 1].bar(days, humid, color="#40c0a6", alpha=0.8)
axes[1, 1].set_title("每日湿度")
axes[1, 1].set_ylabel("湿度(%)")
fig.suptitle("一周天气可视化周报", fontsize=15, fontweight="bold")
fig.tight_layout()
plt.show()图 12-1 是真实输出:左上「趋势 + 区间」、右上「降雨量」、左下「分布」、右下「湿度」,一页看完一周天气:

注意图 12-1 里出现的知识点:折线与区间填充(第 3、6 章)、柱状图(第 5 章)、箱线图(第 6 章)、子图与 tight_layout(第 9 章)、suptitle(第 9 章)。一次实践,串起五章。
12.3 项目二:年度销售仪表盘
问题:做一张「年度销售仪表盘」,同时展示逐月趋势、品类占比、品类对比。
第一步,看形态。 逐月销量是时间序列(主图),品类占比是构成(饼图),品类销售额是类别比较(柱状)。
第二步,选布局。 想突出「趋势」,让折线图横跨整行(用 GridSpec);下方放饼图与柱状图。
第三步,编码并验证。
import matplotlib.pyplot as plt
import numpy as np
months = np.arange(1, 13)
sales = np.array([32, 45, 40, 55, 60, 58, 66, 72, 68, 80, 76, 90])
categories = np.array(["电子", "服装", "食品", "家居"])
cat_sales = np.array([420, 310, 260, 210])
fig = plt.figure(figsize=(9.5, 6.2))
gs = fig.add_gridspec(2, 2, height_ratios=[1.4, 1], width_ratios=[1.6, 1])
ax_main = fig.add_subplot(gs[0, :]) # 横跨整行的主图
ax_main.plot(months, sales, marker="o", color="#11557c", linewidth=2)
ax_main.fill_between(months, sales, 0, color="#11557c", alpha=0.15)
ax_main.annotate("年度峰值", xy=(12, 90), xytext=(9, 80),
arrowprops=dict(arrowstyle="->", color="#d33f49"))
ax_main.set_title("2025 年逐月销售额")
ax_main.set_xlabel("月份")
ax_main.set_ylabel("销售额(万元)")
ax_main.set_xticks(months)
ax_pie = fig.add_subplot(gs[1, 0]) # 左下饼图
ax_pie.pie(cat_sales, labels=categories, autopct="%1.0f%%",
colors=["#11557c", "#ee8c18", "#40c0a6", "#d33f49"], startangle=90)
ax_pie.set_title("品类销售占比")
ax_bar = fig.add_subplot(gs[1, 1]) # 右下柱状图
ax_bar.bar(categories, cat_sales, color=["#11557c", "#ee8c18", "#40c0a6", "#d33f49"])
ax_bar.set_title("品类销售额")
ax_bar.set_ylabel("销售额(万元)")
fig.suptitle("2025 年度销售仪表盘", fontsize=15, fontweight="bold")
fig.tight_layout()
plt.show()图 12-2 真实输出:GridSpec 让主图横跨整行,下方两块并排;annotate 标出年度峰值:

仪表盘的核心是「信息分层」:最重要的趋势占最大面积,支撑信息放次要位置。这张图用到的知识点:GridSpec(第 9 章)、饼图(第 6 章)、柱状图(第 5 章)、注释(第 8 章)、fill_between(第 6 章)。
12.4 阅读 AI 生成的 Matplotlib 代码
你让 AI 画图,它给你一段代码。不要直接信任,按固定顺序审查:
- 能跑吗? 先运行。报错先读最后一行,确认是不是
ValueError/AttributeError等常见问题。 - 中文正常吗? 有没有配置
font.sans-serif与axes.unicode_minus?很多 AI 初稿会漏这一步,画出一片方框。 - 有标题、轴标签、单位吗? 没有标签的图无法独立阅读。
- 图例对得上吗?
label是否都写了、图例是否有遗漏或多余。 - 配色和字号合适吗? 配色是否冲突、投影/打印是否够大。
- 布局对吗? 子图是否重叠,要不要
tight_layout。 - 信息诚实吗? 坐标轴范围有没有被故意截断制造误导、数值标签是否真实。
12.5 改进一段 AI 生成的代码
下面是一段「AI 初稿」的真实样例(为演示,故意保留了常见问题):中文未配置、无轴标签、无网格、五条线配色杂乱:
import matplotlib.pyplot as plt
import numpy as np
months = np.arange(1, 13)
sales = np.array([32, 45, 40, 55, 60, 58, 66, 72, 68, 80, 76, 90])
fig, ax = plt.subplots()
for i, col in enumerate(["red", "green", "blue", "magenta", "orange"]):
ax.plot(months, sales + i * 8, color=col)
ax.set_title("2025年各产品销量")
ax.set_xlabel("月份")
ax.set_ylabel("销量")
ax.legend(["产品1", "产品2", "产品3", "产品4", "产品5"])
plt.show()图 12-3 是这段代码的真实输出:标题里的中文变成方框,五条线颜色刺眼、没有网格,读者很难分清哪条是哪条:

按 12.4 的审查流程逐条改进:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["font.sans-serif"] = ["Noto Sans CJK SC", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False
months = np.arange(1, 13)
sales = np.array([32, 45, 40, 55, 60, 58, 66, 72, 68, 80, 76, 90])
fig, ax = plt.subplots()
colors = ["#11557c", "#ee8c18", "#40c0a6", "#d33f49", "#7b5ea7"]
for i in range(5):
ax.plot(months, sales + i * 8, marker="o", markersize=3,
color=colors[i], label=f"产品 {i+1}")
ax.set_title("2025 年各产品销量")
ax.set_xlabel("月份")
ax.set_ylabel("销量(万元)")
ax.set_xticks(months)
ax.legend(ncol=3, fontsize=9)
ax.grid(True, alpha=0.3)
plt.show()图 12-4 是改进后的真实输出:中文正常、统一配色、加网格与图例、标注单位:

改进点逐条对应:① 补中文字体配置;② 用品牌色替换「红绿蓝」;③ 加单位「万元」;④ 图例排 3 列、加网格;⑤ 标记点便于读数。
12.6 综合项目评审清单
做结业项目时,对照下面的清单自评(也是 final.md 的评审标准):
| 标准 | 说明 |
|---|---|
| 可运行 | 按 README 或注释说明可一键运行,无语法错误 |
| 中文正常 | 中文字体配置正确,图内无方框 |
| 有标签 | 每张图都有标题、轴标签(带单位)、必要的图例 |
| 图对信息 | 图表类型与数据形态匹配,没有「用错图」 |
| 结构清晰 | 用函数组织代码,没有大段重复 |
| 布局得当 | 多图用子图/GridSpec 组织,无重叠 |
| 保存合理 | 输出 PNG(dpi≥150)或 PDF,边距合适 |
| 信息诚实 | 数值真实、坐标轴没有被误导性截断 |
AI 代码审查态度:把 AI 生成的 Matplotlib 代码当作「初稿」,按 12.4 的流程审查、按 12.5 的方式改进,验证后再使用——这是本书反复强调的核心能力。
动手实践
- 复现项目一的一周天气周报,把数据换成你自己的(比如一周睡眠时长)。
- 复现项目二的销售仪表盘,把「品类」换成你自己的维度。
- 让 AI 生成一张图,按 12.4 的七条逐条审查,找出至少 3 个问题。
- 按 12.5 的方式改进 AI 生成的图,保存「改进前/后」两张对比图。
- 用 12.6 清单给你的作品自评,写下每一项的得分与改进点。
常见错误
| 错误写法 | 现象 | 原因 |
|---|---|---|
| 项目代码全部写在脚本顶层 | 难以复用与测试 | 用函数组织(load → plot → save) |
| 忘了中文字体配置 | 整份报告全是方框 | 统一在文件开头配置 rcParams |
| 图表类型选错 | 信息表达不清 | 先判数据形态,再选图(6.5) |
多图忘记 tight_layout | 标题重叠 | 收尾统一 fig.tight_layout() |
| 直接信任 AI 代码 | 隐藏 bug 进入报告 | 按 12.4 审查、12.5 改进 |
章末练习
基础
- 把 12.2 的项目一改造成你自己的数据,输出一张 2×2 周报。
- 给 12.3 的仪表盘加一个「累计销售额」文本框(用
ax.text)。 - 运行 12.5 的「AI 初稿」代码,列出它至少 3 个问题。
提高
- 用 GridSpec 重排项目一:左边一列大图、右边两行小图,比较两种布局的优劣。
- 把项目二的输出同时保存为 PNG(dpi=300)与 PDF,对比文件大小。
挑战
- 独立完成一个综合项目(可参照 final.md 的三个主题之一):设计 → 实现 → 验证,并用 12.6 清单自评。
- 找一段 AI 生成的 Matplotlib 代码,按 12.4 的流程审查并重写,输出「审查报告(问题清单 + 修改说明)」与改进后的图。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
- 拿到可视化任务,第一步应该?
- A. 立刻写代码
- B. 判断数据形态,选择图表类型
- C. 问 AI 要代码
- D. 随便画一张
- 一周高低温随时间变化,首选?
- A. 饼图
- B. 折线图
- C. 箱线图
- D. 直方图
- 多图一页报告的总标题用?
- A.
ax.set_title - B.
fig.suptitle - C.
plt.title - D.
ax.suptitle
- A.
- 让主图横跨多行多列用?
- A.
subplots(2, 2) - B.
GridSpec+gs[0, :] - C.
plt.figure - D.
fig.add_axes
- A.
- 审查 AI 生成的 Matplotlib 代码,第一步是?
- A. 看配色
- B. 先运行,能跑吗
- C. 直接改标题
- D. 删除注释
- AI 初稿最常见的「中文问题」是?
- A. 中文写错
- B. 没配置中文字体,全是方框
- C. 中文太多
- D. 没有中文
- 图例对不上通常因为?
- A. 没写
label - B. 没写
title - C. 数据太多
- D. 坐标轴错误
- A. 没写
- 项目二仪表盘里,最重要的信息应该?
- A. 放最小位置
- B. 占最大面积
- C. 用最暗颜色
- D. 删掉
- 对 AI 生成的代码,正确的态度是?
- A. 直接使用并信任
- B. 审查、验证、改进后再使用
- C. 一律不用
- D. 只看注释
- 综合项目评审标准不包括?
- A. 可运行
- B. 图表类型与数据形态匹配
- C. 代码行数越少越好
- D. 保存格式合理
