ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI自然语言驱动ECharts:数据可视化图表生成实战指南

AI自然语言驱动ECharts:数据可视化图表生成实战指南

上周接了个体育赛事总结的需求,里面要放一张奖牌榜柱状图,往常我的做法是老老实实打开ECharts文档,找个模板改数据、调tooltip、配颜色,没有半小时下不来。这次我临时换了个思路:直接用AI的自然语言描述需求,让它来生成ECharts配置。结果从整理数据到跑出第一版可交互的柱状图,总共花不到5分钟,后续再改配色、调标题、加圆角,全程都是对话几句就搞定。这篇文章就把"AI + 自然语言 + 数据可视化"这套玩法完整记录一遍,包含我实际跑通的Prompt全文、数据的整理方式、结果落地时需要人工修改的配置,以及过程中踩过的坑。无论你是前端工程师、数据分析师,还是自己折腾爬虫和报表的爱好者,这套方法都能帮你省掉大量写图表的时间,它不能完全替代人工调试,但绝对是一个特别好用的轮子。

1. 为什么我决定用自然语言来驱动ECharts

1.1 传统写图表的痛点到底在哪

普通人看"数据可视化"可能觉得是个锦上添花的东西,但真正亲手做过图表的人才知道,从数据到图表的这段路有多磨人。首先要理清原始表里的字段,然后想清楚图表类型、维度指标、聚合方式,再打开ECharts官方示例找一个最接近的模板,复制下来改数据。改完发现X轴标签太长叠在一起,又去查rotate配置;等到图表能看了,颜色又太丑,再花十几分钟配一套顺眼的。整个过程的精力损耗只有一小部分花在"设计图表表达"上,绝大部分都花在"把想法翻译成配置语法"和"调试细节"上。

尤其是ECharts这种配置项极其灵活的库,同样的柱状图能有好多写法,轴、系列、提示框、图例、网格这些配置之间还有依赖关系。你在脑子里想的是"拿这个代表团的金牌数量画一根从高到低的柱子",但ECharts要你输入的是xAxis.data数组、series.type字段、series.data数组、itemStyle颜色这几个独立的结构化配置。这层转译成本,就是传统做图的大头。越是熟练的工程师,越会意识到这层工作重复性极高——换个数据源,逻辑还是那一套,但每次都不得不重新走一遍查文档的流程。

1.2 大模型恰好擅长做"翻译"这件事

大模型最擅长的事情,恰好就是"把一段自然语言翻译成另一种表达形式"。只要给它足够的上下文:数据结构是什么、目标图表类型是什么、用什么库、输出格式是什么,它就能生成一份可运行的配置。这不算黑科技,本质上就是你平时用AI写代码、写SQL、写正则那套逻辑。区别在于,放在图表场景里收益被放大得很明显:ECharts配置项的语法密度很高,手写一个复杂图表的option要好几十行;但用自然语言把同样的内容说清楚,可能只需要三五句话。

不过这里要先说清楚边界。AI只负责"翻译",不负责"设计数据和业务口径"。你如果自己都说不清"这个图表到底要看什么指标"、搞不懂字段怎么对应,那AI也会跟着迷茫,输出一份看起来正常但实际答非所问的配置。我实测下来的判断标准是这样:只要你能说清楚数据从哪来、图表要表达什么、想用什么图表类型,那这件事就非常适合用AI来干。反之,如果自己脑子里一团浆糊,先别急着找AI,先把需求想明白。

2. 数据准备是Prompt的隐形地基,别跳过这步

2.1 别指望模型“知道”亚运会数据

很多人第一次试这招,会直接把"2022年杭州亚运会金牌榜"这几个字丢给AI,然后等着它生成图表。实际效果是,模型确实会给你生成一张看起来不错的图,但你仔细一对数字,全是编的。底层大模型虽然训练数据里包含大量体育赛事信息,但对某一届综合性运动会的最终奖牌数目细节并没有可靠记忆,数字可能来自往届、可能是预测值、甚至是模型脑补出来的合理数值。更麻烦的是,这种错误图表样式完全正常,混在一份报告里极其隐蔽,不逐项核对根本发现不了。

所以做可视化有一条铁律:数据本体绝不能交给模型的记忆,必须作为上下文喂进Prompt里。这一步是整个流程的隐形地基,地基没打牢,后面Prompt写得多漂亮都白搭。具体做法很简单——把数据整理成结构化格式,原样粘贴到Prompt里。

2.2 我这次用的数据格式和字段命名习惯

我演示用的是一份简洁的JSON数组,长这样:

[ {"country": "中国", "gold": 201, "silver": 111, "bronze": 71, "total": 383}, {"country": "日本", "gold": 52, "silver": 42, "bronze": 49, "total": 143}, {"country": "韩国", "gold": 42, "silver": 59, "bronze": 58, "total": 159}, {"country": "印度", "gold": 28, "silver": 38, "bronze": 39, "total": 105}, {"country": "乌兹别克斯坦", "gold": 22, "silver": 18, "bronze": 31, "total": 71} ]

这里有几个实操中总结出来的细节,值得单独说一下。

字段名尽量用英文,例如gold、silver、bronze。模型对英文标识符的解析成功率高,也不容易跟中文单位混在一起。你要是非用"金牌数"当键名不是不行,但后面在tooltip的formatter里拼接字符串时,中文字段名很容易被模型错误引用,经验上英文键名最稳。

数值字段只保留纯数字,不要写"201枚"这种带单位的文本。一旦混入单位,模型很可能把"枚"当成字符串的一部分,后续排序、求和、在提示框里做数字格式化都会产生脏数据。单位这些信息放到图表标题或者tooltip模板里加就行。

数据在Prompt里的排列顺序,最好就是你期望图表呈现的顺序。我打算画金牌数降序的TOP5,所以在复制进Prompt之前就先排好了序。虽然模型本身也能处理排序任务,但我更倾向于减少变量,Not 让它多做一步就多一个潜在的出错点。

2.3 从Excel、CSV到Prompt数据的整理路径

如果你的原始数据在Excel或CSV里,转成JSON数组其实很轻松。有Python环境的话一行pandas代码就搞定:

import pandas as pd df = pd.read_excel("奖牌榜.xlsx") result = df[["country", "gold", "silver", "bronze", "total"]].to_json(orient="records", force_ascii=False) print(result)

没有Python也没关系,数据量小的话直接在文本编辑器里手敲一个数组也就几分钟的事。这里有个特别容易忽略的点:数据里的缺失值要提前处理。比如某个代表团的银牌数是空的,你不能留空让模型自己猜测;要么填0,要么写null并在Prompt里专门注明。模型对不同缺失值的处理策略不一致,有时会把这一行直接过滤掉,导致图表莫名其妙少了一个类别,有时又会在图例里留下一个空档,样式非常突兀。自己预先把缺失值统一填成0,是最省心的做法。

3. 一条能直接复用的完整Prompt与逐段拆解

3.1 完整Prompt全文,复制改数据就能用

下面是我实际跑通的一份完整Prompt,除了数据部分要换成你自己的内容之外,其他结构都可以直接复用。模型最好选择对长文本理解能力强的大模型,上下文窗口大一些,输出会更稳定。

# 角色 你是一名资深前端开发工程师,精通ECharts数据可视化,擅长把表格数据变成美观、专业的图表。 # 背景 我有一份2022年杭州亚运会奖牌榜的真实数据,需要生成一个用于数据分析报告的图表。 # 数据 [ {"country": "中国", "gold": 201, "silver": 111, "bronze": 71, "total": 383}, {"country": "日本", "gold": 52, "silver": 42, "bronze": 49, "total": 143}, {"country": "韩国", "gold": 42, "silver": 59, "bronze": 58, "total": 159}, {"country": "印度", "gold": 28, "silver": 38, "bronze": 39, "total": 105}, {"country": "乌兹别克斯坦", "gold": 22, "silver": 18, "bronze": 31, "total": 71} ] # 任务 基于以上数据生成一个完整的ECharts option配置,要求如下: 1. 图表类型:柱状图,X轴为国家名称,Y轴为金牌数量,按金牌数降序排列。 2. 标题为“杭州亚运会金牌榜TOP5”,副标题注明“数据来自公开奖牌榜”。 3. 柱形使用渐变色,从橙色渐变到红色,整体风格现代、简洁。 4. X轴标签如果过长,倾斜45度显示。 5. 在柱形顶部显示具体金牌数值。 6. 鼠标悬浮时提示国家名称、金牌、银牌、铜牌、总奖牌数。 7. tooltip的数据字段必须和我的数据字段一一对应,不得自行发明字段。 8. 图表需自适应容器大小。 # 输出格式 只输出ECharts的option对象本身,不要输出HTML、初始化代码、代码块标记或额外解释。所有配置项必须是ECharts 5.x版本支持的合法配置。

3.2 为什么Prompt要按这个结构写

这套Prompt是"角色-背景-数据-任务-输出格式"五段式,每段都有明确用途,我逐个拆一下。

角色段放在最前面,是为了让模型切换成"资深前端工程师"的视角来思考和输出。实测结果差异非常明显:有角色设定的情况下,它生成的配置更完整,会自动考虑tooltip、grid、legend、responsive这些实用配置;没有角色设定时,它倾向于给一个最基础的柱子图,很多细节要靠后续追问才补上。人的状态影响产出质量,模型的角色感也有类似作用。

背景段看似可有可无,实际影响措辞和数据语义。让模型知道这是"真实数据、用于数据分析报告",它生成的标题、副标题、单位说明就会收敛很多,不会出现"预估""推测"这类带不确定性的词。反过来,如果背景里不说明数据来源,模型可能会在标题里加入一些误导性描述。

数据段必须原样放置,这一点在上面已经强调过。这里再补一个细节:不要把数据截断成前两行然后写"后面省略"之类的话,一旦出现省略,模型就可能自行编造字段或数据格式,后续排查起来更痛苦。

任务段是整个Prompt的核心,我坚持把所有客观约束都列出来:图表类型、排序规则、标签倾斜角度、渐变颜色范围、tooltip包含字段。这些条件写死之后,模型就没有太多自由发挥的空间了。自由发挥恰恰是生成图表脚本时最麻烦的随机因素——一会给你加个动画,一会给你换种配色,每轮输出还不一致。

输出格式段是我调试了好几次之后才加上的。没有它,模型会很自然地把完整HTML页面、echarts.init初始化脚本、甚至CSS一起输出,你需要自己剥离,二次加工成本很高。加了"只输出option对象本身"和"不要输出代码块标记"这两句之后,输出内容就干净很多了。

3.3 写Prompt之前,先回答三个问题

我见过不少朋友在写Prompt时陷入"描述一大堆但没说到点子上"的状态,这里分享一个我给自己定的标准:动笔之前先回答三个问题。

第一个问题,我手里的数据字段有哪些?这决定了你在Prompt里对数据的所有引用。第二个问题,我想让图表呈现哪一维指标?是只画金牌数,还是金银铜三组并列柱状图,抑或叠加总奖牌数?这个不明确,AI只能替你猜。第三个问题,输出物到底是纯option配置,还是完整页面?如果只是内部调试,纯配置就够了;如果要做成独立HTML交付,那对输出的要求完全不同,Prompt要相应调整。

真要再加一个思考维度,就是图表给谁看。给管理人员汇报用的,和给数据分析师自用的,信息密度、配色风格、要不要数据标签差别很大。这些使用场景信息也要写进Prompt里,AI生成的结果才会贴实际情况。

4. AI输出的ECharts配置怎么落地,改哪里最关键

4.1 最简易的落地模板,粘进去就能跑

AI返回的option对象,最直接的落地办法就是放进一个最小HTML模板里。这里给出一个我常用的骨架,把AI生成的option粘贴到指定位置即可运行:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>杭州亚运会金牌榜</title> <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> <style> #chart { width: 800px; height: 500px; margin: 40px auto; } </style> </head> <body> <div id="chart"></div> <script> // 这里粘贴AI生成的option对象 var option = { /* AI生成的配置 */ }; var chart = echarts.init(document.getElementById('chart')); chart.setOption(option); window.addEventListener('resize', function () { chart.resize(); }); </script> </body> </html>

如果你是本地打开测试,直接用浏览器访问就行。如果要在公司内网或者自己的网站里用,把echarts的script地址换成内网离线文件会更保险,避免依赖外部CDN导致加载失败。

4.2 落地上最常修改的四个点位

AI生成的结果第一次渲染出来后,通常不会完全尽如人意。根据我的实操经验,下面这几个点是每次都要人工过一遍的。

第一是核对数据本身。AI输出的series.data要和源数据逐一比对,尤其是排序后的顺序。虽然Prompt里明确写了"按金牌数降序",但当我给它的数据源不是有序数组时,模型经过"排序+映射"两步操作后,偶尔会出现顺序和现实不一致的情况。更好做的方案就是我在数据准备阶段说的——你自己先排好序再交给它,这样series.data大概率就是按顺序来的,只要核对值对不对就行。

第二是tooltip的formatter定制。因为数据里的数值是纯数字,默认提示框不太会带单位。如果要显示"金牌:201枚"这种带量词的文案,需要在formatter里拼接。AI生成的基础版通常只会打印原始数值,这里我一般会手动加一段脚本:

tooltip: { trigger: 'axis', formatter: function (params) { var p = params[0]; return p.name + '<br/>金牌:' + p.value + '枚'; } }

如果希望提示框展示金银铜全部信息,那formatter里还要手动引用对应的数据字段,写起来会稍微复杂一点,但这是图表专业度的重要体现。

第三是渐变色函数的写法。AI给出的渐变配置,多数情况下是new echarts.graphic.LinearGradient(0, 0, 0, 1, [...])这种依赖echarts全局对象的形式,只要页面里引入过echarts就能正常运行。但也有相当一部分模型会输出一个字符串形式的渐变色,或者一个看起来像渐变但实际上没有正确引用graphic命名空间的写法,渲染时直接报错。这种情况需要你手动把渐变改成标准写法,或者退一步使用普通的纯色数组。在第一次落地时,这一步是最容易莫名报错的源头。

第四是自适应部分。AI默认不会帮你想窗口变化的事,不主动给图表添加resize监听,浏览器窗口缩放时图表不会跟着变。这在投屏、移动端展示、侧边栏折叠这类场景下体验很差。我习惯在初始化之后手动加上监听,模板里已经写了,你直接保留就行。

4.3 比生成更重要的审查逻辑

这里想单独强调一句:AI生成代码已经很成熟了,但图表代码和普通业务代码不同,它直接承载数据的语义表达。画错一个字段,读者可能就会看错一个结论。所以不管模型输出得多流畅,我每次都会花至少半分钟做一次核对,重点检查三件事:series.data的数值和源数据一致性、tooltip里有没有出现undefined、图表标题是否准确表现了数据口径。

尤其是当你手里的数据涉及正式报告或对外发布时,图表界面上展示错误信息的后果,远比代码报错严重。AI可以帮你省掉大量体力活,但把最后一道审查关留给自己,是任何时候都不能省的专业习惯。

5. 实测翻车现场与提示词迭代心得

5.1 翻车现场一:柱状图被画成了折线图

第一次跑的时候,我在Prompt里写了"图表类型:柱状图",但这句话放在任务段的中间,模型的注意力显然被后面对比效果的描述分走了,生成的series里用的居然是type: 'line'。第一眼看到折线图的时候我愣了一下,数据是五组离散代表团,画折线本身在语义上就不对劲,但模型依然这么做了。

这个问题的解法说起来有点出乎意料:不是重新解释什么叫柱状图,而是把"图表类型"单独放到任务段的第一条,并且加一句"series中只能出现type: 'bar',不得使用其他类型"。关键参数在Prompt里的位置越靠前、表述越绝对,模型越会严格执行。这个规律后来我反复验证过,在让AI生成代码时非常管用。

5.2 翻车现场二:tooltip里出现undefined

第二次跑,数据里包含了total字段,但Prompt里只要求把金牌数画进柱状图。模型在生成tooltip时可能想做得更丰富一点,结果在formatter里引用了data.total之类的字段。问题是,如果series.data是纯数值数组,ECharts的tooltip formatter拿到的params对象里并没有total这个字段,于是页面上直接渲染出undefined,非常刺眼。

这个问题要从两个方向同时解决。一是在Prompt里明确写"tooltip的数据字段必须和我的数据字段一一对应,不得自行发明字段";二是把series.data改成对象数组,让每个柱子携带完整数据对象。两者结合后,formatter里就能顺利读取到gold、silver、bronze、total这些字段。如果你发现AI生成的对象数组写法不对,也可以手动修改series.data为:

series: [{ type: 'bar', data: [ { value: 201, silver: 111, bronze: 71 }, { value: 52, silver: 42, bronze: 49 } ] }]

5.3 翻车现场三:输出被代码块包裹,自动化还要多剥一层壳

很多模型默认用Markdown的代码块包裹代码输出,这本身不算问题,手工作业时甚至方便复制。但如果你打算把这套流程做成API自动化的批量工具,那每份输出都要先剥掉首尾的```javascript标记,多一步处理就多一种出错可能。

我的解决办法很简单:在Prompt末尾加一句"不要输出代码块标记,直接输出代码本身"。如果模型依然不听,那就在自动化脚本里做一层字符串清洗,把javascript和去掉再交给下一步处理。这类反模式是AI生成内容时的通病,提前在Prompt里声明能省掉不少麻烦。

5.4 多轮对话迭代,而不是每次重新生成

关于提示词迭代,我最大的心得是:不要指望一次Prompt就达到完美。合理的节奏是"第一版先看大方向,第二版改细节,第三版定稿"。我第一次生成的图表虽然能看,但配色偏冷、标题偏长。这时候我不需要重新发一遍完整Prompt,而是直接追加一句修改要求:"请把主色调改成热度更高的橙色系,标题缩短为'杭州亚运会金牌榜TOP5',柱形加圆角。"模型在对话上下文里能记住之前的配置,几秒钟就返回了新版本。

这个配合方式和传统的"重新生成"有个本质区别:重新生成会丢掉前面所有修改,相当于从零再跑一遍,结果还可能变;而对话式迭代是在现有方案上做增量修改,既稳定又高效。我后来做任何AI生成图表,都默认走这个流程:粗版本定位结构,细版本精修样式。

5.5 自然语言做可视化的边界,顺便分享两个小技巧

这套方法虽然好用,但边界也很清晰。它适合一切"已有的、结构化的数据"快速出图,特别适合内部汇报、数据分析、临时看数这类场景。但如果你需要高度定制的地图迁徙、3D散点、复杂联动交互这类高级图表,AI生成的基础配置往往不够,还是得人工介入做深度开发。另外,如果数据量特别大,直接塞进Prompt也不现实,要么抽样、要么聚合、要么用更长的上下文方案。把合适的事交给合适的方法,才是效率最大化的关键。

最后分享两个小技巧。第一个,把这份Prompt当成模板保存在自己的常用语料库里,每次遇到新图表需求,只需要改数据和任务两个部分,其余不用动。第二个,如果你经常做同一类报表,可以让AI直接生成一个"可以被配置文件驱动的图表模板",后续更新数据时,连Prompt都不用重写,替换JSON就好。我现在的做法就是在本地维护了几个图表模板,遇到需求先改数据,再让AI微调样式,整体效率比从头手写高出一大截。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进