Skip to content

第 12 章 综合实践:数据可视化报告

学习目标

  • 能把全书知识组合成完整程序(设计 → 实现 → 验证)
  • 会阅读 AI 生成的 Matplotlib 代码,按固定顺序审查
  • 会用「数据形态 → 图表类型」做设计决策
  • 树立「理解并验证后再使用」的态度

12.1 综合实践的思路:拆解问题

面对真实可视化任务,先拆解再编码,任何任务都按三步走:

  1. 数据是什么形态? 时间序列、类别、分布、构成、关系?这一步决定图表类型(对照第 6 章 6.5 的选图表)。
  2. 要表达什么信息? 趋势、比较、分布、占比,还是讲一个故事?这一步决定布局与标注。
  3. 如何验证? 图形画出来「一眼可读」吗?数值标签对吗?中文显示正常吗?保存的分辨率够吗?

本章用两个完整项目演示,再用一套「AI 代码审查流程」收尾——它也是结业项目的评审标准。

12.2 项目一:一周天气可视化周报

问题:拿到一周的天气数据(高低温、降雨、湿度),做一页可视化周报。

第一步,看形态。 高低温是两条时间序列(折线 + 区间)、降雨量是逐日数值(柱状)、湿度逐日(柱状)、高低温的分布(箱线图)。四种形态,四种图。

第二步,选布局。 一页四图用 subplots(2, 2),总标题用 suptitle

第三步,编码并验证。

python
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 一周天气可视化周报

注意图 12-1 里出现的知识点:折线与区间填充(第 3、6 章)、柱状图(第 5 章)、箱线图(第 6 章)、子图与 tight_layout(第 9 章)、suptitle(第 9 章)。一次实践,串起五章。

12.3 项目二:年度销售仪表盘

问题:做一张「年度销售仪表盘」,同时展示逐月趋势、品类占比、品类对比。

第一步,看形态。 逐月销量是时间序列(主图),品类占比是构成(饼图),品类销售额是类别比较(柱状)。

第二步,选布局。 想突出「趋势」,让折线图横跨整行(用 GridSpec);下方放饼图与柱状图。

第三步,编码并验证。

python
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 标出年度峰值:

图 12-2 年度销售仪表盘

仪表盘的核心是「信息分层」:最重要的趋势占最大面积,支撑信息放次要位置。这张图用到的知识点:GridSpec(第 9 章)、饼图(第 6 章)、柱状图(第 5 章)、注释(第 8 章)、fill_between(第 6 章)。

12.4 阅读 AI 生成的 Matplotlib 代码

你让 AI 画图,它给你一段代码。不要直接信任,按固定顺序审查:

  1. 能跑吗? 先运行。报错先读最后一行,确认是不是 ValueError / AttributeError 等常见问题。
  2. 中文正常吗? 有没有配置 font.sans-serifaxes.unicode_minus?很多 AI 初稿会漏这一步,画出一片方框。
  3. 有标题、轴标签、单位吗? 没有标签的图无法独立阅读。
  4. 图例对得上吗? label 是否都写了、图例是否有遗漏或多余。
  5. 配色和字号合适吗? 配色是否冲突、投影/打印是否够大。
  6. 布局对吗? 子图是否重叠,要不要 tight_layout
  7. 信息诚实吗? 坐标轴范围有没有被故意截断制造误导、数值标签是否真实。

12.5 改进一段 AI 生成的代码

下面是一段「AI 初稿」的真实样例(为演示,故意保留了常见问题):中文未配置、无轴标签、无网格、五条线配色杂乱:

python
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-3 AI 初稿:中文乱码、配色杂乱、可读性差

按 12.4 的审查流程逐条改进:

python
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 是改进后的真实输出:中文正常、统一配色、加网格与图例、标注单位:

图 12-4 改进后:中文正常、配色统一、可读性高

改进点逐条对应:① 补中文字体配置;② 用品牌色替换「红绿蓝」;③ 加单位「万元」;④ 图例排 3 列、加网格;⑤ 标记点便于读数。

12.6 综合项目评审清单

做结业项目时,对照下面的清单自评(也是 final.md 的评审标准):

标准说明
可运行按 README 或注释说明可一键运行,无语法错误
中文正常中文字体配置正确,图内无方框
有标签每张图都有标题、轴标签(带单位)、必要的图例
图对信息图表类型与数据形态匹配,没有「用错图」
结构清晰用函数组织代码,没有大段重复
布局得当多图用子图/GridSpec 组织,无重叠
保存合理输出 PNG(dpi≥150)或 PDF,边距合适
信息诚实数值真实、坐标轴没有被误导性截断

AI 代码审查态度:把 AI 生成的 Matplotlib 代码当作「初稿」,按 12.4 的流程审查、按 12.5 的方式改进,验证后再使用——这是本书反复强调的核心能力。

动手实践

  1. 复现项目一的一周天气周报,把数据换成你自己的(比如一周睡眠时长)。
  2. 复现项目二的销售仪表盘,把「品类」换成你自己的维度。
  3. 让 AI 生成一张图,按 12.4 的七条逐条审查,找出至少 3 个问题。
  4. 按 12.5 的方式改进 AI 生成的图,保存「改进前/后」两张对比图。
  5. 用 12.6 清单给你的作品自评,写下每一项的得分与改进点。

常见错误

错误写法现象原因
项目代码全部写在脚本顶层难以复用与测试用函数组织(load → plot → save)
忘了中文字体配置整份报告全是方框统一在文件开头配置 rcParams
图表类型选错信息表达不清先判数据形态,再选图(6.5)
多图忘记 tight_layout标题重叠收尾统一 fig.tight_layout()
直接信任 AI 代码隐藏 bug 进入报告按 12.4 审查、12.5 改进

章末练习

基础

  1. 把 12.2 的项目一改造成你自己的数据,输出一张 2×2 周报。
  2. 给 12.3 的仪表盘加一个「累计销售额」文本框(用 ax.text)。
  3. 运行 12.5 的「AI 初稿」代码,列出它至少 3 个问题。

提高

  1. 用 GridSpec 重排项目一:左边一列大图、右边两行小图,比较两种布局的优劣。
  2. 把项目二的输出同时保存为 PNG(dpi=300)与 PDF,对比文件大小。

挑战

  1. 独立完成一个综合项目(可参照 final.md 的三个主题之一):设计 → 实现 → 验证,并用 12.6 清单自评。
  2. 找一段 AI 生成的 Matplotlib 代码,按 12.4 的流程审查并重写,输出「审查报告(问题清单 + 修改说明)」与改进后的图。

章末自测

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

  1. 拿到可视化任务,第一步应该?
    • A. 立刻写代码
    • B. 判断数据形态,选择图表类型
    • C. 问 AI 要代码
    • D. 随便画一张
  2. 一周高低温随时间变化,首选?
    • A. 饼图
    • B. 折线图
    • C. 箱线图
    • D. 直方图
  3. 多图一页报告的总标题用?
    • A. ax.set_title
    • B. fig.suptitle
    • C. plt.title
    • D. ax.suptitle
  4. 让主图横跨多行多列用?
    • A. subplots(2, 2)
    • B. GridSpec + gs[0, :]
    • C. plt.figure
    • D. fig.add_axes
  5. 审查 AI 生成的 Matplotlib 代码,第一步是?
    • A. 看配色
    • B. 先运行,能跑吗
    • C. 直接改标题
    • D. 删除注释
  6. AI 初稿最常见的「中文问题」是?
    • A. 中文写错
    • B. 没配置中文字体,全是方框
    • C. 中文太多
    • D. 没有中文
  7. 图例对不上通常因为?
    • A. 没写 label
    • B. 没写 title
    • C. 数据太多
    • D. 坐标轴错误
  8. 项目二仪表盘里,最重要的信息应该?
    • A. 放最小位置
    • B. 占最大面积
    • C. 用最暗颜色
    • D. 删掉
  9. 对 AI 生成的代码,正确的态度是?
    • A. 直接使用并信任
    • B. 审查、验证、改进后再使用
    • C. 一律不用
    • D. 只看注释
  10. 综合项目评审标准不包括?
    • A. 可运行
    • B. 图表类型与数据形态匹配
    • C. 代码行数越少越好
    • D. 保存格式合理