《超简单:用 Python 让 Excel 飞起来》读书笔记:第8章 扩展 使用子图展示多个视角

📅 2026/7/14 6:56:16 👁️ 阅读次数 📝 编程学习
《超简单:用 Python 让 Excel 飞起来》读书笔记:第8章 扩展 使用子图展示多个视角

🔥个人主页:杨利杰YJlio
❄️个人专栏:《Sysinternals实战教程》 《Windows PowerShell 实战》 《WINDOWS教程》 《IOS教程》
《微信助手》 《锤子助手》 《Python》 《Kali Linux》
《那些年未解决的Windows疑难杂症》
🌟让复杂的事情更简单,让重复的工作自动化


《超简单:用 Python 让 Excel 飞起来》读书笔记:第8章 扩展 使用子图展示多个视角

  • 1. 第8章扩展:为什么要用子图展示多个视角
  • 2. subplot 与 subplots:为什么我更推荐 subplots
    • 2.1 subplot 快速演示写法
    • 2.2 subplots 推荐写法
  • 3. 2×2 子图仪表盘:一张图看多个维度
    • 3.1 创建 2×2 子图基础模板
  • 4. 共享坐标轴:让多子图对比更公平
    • 4.1 sharey 示例代码
  • 5. 从 Excel 读取数据并生成子图仪表盘
    • 5.1 Excel 数据结构建议
    • 5.2 完整代码:Excel 生成 2×2 子图仪表盘
  • 6. 效果验证:不要只看“有没有生成图片”
    • 6.1 推荐验证动作
  • 7. 常见问题与踩坑记录
    • 7.1 标题和坐标轴挤在一起
    • 7.2 axes 索引写错
    • 7.3 中文乱码
    • 7.4 子图太多,反而看不清
  • 8. 总结提升:子图不是拼图,是分析结构

1. 第8章扩展:为什么要用子图展示多个视角

这一篇继续整理《超简单:用 Python 让 Excel 飞起来》中关于图表自动化的内容,主题是使用子图展示多个视角。如果说单张柱形图、折线图、散点图解决的是“单一问题”,那么子图解决的就是另一个层级的问题:怎样把多个分析角度放在同一张画布里,让读者不用来回翻图也能看懂整体情况。

在真实工作里,数据分析很少只看一个指标。比如做工单分析时,我不仅想看每月工单数量,还想看解决率、数量和解决率之间有没有关系、工单数量大概集中在哪个区间。单独画四张图当然也可以,但汇报时会显得分散,读者需要不断切换上下文。

子图的本质,是在一张 Figure 画布里放多个 Axes 小图。它不是为了炫技,而是为了把“趋势、数量、关系、分布”这些不同视角集中呈现。

这张图展示了本文的核心主题:使用 Python 和 Matplotlib,把多个分析视角集中到一张图中。

从这张图中我们可以看出,子图适合承载多种图表类型:柱状图负责对比,折线图负责趋势,散点图负责关系,直方图负责分布。当一份报告需要同时说明多个问题时,子图比单独堆多张图片更清晰。

原始数据

明确分析视角

趋势分析

数量对比

关系分析

分布分析

子图仪表盘


2. subplot 与 subplots:为什么我更推荐 subplots

Matplotlib 中创建子图,常见有两种写法:plt.subplot()plt.subplots()。这两个名字很像,但实际使用体验完全不同。我的建议很明确:演示可以用 subplot,正式脚本优先用 subplots。

plt.subplot(r, c, i)的写法适合快速演示,意思是把画布分成 r 行 c 列,然后指定第 i 个位置。它的优点是上手快,缺点是代码一多就容易乱。尤其当你要循环绘图、统一设置标题、共享坐标轴时,维护成本会明显变高。

plt.subplots(r, c)更适合工程化使用,因为它会一次性返回figaxes。有了axes数组之后,每个小图都可以通过索引精准控制,结构更清楚。

这张图展示了subplot()subplots()两种写法的核心区别。

从这张图中我们可以看出,subplot()是“逐个指定位置”,更像临时画图;而subplots()是“一次创建完整布局”,更适合长期维护。如果文章中的代码准备沉淀成脚本模板,不建议长期使用 subplot 写法。

2.1 subplot 快速演示写法

importmatplotlib.pyplotasplt plt.figure(figsize=(10,4))plt.subplot(1,2,1)plt.plot([1,2,3],[2,4,6])plt.title("子图1:折线图")plt.subplot(1,2,2)plt.bar(["A","B","C"],[3,5,2])plt.title("子图2:柱形图")plt.tight_layout()plt.show()

这段代码适合教学演示,但如果你继续增加第三张、第四张图,代码会变得不太好管理。

2.2 subplots 推荐写法

importmatplotlib.pyplotasplt fig,axes=plt.subplots(1,2,figsize=(10,4))axes[0].plot([1,2,3],[2,4,6])axes[0].set_title("子图1:折线图")axes[1].bar(["A","B","C"],[3,5,2])axes[1].set_title("子图2:柱形图")plt.tight_layout()plt.show()

这里的axes[0]axes[1]就像两个独立的小画板,后续无论是加标题、加网格、设置坐标轴,还是循环处理,都会更自然。


3. 2×2 子图仪表盘:一张图看多个维度

最常用的子图布局之一是2×2 仪表盘。它适合把四类信息放在一起:趋势、数量、关系、分布。这个结构很适合日报、周报、月度数据复盘,也适合把 Excel 数据分析结果做成一张可交付图片。

比如我们拿一份工单数据来举例:

  • 折线图:看工单数量随月份变化的趋势;
  • 柱形图:看不同类别或产品的数量对比;
  • 散点图:看两个指标之间是否存在关系;
  • 直方图:看数据大致集中在哪些区间。

这张图展示了一个典型的 2×2 子图仪表盘,用四个小图同时表达趋势、数量、关系和分布。

从这张图中我们可以看出,2×2 子图不是简单把图拼在一起,而是把不同问题放到同一个分析页面里。真正有价值的子图,应该做到每个小图解决一个明确问题,而不是为了凑满四宫格。

3.1 创建 2×2 子图基础模板

importmatplotlib.pyplotaspltimportnumpyasnp plt.rcParams["font.sans-serif"]=["SimHei"]plt.rcParams["axes.unicode_minus"]=Falsemonths=["1月","2月","3月","4月","5月","6月"]tickets=np.array([120,98,135,110,150,160])rate=np.array([92,88,95,90,96,97])x=np.arange(len(months))fig,axes=plt.subplots(2,2,figsize=(11,7))# 1)折线图:趋势axes[0,0].plot(x,tickets,marker="o")axes[0,0].set_title("工单数量趋势")axes[0,0].set_xticks(x)axes[0,0].set_xticklabels(months)# 2)柱形图:数量对比axes[0,1].bar(x,tickets,alpha=0.85)axes[0,1].set_title("工单数量对比")axes[0,1].set_xticks(x)axes[0,1].set_xticklabels(months)# 3)散点图:关系axes[1,0].scatter(tickets,rate,alpha=0.85)axes[1,0].set_title("数量与解决率关系")axes[1,0].set_xlabel("工单数量")axes[1,0].set_ylabel("解决率")# 4)直方图:分布axes[1,1].hist(tickets,bins=5,alpha=0.85)axes[1,1].set_title("工单数量分布")axes[1,1].set_xlabel("数量区间")axes[1,1].set_ylabel("频数")foraxinaxes.ravel():ax.grid(True,linestyle="--",alpha=0.35)fig.suptitle("子图仪表盘:趋势 / 数量 / 关系 / 分布",fontsize=14)plt.tight_layout()plt.show()

这里最关键的写法是axes[行, 列]。它能让你非常明确地知道每一张小图放在哪里。如果后续要批量生成报告图,这种结构比临时堆代码稳得多。


4. 共享坐标轴:让多子图对比更公平

子图最容易出现的误导,不是图画错了,而是坐标轴尺度不一致。两个趋势图如果 Y 轴范围不同,视觉上会给人一种“波动都很明显”的错觉,但实际上可能只是坐标轴自动缩放造成的。

只要是用于对比的多子图,就要优先考虑是否需要共享坐标轴。常见参数是sharex=Truesharey=True

  • sharex=True:多个子图共享 X 轴;
  • sharey=True:多个子图共享 Y 轴;
  • 对比趋势时,经常使用sharey=True,让读数范围一致。

这张图展示了共享 Y 轴的意义:让两个子图使用同一套数值范围,避免读者被不同刻度误导。

从这张图中我们可以看出,共享坐标轴可以让对比更公平。尤其是在比较两个产品、两个部门、两个方案的走势时,统一刻度比单纯追求“图看起来好看”更重要。

4.1 sharey 示例代码

importmatplotlib.pyplotaspltimportnumpyasnp plt.rcParams["font.sans-serif"]=["SimHei"]plt.rcParams["axes.unicode_minus"]=Falsemonths=["1月","2月","3月","4月","5月","6月"]x=np.arange(len(months))product_a=[20,35,45,60,75,90]product_b=[18,28,38,55,65,78]fig,axes=plt.subplots(1,2,figsize=(10,4),sharey=True)axes[0].plot(x,product_a,marker="o")axes[0].set_title("产品A")axes[0].set_xticks(x)axes[0].set_xticklabels(months)axes[1].plot(x,product_b,marker="o",linestyle="--")axes[1].set_title("产品B")axes[1].set_xticks(x)axes[1].set_xticklabels(months)foraxinaxes:ax.grid(True,linestyle="--",alpha=0.35)fig.suptitle("共享Y轴:让趋势对比更公平")plt.tight_layout()plt.show()

sharey 的价值不在于少写代码,而在于降低误读风险。在正式汇报中,如果两个图本来就是用来对比的,最好不要让 Matplotlib 自动给每张图单独缩放。


5. 从 Excel 读取数据并生成子图仪表盘

前面的例子都是手写数组,但实际办公场景里,数据通常来自 Excel。真正可复用的做法应该是:从 Excel 读取数据 → 用 Python 绘制子图 → 保存为 PNG → 插入报告或 Excel 模板。

这一步才是“Excel 飞起来”的关键:不是手工画图,而是把图表生成过程变成脚本。

这张图展示了 Excel 到 Python 子图仪表盘的完整流程:读取数据、自动绘图、导出 PNG。

从这张图中我们可以看出,子图不仅是 Matplotlib 的绘图技巧,也可以成为办公自动化流程的一部分。只要 Excel 数据结构稳定,后续每次更新数据后都可以一键重新生成图表。

5.1 Excel 数据结构建议

假设 Excel 中有一个名为数据的工作表,包含以下字段:

月份工单数量解决率
2026-0112092
2026-029888
2026-0313595
2026-0411090
2026-0515096
2026-0616097

字段越稳定,脚本越稳定。不要今天叫“工单数量”,明天叫“数量”,后天又改成“工单数”,这会直接导致脚本找不到列。

5.2 完整代码:Excel 生成 2×2 子图仪表盘

importpandasaspdimportnumpyasnpimportmatplotlib.pyplotaspltfrompathlibimportPath plt.rcParams["font.sans-serif"]=["SimHei"]plt.rcParams["axes.unicode_minus"]=Falsedefexcel_to_subplots_dashboard(xlsx_path:str,sheet:str,month_col:str,count_col:str,rate_col:str,out_png:str="out/子图仪表盘.png",):# 1. 读取 Excel 数据df=pd.read_excel(xlsx_path,sheet_name=sheet)# 2. 提取字段并做基础清洗months=df[month_col].astype(str).tolist()count=pd.to_numeric(df[count_col],errors="coerce").fillna(0).to_numpy()rate=pd.to_numeric(df[rate_col],errors="coerce").fillna(0).to_numpy()x=np.arange(len(months))# 3. 创建 2×2 子图fig,axes=plt.subplots(2,2,figsize=(11,7))# 子图1:工单数量趋势axes[0,0].plot(x,count,marker="o")axes[0,0].set_title("工单数量趋势")axes[0,0].set_xticks(x)axes[0,0].set_xticklabels(months,rotation=30)# 子图2:工单数量柱形图axes[0,1].bar(x,count,alpha=0.85)axes[0,1].set_title("工单数量对比")axes[0,1].set_xticks(x)axes[0,1].set_xticklabels(months,rotation=30)# 子图3:数量与解决率关系axes[1,0].scatter(count,rate,alpha=0.85)axes[1,0].set_title("数量与解决率关系")axes[1,0].set_xlabel("工单数量")axes[1,0].set_ylabel("解决率")# 子图4:工单数量分布axes[1,1].hist(count,bins=6,alpha=0.85)axes[1,1].set_title("工单数量分布")axes[1,1].set_xlabel("数量区间")axes[1,1].set_ylabel("频数")# 4. 统一设置网格foraxinaxes.ravel():ax.grid(True,linestyle="--",alpha=0.35)fig.suptitle("子图仪表盘:数量 / 趋势 / 关系 / 分布",fontsize=14)# 5. 保存 PNGplt.tight_layout(rect=[0,0,1,0.95])out_png=Path(out_png)out_png.parent.mkdir(parents=True,exist_ok=True)plt.savefig(out_png,dpi=200)plt.close()returnstr(out_png)if__name__=="__main__":png_path=excel_to_subplots_dashboard(xlsx_path="report.xlsx",sheet="数据",month_col="月份",count_col="工单数量",rate_col="解决率",out_png="out/子图仪表盘.png",)print("已输出:",png_path)

这段代码已经具备可交付雏形:能读 Excel、能生成子图、能保存图片。后续如果要继续增强,可以把输出 PNG 插回 Excel 或 Word 报告中。


6. 效果验证:不要只看“有没有生成图片”

图表脚本运行成功,不代表结果就一定正确。我的习惯是至少检查三件事:

  • PNG 文件是否正常生成;
  • 子图数量是否正确,布局是否没有重叠;
  • 图上的数据是否和 Excel 原始数据一致。

最危险的情况不是脚本报错,而是脚本不报错但图画错了。比如字段读取错了、月份排序错了、百分比被当作普通数值处理了,这些都可能让图看起来“正常”,但结论完全偏掉。

6.1 推荐验证动作

我建议第一次跑脚本后,手动拿 Excel 原始表中的 2~3 行数据进行抽查。例如:

Excel 中 2026-01 工单数量 = 120 图表中 1月对应柱形高度是否接近 120? Excel 中 2026-02 解决率 = 88 散点图或折线图中对应点是否在 88 附近?

如果这些基础点位都对,再继续检查整体趋势。排查图表问题时,不要一上来怀疑 Matplotlib,先怀疑数据输入和字段匹配。


7. 常见问题与踩坑记录

7.1 标题和坐标轴挤在一起

这是子图最常见的问题。解决方法是增加画布尺寸,并使用tight_layout()

fig,axes=plt.subplots(2,2,figsize=(11,7))plt.tight_layout()

如果用了总标题fig.suptitle(),建议这样写:

plt.tight_layout(rect=[0,0,1,0.95])

7.2 axes 索引写错

2×2 子图中,axes是二维数组。常见写法是:

axes[0,0]axes[0,1]axes[1,0]axes[1,1]

不要把二维 axes 当成一维列表直接乱用,否则很容易出现索引错误。如果想统一循环处理,可以使用:

foraxinaxes.ravel():ax.grid(True)

7.3 中文乱码

如果标题或坐标轴中文显示成方块,可以在脚本开头加入:

plt.rcParams["font.sans-serif"]=["SimHei"]plt.rcParams["axes.unicode_minus"]=False

这不是子图的问题,而是 Matplotlib 字体配置问题。

7.4 子图太多,反而看不清

子图不是越多越好。一般博客文章里,2×2 已经比较合适。如果你放 3×3、4×4,每个小图都会被压缩,读者反而看不清。

我的建议是:一张图最多表达 3~4 个核心视角,超过这个数量就拆成多张图。


8. 总结提升:子图不是拼图,是分析结构

这一节真正值得掌握的,不是某一行 Matplotlib 代码,而是一个更实用的图表思路:当一个问题需要多个角度才能讲清楚时,就用子图把这些角度组织起来。

我从这节带走的核心结论有四个:

  1. subplot 适合快速演示,subplots 更适合正式脚本;
  2. 2×2 子图适合展示趋势、数量、关系、分布;
  3. 多图对比时要注意共享坐标轴,避免视觉误导;
  4. 从 Excel 读取数据并保存 PNG,才是真正可复用的办公自动化流程。

子图的价值不在“把多个图塞进一张画布”,而在“用一个清晰布局表达多个分析问题”。如果每个小图都有明确作用,那么这张图就是仪表盘;如果每个小图都只是凑数,那就是信息墙。

所以我建议在写 Python 图表自动化脚本时,把子图当成一种“报告结构”来设计,而不是单纯当成绘图语法。这样写出来的图,才更适合放进 Excel 报告、PPT 汇报和技术博客中。


返回顶部