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

发布时间:2026/7/14 6:53:09
《超简单:用 Python 让 Excel 飞起来》读书笔记:第8章 扩展 使用子图展示多个视角 个人主页杨利杰YJlio❄️个人专栏《Sysinternals实战教程》 《Windows PowerShell 实战》 《WINDOWS教程》 《IOS教程》《微信助手》 《锤子助手》 《Python》 《Kali Linux》《那些年未解决的Windows疑难杂症》让复杂的事情更简单让重复的工作自动化《超简单用 Python 让 Excel 飞起来》读书笔记第8章 扩展 使用子图展示多个视角1. 第8章扩展为什么要用子图展示多个视角2. subplot 与 subplots为什么我更推荐 subplots2.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为什么我更推荐 subplotsMatplotlib 中创建子图常见有两种写法plt.subplot()和plt.subplots()。这两个名字很像但实际使用体验完全不同。我的建议很明确演示可以用 subplot正式脚本优先用 subplots。plt.subplot(r, c, i)的写法适合快速演示意思是把画布分成 r 行 c 列然后指定第 i 个位置。它的优点是上手快缺点是代码一多就容易乱。尤其当你要循环绘图、统一设置标题、共享坐标轴时维护成本会明显变高。plt.subplots(r, c)更适合工程化使用因为它会一次性返回fig和axes。有了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,axesplt.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月]ticketsnp.array([120,98,135,110,150,160])ratenp.array([92,88,95,90,96,97])xnp.arange(len(months))fig,axesplt.subplots(2,2,figsize(11,7))# 1折线图趋势axes[0,0].plot(x,tickets,markero)axes[0,0].set_title(工单数量趋势)axes[0,0].set_xticks(x)axes[0,0].set_xticklabels(months)# 2柱形图数量对比axes[0,1].bar(x,tickets,alpha0.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,alpha0.85)axes[1,0].set_title(数量与解决率关系)axes[1,0].set_xlabel(工单数量)axes[1,0].set_ylabel(解决率)# 4直方图分布axes[1,1].hist(tickets,bins5,alpha0.85)axes[1,1].set_title(工单数量分布)axes[1,1].set_xlabel(数量区间)axes[1,1].set_ylabel(频数)foraxinaxes.ravel():ax.grid(True,linestyle--,alpha0.35)fig.suptitle(子图仪表盘趋势 / 数量 / 关系 / 分布,fontsize14)plt.tight_layout()plt.show()这里最关键的写法是axes[行, 列]。它能让你非常明确地知道每一张小图放在哪里。如果后续要批量生成报告图这种结构比临时堆代码稳得多。4. 共享坐标轴让多子图对比更公平子图最容易出现的误导不是图画错了而是坐标轴尺度不一致。两个趋势图如果 Y 轴范围不同视觉上会给人一种“波动都很明显”的错觉但实际上可能只是坐标轴自动缩放造成的。只要是用于对比的多子图就要优先考虑是否需要共享坐标轴。常见参数是sharexTrue和shareyTruesharexTrue多个子图共享 X 轴shareyTrue多个子图共享 Y 轴对比趋势时经常使用shareyTrue让读数范围一致。这张图展示了共享 Y 轴的意义让两个子图使用同一套数值范围避免读者被不同刻度误导。从这张图中我们可以看出共享坐标轴可以让对比更公平。尤其是在比较两个产品、两个部门、两个方案的走势时统一刻度比单纯追求“图看起来好看”更重要。4.1 sharey 示例代码importmatplotlib.pyplotaspltimportnumpyasnp plt.rcParams[font.sans-serif][SimHei]plt.rcParams[axes.unicode_minus]Falsemonths[1月,2月,3月,4月,5月,6月]xnp.arange(len(months))product_a[20,35,45,60,75,90]product_b[18,28,38,55,65,78]fig,axesplt.subplots(1,2,figsize(10,4),shareyTrue)axes[0].plot(x,product_a,markero)axes[0].set_title(产品A)axes[0].set_xticks(x)axes[0].set_xticklabels(months)axes[1].plot(x,product_b,markero,linestyle--)axes[1].set_title(产品B)axes[1].set_xticks(x)axes[1].set_xticklabels(months)foraxinaxes:ax.grid(True,linestyle--,alpha0.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-01120922026-0298882026-03135952026-04110902026-05150962026-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:strout/子图仪表盘.png,):# 1. 读取 Excel 数据dfpd.read_excel(xlsx_path,sheet_namesheet)# 2. 提取字段并做基础清洗monthsdf[month_col].astype(str).tolist()countpd.to_numeric(df[count_col],errorscoerce).fillna(0).to_numpy()ratepd.to_numeric(df[rate_col],errorscoerce).fillna(0).to_numpy()xnp.arange(len(months))# 3. 创建 2×2 子图fig,axesplt.subplots(2,2,figsize(11,7))# 子图1工单数量趋势axes[0,0].plot(x,count,markero)axes[0,0].set_title(工单数量趋势)axes[0,0].set_xticks(x)axes[0,0].set_xticklabels(months,rotation30)# 子图2工单数量柱形图axes[0,1].bar(x,count,alpha0.85)axes[0,1].set_title(工单数量对比)axes[0,1].set_xticks(x)axes[0,1].set_xticklabels(months,rotation30)# 子图3数量与解决率关系axes[1,0].scatter(count,rate,alpha0.85)axes[1,0].set_title(数量与解决率关系)axes[1,0].set_xlabel(工单数量)axes[1,0].set_ylabel(解决率)# 子图4工单数量分布axes[1,1].hist(count,bins6,alpha0.85)axes[1,1].set_title(工单数量分布)axes[1,1].set_xlabel(数量区间)axes[1,1].set_ylabel(频数)# 4. 统一设置网格foraxinaxes.ravel():ax.grid(True,linestyle--,alpha0.35)fig.suptitle(子图仪表盘数量 / 趋势 / 关系 / 分布,fontsize14)# 5. 保存 PNGplt.tight_layout(rect[0,0,1,0.95])out_pngPath(out_png)out_png.parent.mkdir(parentsTrue,exist_okTrue)plt.savefig(out_png,dpi200)plt.close()returnstr(out_png)if__name____main__:png_pathexcel_to_subplots_dashboard(xlsx_pathreport.xlsx,sheet数据,month_col月份,count_col工单数量,rate_col解决率,out_pngout/子图仪表盘.png,)print(已输出,png_path)这段代码已经具备可交付雏形能读 Excel、能生成子图、能保存图片。后续如果要继续增强可以把输出 PNG 插回 Excel 或 Word 报告中。6. 效果验证不要只看“有没有生成图片”图表脚本运行成功不代表结果就一定正确。我的习惯是至少检查三件事PNG 文件是否正常生成子图数量是否正确布局是否没有重叠图上的数据是否和 Excel 原始数据一致。最危险的情况不是脚本报错而是脚本不报错但图画错了。比如字段读取错了、月份排序错了、百分比被当作普通数值处理了这些都可能让图看起来“正常”但结论完全偏掉。6.1 推荐验证动作我建议第一次跑脚本后手动拿 Excel 原始表中的 23 行数据进行抽查。例如Excel 中 2026-01 工单数量 120 图表中 1月对应柱形高度是否接近 120 Excel 中 2026-02 解决率 88 散点图或折线图中对应点是否在 88 附近如果这些基础点位都对再继续检查整体趋势。排查图表问题时不要一上来怀疑 Matplotlib先怀疑数据输入和字段匹配。7. 常见问题与踩坑记录7.1 标题和坐标轴挤在一起这是子图最常见的问题。解决方法是增加画布尺寸并使用tight_layout()fig,axesplt.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每个小图都会被压缩读者反而看不清。我的建议是一张图最多表达 34 个核心视角超过这个数量就拆成多张图。8. 总结提升子图不是拼图是分析结构这一节真正值得掌握的不是某一行 Matplotlib 代码而是一个更实用的图表思路当一个问题需要多个角度才能讲清楚时就用子图把这些角度组织起来。我从这节带走的核心结论有四个subplot 适合快速演示subplots 更适合正式脚本2×2 子图适合展示趋势、数量、关系、分布多图对比时要注意共享坐标轴避免视觉误导从 Excel 读取数据并保存 PNG才是真正可复用的办公自动化流程。子图的价值不在“把多个图塞进一张画布”而在“用一个清晰布局表达多个分析问题”。如果每个小图都有明确作用那么这张图就是仪表盘如果每个小图都只是凑数那就是信息墙。所以我建议在写 Python 图表自动化脚本时把子图当成一种“报告结构”来设计而不是单纯当成绘图语法。这样写出来的图才更适合放进 Excel 报告、PPT 汇报和技术博客中。返回顶部