PX04-用 Python 读 Excel 画折线图,还能直接插回 Excel 文件

适用版本:Python 3.10+ / pandas 2.0+ / matplotlib 3.x / xlwings 0.24.3+

依赖pandasmatplotlibxlwings

平台:Windows(xlwings 需要本机安装 Microsoft Excel)


1. 为什么需要这套方案

做报表的朋友大概都有这种经历:业务方拿到 Excel,转头就问"能不能带个趋势图?"。行吧,画就画,可你用 Excel 自带图表辛辛苦苦做完,发过去第二天人又来了------数据更新了,图得重做。

手动截图、粘贴、对齐位置,一次两次还行,天天来谁受得了。

这篇讲一个我自己用了挺久的套路:用 Python 从 Excel 读数据,matplotlib 画图,然后直接把图片插回同一张 Excel 工作表里。脚本写好之后,数据一变重跑一下就行,全程不用手动碰。

2. 工具分工

环节 工具 理由
从 Excel 读数据 xlwings 文件可能有合并表头/格式,xlwings 读的是"所见即所得"的当前区域
计算与整理 pandas 转成 DataFrame 后排序、重采样都方便
画图 matplotlib 样式可控,能出高质量图
插回 Excel xlwings sheet.pictures.add() 唯一能把图片落到指定单元格位置的方案

3. 完整实现

直接上代码,注释写得很细,复制过去改改路径就能跑:

python 复制代码
import matplotlib.pyplot as plt
import pandas as pd
import xlwings as xw
from pathlib import Path

DATA_DIR = Path(r"D:\MTCResearch\Python-excels\data")
SRC = DATA_DIR / "本月份上衣销量数据.xlsx"

# -------------------------------------------------------------
# 中文字体配置(Windows)------这两行千万别忘了!
# 不配置的话,所有中文都会渲染成"□□□"方框
# -------------------------------------------------------------
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]   # 前者优先,后者兜底
plt.rcParams["axes.unicode_minus"] = False   # 解决负号显示为方块的问题

with xw.App(visible=False, add_book=False) as app:
    wb = app.books.open(SRC)
    sheet = wb.sheets[0]

    # ---------------------------------------------------------
    # 第一步:把 Excel 当前区域读成 DataFrame
    # options(pd.DataFrame, ...) 的第一个参数指定"返回类型"
    # expand="table" 从 A1 向下向右扩展到连续数据边界
    #
    # 注意:默认会把【第一列当作行索引】,本例第一列是日期,正好拿来做横轴;
    #      若你的首列是普通数据(如"序号"),加 index=False 关掉这个行为
    # ---------------------------------------------------------
    df = sheet.range("A1").options(pd.DataFrame, expand="table").value

    # 保险起见统一类型:Excel 存的数字常常被读成 float
    df["销量"] = df["销量"].astype(float)
    print(df.head())
    #           类型     销量
    # 日期
    # 2021-07-01  上衣  691.0
    # 2021-07-02  上衣  121.0
    # 2021-07-03  上衣  118.0
    # 2021-07-04  上衣  879.0
    # 2021-07-05  上衣  470.0

    # ---------------------------------------------------------
    # 第二步:画图
    # figsize 单位是英寸,(12, 6) 是 12:6 的宽屏比例
    # dpi=100 → 输出 1200×600 像素
    # ---------------------------------------------------------
    fig, ax = plt.subplots(figsize=(12, 6), dpi=100)
    ax.plot(df.index, df["销量"], marker="o", linewidth=1.5, color="#C00000")
    ax.set_title("本月份上衣销量趋势", fontsize=14)
    ax.set_xlabel("日期")
    ax.set_ylabel("销量(件)")
    ax.grid(alpha=0.3, linestyle="--")
    fig.autofmt_xdate()          # 日期标签自动倾斜,避免重叠
    fig.tight_layout()           # 自动裁剪白边

    # ---------------------------------------------------------
    # 第三步:插入 Excel
    # name     → 图片在 Excel 中的名称(相当于"图层名")
    # update   → True 表示已存在同名图片时【替换】,False 会叠加上去
    # left/top → 以 E3 单元格的左上角为锚点(单位:磅 point)
    # ---------------------------------------------------------
    pic = sheet.pictures.add(
        fig,
        name="折线图",
        update=True,
        left=sheet.range("E3").left,
        top=sheet.range("E3").top,
    )
    print(pic)      # <Picture '折线图' in <Sheet [本月份上衣销量数据.xlsx]Sheet1>>

    # ---------------------------------------------------------
    # 第四步:释放资源
    # 不 close 的话,matplotlib 会累计 figure 并在超过 20 个时告警
    # ---------------------------------------------------------
    plt.close(fig)

    wb.save()
    wb.close()

4. 6 个你很可能踩的坑

这些都是我实打实踩过的坑,列出来帮你省点时间。

4.1 中文乱码:这两行千万别忘了

python 复制代码
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]  # 指定中文字体
plt.rcParams["axes.unicode_minus"] = False                        # 修复负号变方块

只写第一行不行------中文能显示,但坐标轴上的负号 - 会变成方块,因为默认字体里没有对应的字形。两行必须同时加。

各平台可用的中文字体:

平台 推荐字体名
Windows SimHei(黑体)、Microsoft YaHei(微软雅黑)
macOS Arial Unicode MSPingFang SC
Linux 需手动安装 Noto Sans CJK SC,再 fc-list :lang=zh 查名称

4.2 options(pd.DataFrame) 默认吃掉第一列

python 复制代码
df = sheet.range("A1").options(pd.DataFrame, expand="table").value

这行默认把第一列作为行索引。本例第一列是日期,正好当横轴用,感觉还挺方便。但如果你的第一列是普通数据(比如"序号"),数据就会被"吃掉"变成索引,人都懵了------怎么少了一列?

关掉它:

python 复制代码
df = sheet.range("A1").options(pd.DataFrame, expand="table", index=False).value

对应的还有 header=False(不把第一行当列名),需要的时候也记得加。

4.3 重跑脚本,图越叠越多

pictures.add() 每调用一次就插入一张新图。如果你不带 update=True 就反复运行脚本,工作表上会叠着一堆一模一样的图,而且肉眼很难发现------因为它们完美重合了。

下次你手动拖动图片的时候,下面还藏着十张八张,那画面太美......

养成习惯: update=True 加上。

4.4 定位图片别写死像素

python 复制代码
left=sheet.range("E3").left      # E3 左边缘距工作表左边的距离(磅)
top=sheet.range("E3").top        # E3 上边缘距工作表顶部的距离(磅)

用单元格坐标来定位,好处是插入列、调整行高之后,图片锚点会自动跟着走。

如果你写 left=300, top=50 这种魔法数字,哪天表格前面加了一列,图就飘到不知道哪儿去了。

需要缩放的话,再加 width / height(单位也是磅)或者 scale=0.8

4.5 一定要 plt.close(fig),不然内存炸

matplotlib 的 figure 不会自动回收。你要是在循环里给几十个 sheet 各画一张图,又忘了 close(),第 21 张就会弹警告:

RuntimeWarning: More than 20 figures have been opened.

内存也会一路涨。画完即关,这是个好习惯。

4.6 不需要插回 Excel?直接存图片更省事

如果你的需求只是"出一张图",不需要嵌回 Excel,那直接 savefig 就完事儿了,也完全不依赖 Excel:

python 复制代码
fig.savefig(DATA_DIR / "销量趋势.png", dpi=150, bbox_inches="tight")

bbox_inches="tight" 能帮你把多余的白边裁掉,出图更清爽。

5. 常见报错对照表

踩坑多了,整理了一份速查表,遇到问题先对照看看:

报错 / 现象 什么情况 怎么修
图上中文全是 □□□ 方块 没配置中文字体 font.sans-serif 那行
负号也是方块 axes.unicode_minus=False 补上,这两行要成双成对
每次运行图越来越多、越叠越厚 update=False 或者没写 改成 update=True
More than 20 figures 警告 plt.close() 画完就关,别攒着
插进 Excel 的图是空白的 你先 close() 了再 add 顺序反了,先 add 再 close
第一列数据"消失"了 options(pd.DataFrame) 默认吃首列作索引 index=False
任务管理器里一堆 EXCEL.EXE 关不掉 没用 with / 没 quit() with xw.App() as app 包起来
日期横轴挤成一团看不清 标签太长了 fig.autofmt_xdate() 自动倾斜

6. 小结

这套"读 Excel → 画图 → 插回 Excel"的流程,核心就三点:

  1. 用 xlwings 读写 Excel,所见即所得,不破坏原表格式;
  2. 用 matplotlib 画图,样式可控、质量高;
  3. update=True + 单元格锚点定位,脚本可重复运行,数据更新后一键重出图。

把这套脚本固化下来,以后业务方再要趋势图,你只需要改改数据文件路径,跑一下,完事儿。

相关推荐
Mr.朱鹏1 小时前
Docker三剑客实战指南:Docker、Dockerfile 和 Docker Compose
python·docker·devops·dockerfile
0566461 小时前
用大模型构建答疑机器人:从 API 调用到上下文工程
python·学习·agent
haluhalu.1 小时前
初识 Protobuf:微服务跨语言通信的一份契约
java·c语言·开发语言·c++·python
Liaiyang661 小时前
# 自研 AST 容错初筛工具:横向评测 Django、PyTorch、TensorFlow 三大开源 Python 框架异常收容风险
python·测试工具·自动化·开源软件·代码规范·devops·代码复审
空奈qwq1 小时前
机器学习入门:从核心概念到建模全流程
人工智能·python·机器学习
IvanCodes1 小时前
Python 基础语法(六):字典与集合
python
lie..1 小时前
30天从零开始学AI应用开发(Day 4):Python 极速入门(上):够用就行,别啃书
人工智能·python·大模型
正经教主2 小时前
【FDE系列】阶段2:Day 38:Shell 脚本 — 把命令串起来自动跑
人工智能·python·fde
诺伦2 小时前
多Agent架构下Token成本优化实战:Agent编排策略与预算控制全解析
python·ai agent·token优化·agent编排·多agent架构·llm成本控制