跳到主内容
快讯直播
AI智模界
教程

Excel 秒变图表:AI 辅助数据可视化实战

把一张手头的 Excel 表格丢进去,几分钟后拿到一张可以直接贴进周报的柱状图、折线图或交互式 HTML 图表——不需要记图表菜单在哪,也不需要手动拖数据区域。这篇教程带你搭一条可复用的流水线:让大模型把"业务需求 + 表结构"翻译成一份图表配置(JSON),再由本地脚本读取 Excel 渲染出图。

这样做比直接让模型输出绘图代码更稳:配置是纯数据,容易被校验、被修改、被批量复用;而生成的代码一旦列名写错,往往要来回调试好几轮。

这篇能做出什么

完成后你会拥有三个文件:

  • inspect.py:读取 Excel,打印列名、类型、缺失值,帮你确认"数据长什么样"
  • render.py:读一份 JSON 配置 + 一个 Excel,输出 PNG 或交互式 HTML
  • prompt.md:一段固定提示词,把表结构和你的需求发给任意大模型,拿回合法配置

再配一个 run.sh 或一段 Python 批处理,就能对同一个 Excel 里的多个 sheet 一次性出图。

前置条件清单

  • 一台能装 Python 的电脑(Windows / macOS / Linux 均可)
  • Python 3 环境,版本以官方文档当前版本为准
  • 一个能读取 Excel 的大模型对话入口或 API(可选,没有也能跑,配置手写即可)
  • 待处理的 Excel 文件,.xlsx 格式

依赖清单:pandasopenpyxlmatplotlibplotly。前三者负责读表和出静态图,plotly 负责交互式 HTML。

如果你要把数据发到云端模型,先做脱敏:删掉姓名、手机号、身份证号、客户编号这类列,或者只发列名和前 5 行样例,不发全量数据。

第一步:建目录、装依赖

```bash

mkdir -p ~/excel-chart/data ~/excel-chart/out

cd ~/excel-chart

python3 -m venv .venv

source .venv/bin/activate # Windows 用 .venv\Scripts\activate

pip install pandas openpyxl matplotlib plotly

```

把待处理的 Excel 放进 data/ 目录,比如 data/sales.xlsx。输出的图统一落在 out/

第二步:先做数据体检

很多人出图失败,不是绘图代码的问题,而是 Excel 里的数字被当成了文本。先跑体检脚本看清事实。

```python

inspect.py

import sys

import pandas as pd

path = sys.argv[1] if len(sys.argv) > 1 else "data/sales.xlsx"

xl = pd.ExcelFile(path)

print("sheet 列表:", xl.sheet_names)

for name in xl.sheet_names:

df = xl.parse(name)

print(f"\n=== sheet: {name} | 行数 {len(df)} 列数 {len(df.columns)} ===")

print("列名:", list(df.columns))

print("类型:")

print(df.dtypes.to_string())

print("缺失值:")

print(df.isna().sum().to_string())

print("前 5 行:")

print(df.head().to_string())

```

运行:

```bash

python inspect.py data/sales.xlsx

```

重点看三件事:

1. 本该是数字的列(销售额、数量)类型是不是 int64 / float64。如果是 object,说明混了文本。

2. 日期列是不是 datetime64。如果是 object,排序会按字符串走,"10月"会排在"2月"前面。

3. 缺失值有多少。数值列有缺失,聚合结果会偏。

第三步:把脏数据修干净

针对体检发现的问题,在读取阶段加一层清洗。下面是一个通用清洗函数,按需取用。

```python

clean.py

import pandas as pd

def to_number(s: pd.Series) -> pd.Series:

"""处理 '1,234'、'¥1200'、'12.5%' 这类文本数字"""

if s.dtype.kind in "if":

return s

t = s.astype(str).str.strip()

if t.str.endswith("%").any():

return pd.to_numeric(t.str.rstrip("%"), errors="coerce") / 100

t = t.str.replace(r"[,\s¥$¥元]", "", regex=True)

return pd.to_numeric(t, errors="coerce")

def load(path: str, sheet: str) -> pd.DataFrame:

df = pd.read_excel(path, sheet_name=sheet)

df.columns = [str(c).strip() for c in df.columns]

合并单元格读出来是 NaN,向下填充

for col in df.columns:

if df[col].dtype == object and df[col].isna().any():

df[col] = df[col].ffill()

日期列:列名里带"日期/时间/月/日"的尝试转换

for col in df.columns:

if any(k in col for k in ("日期", "时间", "date", "Date", "月份")):

df[col] = pd.to_datetime(df[col], errors="coerce")

文本列里的数字

for col in df.columns:

if df[col].dtype == object and col not in ("部门", "产品", "地区"):

df[col] = to_number(df[col]) if df[col].astype(str).str.contains(r"\d").any() else df[col]

return df

```

最后那个循环是个启发式,实际用的时候建议把要转数字的列名显式写出来,避免误伤。比如:

```python

for col in ["销售额", "数量", "单价"]:

df[col] = to_number(df[col])

```

第四步:定义图表配置格式

不要让模型直接写 matplotlib 代码,让它填这张"表单":

```json

{

"chart": "bar",

"x": "月份",

"y": ["销售额"],

"agg": "sum",

"sort": "desc",

"top": 10,

"title": "各月销售额排名"

}

```

字段含义:

  • chartbar 柱状、line 折线、pie 饼图、scatter 散点
  • x:横轴列名
  • y:数值列名数组,可以有多个
  • agg:聚合方式,sum / mean / max / min / null(不聚合)
  • sortdesc / asc / null
  • top:只取前 N 项,null 表示全部
  • title:图标题

保存为 spec/bar.json

第五步:写渲染器

这个脚本读取配置和 Excel,做列名校验、聚合、排序,然后出图。

```python

render.py

import json

import sys

import pandas as pd

import matplotlib

matplotlib.use("Agg")

import matplotlib.pyplot as plt

from clean import load

中文字体:按系统已有字体排优先级

plt.rcParams["font.sans-serif"] = [

"Noto Sans CJK SC", "Source Han Sans SC", "PingFang SC",

"Microsoft YaHei", "SimHei", "Arial Unicode MS",

]

plt.rcParams["axes.unicode_minus"] = False

def validate(spec: dict, df: pd.DataFrame) -> None:

need = [spec["x"]] + list(spec["y"])

missing = [c for c in need if c not in df.columns]

if missing:

raise ValueError(

f"表里找不到这些列: {missing}\n实际列名: {list(df.columns)}"

)

def prepare(spec: dict, df: pd.DataFrame) -> pd.DataFrame:

x = spec["x"]

ys = list(spec["y"])

data = df[[x] + ys].copy().dropna(subset=[x])

for c in ys:

data[c] = pd.to_numeric(data[c], errors="coerce")

data[c] = data[c].fillna(0)

if spec.get("agg"):

data = data.groupby(x, as_index=False)[ys].agg(spec["agg"])

if spec.get("sort") == "desc":

data = data.sort_values(ys[0], ascending=False)

elif spec.get("sort") == "asc":

data = data.sort_values(ys[0], ascending=True)

if spec.get("top"):

data = data.head(int(spec["top"]))

return data

def draw(spec: dict, data: pd.DataFrame, out: str) -> None:

kind = spec.get("chart", "bar")

x, ys = spec["x"], list(spec["y"])

fig, ax = plt.subplots(figsize=(10, 5))

if kind == "bar":

data.plot.bar(x=x, y=ys, ax=ax)

elif kind == "line":

data.plot.line(x=x, y=ys, ax=ax, marker="o")

elif kind == "scatter":

data.plot.scatter(x=x, y=ys[0], ax=ax)

elif kind == "pie":

ax.pie(data[ys[0]], labels=data[x].astype(str), autopct="%1.1f%%",

startangle=90)

else:

raise ValueError(f"不支持的图表类型: {kind}")

ax.set_title(spec.get("title", ""))

if kind != "pie":

ax.set_xlabel(x)

ax.tick_params(axis="x", rotation=45)

ax.grid(axis="y", alpha=0.3)

fig.tight_layout()

fig.savefig(out, dpi=150)

plt.close(fig)

print("已输出:", out)

if __name__ == "__main__":

spec_path, excel_path, sheet, out = sys.argv[1:5]

with open(spec_path, encoding="utf-8") as f:

spec = json.load(f)

df = load(excel_path, sheet)

validate(spec, df)

draw(spec, prepare(spec, df), out)

```

运行:

```bash

python render.py spec/bar.json data/sales.xlsx Sheet1 out/bar.png

```

第六步:让大模型产出配置

这一步是"AI"真正发挥作用的地方。把下面这段提示词连同表结构一起发出去。

```text

你是数据可视化助手。根据表结构和需求,输出一个 JSON 对象。

只输出 JSON,不要解释,不要 markdown 代码块。

字段说明:

chart: bar | line | pie | scatter

x: 横轴列名,必须来自给定列名

y: 数值列名数组,必须来自给定列名

agg: sum | mean | max | min | null

sort: desc | asc | null

top: 整数或 null

title: 中文标题

列名:[把 inspect.py 打印出的列名粘到这里]

每列含义:[一句话说明,可省略]

数据样例:

[粘前 5 行]

需求:看各月份的销售额,从高到低排,只看前 8 个月。

```

把返回的 JSON 存成文件,跑 render.py。如果报"表里找不到这些列",说明模型编了列名,把错误信息连同实际列名一起发回去让它重写,通常一次就能改对。

对同一张表,你可以为不同需求各存一份配置:spec/monthly.jsonspec/by_region.jsonspec/trend.json,之后改需求只改 JSON,不动代码。

第七步:换成交互式 HTML

要给同事看、想鼠标悬停显示数值,把 draw 换成 plotly 版本即可。

```python

render_html.py

import json

import sys

import pandas as pd

import plotly.express as px

from clean import load

from render import prepare, validate

spec_path, excel_path, sheet, out = sys.argv[1:5]

spec = json.load(open(spec_path, encoding="utf-8"))

df = load(excel_path, sheet)

validate(spec, df)

data = prepare(spec, df)

kind = spec.get("chart", "bar")

fn = {"bar": px.bar, "line": px.line, "scatter": px.scatter, "pie": px.pie}[kind]

if kind == "pie":

fig = fn(data, names=spec["x"], values=spec["y"][0], title=spec.get("title", ""))

else:

fig = fn(data, x=spec["x"], y=spec["y"], title=spec.get("title", ""))

include_plotlyjs=True 会把 JS 内嵌,离线也能打开,文件会大一些

fig.write_html(out, include_plotlyjs=True)

print("已输出:", out)

```

第八步:批量处理多个 sheet

```python

batch.py

import json

import pandas as pd

from clean import load

from render import validate, prepare, draw

excel_path = "data/sales.xlsx"

specs = {

"Sheet1": "spec/monthly.json",

"Sheet2": "spec/by_region.json",

}

for sheet, spec_path in specs.items():

spec = json.load(open(spec_path, encoding="utf-8"))

df = load(excel_path, sheet)

validate(spec, df)

draw(spec, prepare(spec, df), f"out/{sheet}.png")

```

常见坑与排错

中文变成方框。 系统缺中文字体。Linux 上装 fonts-noto-cjk(包名以发行版仓库为准);macOS 用 PingFang SC;Windows 用 Microsoft YaHei。装完删掉 matplotlib 字体缓存再跑,缓存目录用 matplotlib.get_cachedir() 查。

数字列被读成文本。 典型是单元格里有千分位逗号、货币符号、全角空格。用第三步的 to_number 处理。注意 pd.to_numeric(..., errors="coerce") 会把转不了的值变成 NaN,转换后统计一下 NaN 数量,别有数据被悄悄丢掉。

日期排序不对。 月份列如果是"1月、2月…10月"这种中文,按字符串排会乱。要么转成 datetime,要么加一列数字月份做排序键,出图时用数字列当 x、显示标签另设。

饼图扇区太多。 超过 7~8 类基本看不清。做法是把小类合并成"其他",或者干脆换成横向柱状图,可读性通常更好。

双轴单位不一致。 一个"销售额(元)"一个"转化率(%)"放在同一根 Y 轴上,数值差几个数量级,图形会被压平。要么拆成两张图,要么在配置里支持次坐标轴,要么先各自归一化。

列名前后有空格或换行。 读表后统一 df.columns = [str(c).strip() for c in df.columns],否则模型给的"销售额"和表里的"销售额 "匹配不上。

合并单元格。 读进 pandas 后只有首行有值,其余是 NaN。用 ffill() 向下填充,但只对分类列做,数值列别乱填。

.xls 老格式打不开。 openpyxl 只处理 .xlsx。老格式需要额外依赖,且支持范围有限,建议先用 Excel 另存为 .xlsx。具体支持情况以各库官方文档为准。

模型给的配置跑不通。validate 抛出的错误原文发给模型,再附上真实列名列表,让它重出配置。这个回路比让它"再想想"有效得多。

下一步建议

配置格式跑通之后,有几个方向可以继续加:

  • 定时出图:用系统定时任务(cron 或 Windows 任务计划程序)每天跑一次 batch.py,把图推到共享目录或聊天群机器人,周报里的图自动就有了。
  • 做成面板:用 Streamlit 包一层,上传 Excel、选图表类型、点按钮出图。适合给不写代码的同事用。
  • 配置进版本库:把 spec/*.json 提交到 Git,改配色、改排序都有记录,出了问题能回滚。
  • 接文件读取能力:部分助手支持直接读取上传的表格文件,可以先让它出配置、再本地渲染,省掉手工粘贴表结构的步骤。
  • 加一层异常提示:在 prepare 里判断某列缺失比例、数值波动是否超出历史区间,出图时顺手在标题旁标注"本期数据缺失 12%",比一张漂亮但失真的图更有用。

整套流程的核心思路只有一句:把模型的输出限制在一份小小的、可以被程序校验的结构化配置里。模型负责理解你的意图,脚本负责把事做对。

AI 生成本文由 AI 基于公开信息自动生成,仅供参考。