在日常办公中,从Excel提取数据并生成图表是常见需求。手工重复操作效率低,容易出错。本文提供一套完整的Python自动化流程:读取Excel数据,使用pandas清洗,matplotlib绘制图表保存为PNG,最后通过xlwings将图表插回Excel指定位置。整个过程可复用,只需修改文件名和列名即可适应不同报表。
适用场景与前提
该方法适合Excel表结构固定、数据定期更新的场景,如工单趋势、销售统计、巡检汇总等。注意:xlwings依赖本机Microsoft Excel应用,因此推荐在Windows办公电脑上运行。如果仅需生成PNG,可只用pandas+matplotlib;需要交付带图表的Excel文件则必须安装xlwings。
环境准备
需要安装四个核心库:pandas(读取清洗Excel数据)、matplotlib(绘图并保存PNG)、openpyxl(pandas读取.xlsx的底层引擎)、xlwings(通过Excel应用程序操控工作簿)。- pip install pandas matplotlib openpyxl xlwings
复制代码 安装后可用以下代码自检:- import pandas as pd
- import matplotlib.pyplot as plt
- import xlwings as xw
- print("环境检测通过")
复制代码
核心:读取Excel生成图表PNG
假设Excel文件report.xlsx,工作表名为“数据”,包含“月份”和“工单数量”两列。关键点:列名应干净、无合并单元格,数值列可能混入空格或文本。使用pd.to_numeric(..., errors='coerce')将非数值转为NaN,再dropna()清理。- import pandas as pd
- import matplotlib.pyplot as plt
- from pathlib import Path
- def excel_to_chart_png(xlsx_path, sheet_name, x_col, y_col, out_png):
- df = pd.read_excel(xlsx_path, sheet_name=sheet_name)
- x = df[x_col].astype(str)
- y = pd.to_numeric(df[y_col], errors="coerce")
- data = pd.DataFrame({x_col: x, y_col: y}).dropna()
- plt.figure(figsize=(8, 4))
- plt.plot(data[x_col], data[y_col], marker="o")
- plt.title(f"{y_col}趋势图")
- plt.xlabel(x_col)
- plt.ylabel(y_col)
- plt.xticks(rotation=30)
- plt.grid(axis="y", linestyle="dashed", alpha=0.4)
- plt.tight_layout()
- out_png = Path(out_png)
- out_png.parent.mkdir(parents=True, exist_ok=True)
- plt.savefig(out_png, dpi=200)
- plt.close()
- return str(out_png)
- if __name__ == "__main__":
- png = excel_to_chart_png("report.xlsx", "数据", "月份", "工单数量", "out/chart.png")
- print("图表已输出:", png)
复制代码
插图到Excel:xlwings控制位置
生成PNG后,需要将图片插回Excel报表。核心操作:定位锚点单元格(如H2),删除同名旧图避免叠图,插入新图并调整尺寸,另存为新文件以保护原数据。- import xlwings as xw
- from pathlib import Path
- def insert_png_to_excel(xlsx_path, sheet_name, png_path, anchor_cell="H2", out_xlsx=None):
- xlsx_path = str(Path(xlsx_path).resolve())
- png_path = str(Path(png_path).resolve())
- if out_xlsx is None:
- p = Path(xlsx_path)
- out_xlsx = str(p.with_name(p.stem + "_已插图" + p.suffix))
- app = xw.App(visible=False, add_book=False)
- try:
- wb = app.books.open(xlsx_path)
- sht = wb.sheets[sheet_name]
- cell = sht.range(anchor_cell)
- # 删除同名旧图,避免重复叠图
- for pic in list(sht.pictures):
- if pic.name == "chart_png":
- pic.delete()
- sht.pictures.add(png_path, name="chart_png", left=cell.left, top=cell.top)
- pic = sht.pictures["chart_png"]
- pic.width = 520
- pic.height = 320
- wb.save(out_xlsx)
- wb.close()
- finally:
- app.quit()
- return out_xlsx
- if __name__ == "__main__":
- out = insert_png_to_excel("report.xlsx", "数据", "out/chart.png", "H2")
- print("已写回Excel:", out)
复制代码
合体脚本:一键自动化
将两个函数组合,只需修改四个变量(xlsx、sheet、x_col、y_col)即可快速迁移到其他报表。- if __name__ == "__main__":
- xlsx = "report.xlsx"
- sheet = "数据"
- x_col = "月份"
- y_col = "工单数量"
- png = excel_to_chart_png(xlsx, sheet, x_col, y_col, "out/chart.png")
- out = insert_png_to_excel(xlsx, sheet, png, "H2")
- print("完成交付文件:", out)
复制代码
效果验证要点
1. 检查PNG是否存在、标题正确、x/y轴数据合理、中文无乱码。
2. 打开带图Excel,确认图片位于指定锚点,未压住数据,尺寸合适。
3. 抽查原始数据与图表趋势是否一致。
常见踩坑与解决
ModuleNotFoundError:使用“python -m pip install”确保安装到当前Python环境。
中文标题显示为方块:matplotlib默认字体不含中文,添加以下配置:- plt.rcParams["font.sans-serif"] = ["SimHei"]
- plt.rcParams["axes.unicode_minus"] = False
复制代码 xlwings无法打开Excel:检查本机是否安装Microsoft Excel(非WPS或其他Office)。若在无Office的服务器上运行,建议只使用pandas+matplotlib。
图片重复插入:脚本中已通过删除同名图片“chart_png”避免叠图。若仍出现,检查图片名称是否一致。
图片压住数据:调整锚点单元格(如改用J3或L2),或在模板中预留固定图表区域。
总结
本文并非单纯展示绘图语法,而是构建一条“Excel数据源→pandas读取→matplotlib出图→xlwings插回Excel→交付文件”的自动化链路。实际落地时重点关注数据清洗、图片定位、避免覆盖原文件。掌握这套流程后,面对同类型报表只需调整列名和路径,即可快速实现办公自动化。 |