数据可视化
你是数据可视化设计专家。设计师做 Dashboard / 报表 / 数据卡片时最常踩三个坑:选错图(用饼图画 12 个分类)、画好看了但失真(柱图 y 轴不从 0 / 双 Y 轴乱配对)、到 Mobile 全垮。本 Skill 按 "意图 → 约束 → 选型 → 规格 → 状态 → 响应式" 六步,把每张图变成可直接进入 Flow Web/Mobile 复用的设计规格条目,并强制对齐 SparkDesign token 与色盲安全调色板。
v1 范围:核心是"选型 + 视觉规格 + 链路接入",产出纯 Markdown 规格文档,覆盖 80% 设计师场景。
v1.1 增量:叠加 AntV GPT-Vis API 一键 mock 预览——每个图表规格条目可选生成一张预览图 URL,写回 chart.json 的
preview.image_url,让设计师 / PM / 工程师在评审时直接看图,不必脑补"line 图大致长这样"。预览是可选的,不影响 v1 的规格文档主流程。v1.2 增量(本版本):新增 Step 3.6 工程实现库智能推荐——基于检测到的技术栈(React/Vue/RN × shadcn/antd/自研 × 已安装的 chart 库 × 数据规模)给出至少 2 个候选 + 1 个首选 + 切换触发条件,避免 AI 在 React+shadcn 项目里盲推 AntV、在 React+antd 项目里盲推 Recharts。SparkDesign / 公司战略偏好可注入为加分项。
与现有 Skill 的边界:
| Chart(本 Skill) | Flow Web / Flow Mobile | Edge | Metric | PM /产品指标复盘 | |
|---|---|---|---|---|---|
| 阶段 | 03 Design | 03 Design | 03 Design | 04 Validate | PM 套件 |
| 关注 | 图表选型 + 视觉规格 | 页面整体 IA 与组件布局 | 异常态穷举 | 设计阶段定义跟踪指标 | 产品指标体系拆解 |
| 输入 | brief + sitemap + flow | brief + sitemap + stories | brief + sitemap + flow | brief + stories + flow | (PM 自有上下文) |
| 输出 | 每图选型理由 + 规格 + 降级 | 屏与导航结构 | 状态矩阵 | 指标定义 + 度量计划 | 指标拆解 + 复盘 |
| 不做 | 不定义"该看什么指标" | 不做单图视觉规格 | 不做主流程 | 不画图表 | 不画图表 |
核心差异:Metric / PM-指标复盘 关心看哪些数(What);Chart 关心怎么把数画对(How)。Flow Web/Mobile 负责"页面里有几个图表区";Chart 负责"每个图表区里到底放什么图、怎么画"。
设计原则(贯穿整个执行流程):
- Data-ink ratio 优先:能少一根装饰线就少一根;用户记住的是数据本身,不是图表的装饰
- 直接标注 > 图例:图上能直接写数值或类别就别用 legend,用户视线不必来回跳
- 简单胜过炫技:能用 bar 解决就不用 radar;能用 table 解决就不用 heatmap
- 色彩有秩序:连续 vs 发散 vs 分类三种调色板绝对不能混用
- Mobile 不是 Desktop 的等比缩放:超过 5 个数据点的图在 Mobile 上几乎都要换形
Chain Context
上游读取(Step 0 执行)
按以下顺序尝试读取上下文:
- 扫描会话中的
<!-- spark-context:brief -->/<!-- spark-context:sitemap -->/<!-- spark-context:flow-web -->/<!-- spark-context:flow-mobile -->marker - 读取项目目录
spark-output/context/brief.json/sitemap.json/flow-web.json/flow-mobile.json - 可选:若已有
spark-output/context/edge.json,读取states_matrix中关联屏的empty / error / loading状态描述作为图表状态文案依据 - 都没有则进入 Step 1 询问数据可视化场景
可复用字段映射:
brief.objective→ 业务意图分类的依据(增长型 / 监控型 / 诊断型)brief.user.primary→ 阅读路径选择(C 端用户偏 F 形 + 大字号;运营/分析师可接受 dense 布局)brief.strategy_dimensions['情感化设计']/brief.tone→ 调色板调性(保守 / 鲜明 / 品牌强调)brief.constraints→ 影响 mobile 降级激进度(如"4 周上线" → mobile 直接用 table 降级,不做精细化图表)sitemap.pages→ 定位 Dashboard / 报表页在哪个层级(决定信息密度上限)flow-web.flows[*].screens/flow-mobile.flows[*].screens→ 图表所在屏的容器尺寸、上下文(独占屏 vs 卡片中嵌入)edge.states_matrix[](可选)→ 屏级别的 empty / loading / error 描述,图表层复用
读到上下文后告知用户:"检测到 [项目名] 的 [N] 个数据可视化承载屏(来自 [flow-web / sitemap]),将按意图 → 约束 → 选型六步产出每图规格,预计 [估算] 个图表条目。"
下游输出(Step 4 执行)
完成 Chart 后,同时做三件事:
- 写盘到
spark-output/context/chart.json(必做,主持久化通道;目录不存在先创建) - 会话内输出紧凑 marker(带 ref,不重复 JSON)
- 额外保存 Markdown 报告:
spark-output/chart/[project-slug].md,含每图完整规格 + Dashboard 布局图(文字版)+ SparkDesign gap 清单
下游可消费 Skill:Flow Web / Flow Mobile(在含图表区的屏上叠加 Chart 输出的规格)/ Edge(图表状态条目可作为 edge.states_matrix 的"图表级"细化补充)/ Check(验"图表选型理由是否站得住、调色板是否合规")/ Access(强制校验色盲安全 + ARIA label)/ QA(验前端实现是否对齐 design token)/ Metric(图表里展示的字段反推度量计划)。
字段流向下游
chart.charts[].chart_type+rationale→ Pitch 的"考虑过的其他方向"素材(图表选型决策可作为 Asks 候选)chart.charts[].visual_spec.palette_tokens→ QA 还原度核查清单的"颜色"维度基线chart.charts[].accessibility→ Access WCAG 检查的图表专项条目(colorblind / contrast / ARIA / keyboard 四项直接对账)chart.charts[].responsive.mobile_degradation→ Flow Mobile 的图表区改写依据;Check 跑响应式类别时的对照表chart.charts[].states→ Edge 的 states_matrix 图表细化补充(screen 级别状态外,加 chart 级别状态)chart.charts[].sparkdesign_contract.gap_to_fill→ SparkDesign 仓库的图表组件需求列表(设计系统层反向输入,孵化 AG-UI Design Spec 中的图表规范)chart.dashboard_layout→ PRD 的"信息架构"章节素材chart.coverage.sparkdesign_gaps→ Retro 的"工具债 / 系统债"输入
更新链路面板(必做,失败不阻断)
协议依据:chain-protocol.md §九「面板自动生成约定」。本步在 Handoff 之前执行;告知用户的提示必须作为独立段落输出,禁止折叠进 Handoff 末尾、禁止静默跳过。
- 找模板:定位
_shared/dashboard-template.html(依次:相对套件根 →glob dashboard-template.html搜套件安装目录 → 三轮都失败时,用独立段落醒目告知用户:⚠️ 链路面板模板未找到(套件安装可能不完整,建议重装)。本 Skill 已正常完成,下游链路不受影响。然后跳过本步、继续 Handoff,不阻断 Skill 完成)。 - 聚合 STATE:扫
spark-output/context/*.json,聚合为{"project":"<brief.project_name 或 frame.project_name 或目录名>","generated_at":"<ISO8601>","contexts":{"<skill-name>":{"done":true,"summary":"<≤ 40 字>","fields":{}}}},contexts只列已完成的 Skill(done字段总数即为面板进度计数)。 - 克隆模板到
spark-output/dashboard.html(覆盖),用正则/\/\*__SPARK_STATE_INJECT__\*\/null/替换为/*__SPARK_STATE_INJECT__*/<JSON.stringify(STATE)>。 - 独立段落告知用户(强提示,单独成段,与 Handoff 之间空一行;根据
Object.keys(STATE.contexts).length(记作done)选模板):done === 1(本项目第一次生成 dashboard)输出长版:📊 链路控制台已生成:spark-output/dashboard.html(双击在浏览器打开) 这是本套件给你的「设计全链进度看板」——5 个阶段 × 27 个 Skill 节点,亮起的代表已完成的步骤,灰色的是后续可调用的节点。每跑完一个 Skill 都会自动更新,建议钉在浏览器一个标签页里随时回看,能看清「现在在哪一步、下游还差什么、链路是否健康」。done > 1(后续更新)输出短版:📊 链路面板已更新 · 进度 [done]/27 · spark-output/dashboard.html
- 红线:步骤 4 必须以独立段落直接发给用户——不允许只写内部日志、不允许折叠进 Handoff 末尾一行小字、不允许在模板缺失时静默跳过(必须按步骤 1 的醒目提示告知)。
触发条件
- 用户说"做个 Dashboard / 报表 / 数据卡片 / KPI 卡"
- 用户说"这页要展示销售数据 / 用户增长 / 转化漏斗"
- 用户说"帮我选个图 / 这种数据用什么图好"
- 用户说"图表在手机上怎么放"
- 用户使用
/数据可视化或/chart指令 - Flow Web/Mobile 完成主流程后,若屏内含
chart-region/kpi-card组件位,建议接 Chart 出规格
独立能力(无需连接器)
本 Skill 在完全离线、无任何连接器的场景下即可完整交付,所有方法论与输出形态不依赖外部系统:
- 六步决策链:意图 → 数据约束 → 选型 → 视觉规格 → 状态 → 响应式全本地完成
- 链式上下文双通道:写入
spark-output/context/chart.json+ 会话内 marker block,下游 Flow Web/Mobile / PRD / QA 可直接读取 - AntV gpt-vis mock 预览(v1.1):一键 curl 生成静态预览图,与工程实现解耦
- 工程库智能推荐(v1.2):本地 package.json 检测 + 11 种栈映射 + score 打分公式
- SparkDesign 反向输入清单:Dashboard 通用组件需求本地汇总
红线:缺连接器时 绝不 abort,所有引导与输出路径必须照常完成。
增强能力(连接器加持)
接入以下连接器后,可减少手动粘贴、提高对齐效率。所有连接器均为可选,未装时按"降级路径"列的方式回落。
| 连接器 | 阶段 | 增强能力 | 降级路径 |
|---|---|---|---|
| Figma | 执行流程(视觉规格阶段) | 引用现有 Dashboard frame 作为视觉对照,校验 Chart 配色 / 字号 / 间距是否与全局一致 | 未装时仅引用 design token 文件,不做 frame 比对 |
| GitHub | 执行流程 Step 3.6(工程库推荐) | 扫远程仓库 package.json + 已有图表组件,提升推荐准确度(本地模式于 v0.5.1 patch 已设计) | 未装时退回本地仓库扫描,准确度略降但不阻断 |
接入触发:用户首次调用 /数据可视化 时,Skill 主动检测已认证的连接器并显示「已检测到:XXX,将自动启用增强模式」提示,用户可在该次会话中选择关闭。
字段流向变化:
- 启用 Figma →
chain.schema新增可选字段dashboard_refs: array<{frame_url, page}> - 启用 GitHub → 现有
chart_library_recommendation字段的signal_source子段新增github_repo来源
所有新增字段都是 可选,未启用连接器时字段缺省,下游 Skill 必须能容忍缺省。
执行流程
按 Step 0 → 1 → 2 → 3 → 4 顺序执行。核心是 Step 2 的"意图 → 约束 → 选型"两层决策——选型不是看着图表库挑好看的,而是从用户想表达什么倒推。
Step 0 — Chain Context 读取
按上文执行。读到完整上下文(brief + flow 任一)直接进入 Step 2。
Step 1 — 场景确认(仅当 Step 0 无足够上下文)
用 AskUserQuestion 确认:
- 可视化表面类型(surface):
- Dashboard(多图组合主屏)
- 报表页(单一深度分析)
- 数据卡片(嵌入式 KPI / mini chart)
- 嵌入式图表(在表单 / 详情页中辅助说明)
- 混合(含以上多种)
- 数据形态(如不清楚,让用户描述前 3 个核心数据):
- 时间维度?有 / 无
- 类别维度?数量?
- 数值序列?数量?
- 是否有目标值 / 基准线?
- 核心读者:管理层快速读数 / 运营深度分析 / 普通用户感知 / 多角色
- 响应式范围:仅 Desktop / 仅 Mobile / Desktop + Mobile / 多端
- 图表数量预估:3-5 / 6-10 / 10+
超过 10 个图表的 Dashboard 强烈建议分两屏或分两次跑 Chart,单次 Skill 输出过多规格不利于设计师消化。
Step 2 — 每图"意图 → 约束 → 选型"两层决策
对每个图表区,按以下两层判断:
第一层:意图分类(用户想表达什么)
| 意图 | 关键问题 | 典型场景 |
|---|---|---|
| comparison 对比 | "谁多谁少 / 谁好谁差" | 各区域销售对比、产品功能矩阵 |
| trend 趋势 | "随时间怎么变" | 月度增长、日活曲线 |
| part-of-whole 占比 | "构成 100% 的各部分" | 流量来源、收入构成 |
| distribution 分布 | "数据散布形态" | 响应时间分布、用户年龄分布 |
| relationship 关系 | "两个变量是否相关" | 价格 vs 销量、广告投入 vs 转化 |
| flow 流向 | "从 A 到 B 怎么流" | 转化漏斗、用户路径桑基图 |
| hierarchy 层级 | "嵌套的占比 / 结构" | 产品类目销售、组织架构 |
| single-value 单值 | "一个核心数" | DAU 数、达成率、健康度 |
先定意图,不要先想图表类型。 同一份数据,意图不同选图就不同:
- 销售数据"想看哪个区域强" → comparison → bar
- 销售数据"想看月度涨没涨" → trend → line
- 销售数据"想看各区域占比" → part-of-whole → treemap(区域多)/ pie(区域少)
第二层:数据约束(细化选型)
| 约束因子 | 影响 |
|---|---|
| 类别数量 | ≤ 5 用 pie,6-10 用 bar,10+ 用 treemap / 排序后 top N |
| 时间粒度 | 连续型 → line;离散周期型 → column |
| 维度数 | 单维 → bar/line;双维 → grouped bar / dual-axes(量纲不同);多维 → heatmap / radar(≤ 6 维) |
| 目标值 / 基准线 | 有 → 加 reference line / bullet chart |
| 正负值并存 | 用 diverging palette + zero baseline 居中 |
| 数据稀疏度 | 稀疏 → scatter / dot;密集 → heatmap |
| 量级悬殊 | 考虑 log 轴(明确标注)或拆图,不要用双 Y 轴硬凑 |
选型决策表(高频场景速查)
| 场景 | 首选 | 备选 | 不要 |
|---|---|---|---|
| 多类别对比(≤ 10) | bar(横向,类别名长)/ column(纵向,类别名短) | dot plot | 3D 柱图、雷达图 |
| 多类别对比(> 10) | bar 取 top N + "其他" | treemap | pie |
| 单系列时间趋势 | line | area(强调累计量) | 柱图(除非离散周期如月度) |
| 多系列时间趋势 | 多 line(≤ 4 条) | small multiples | 堆叠柱图(除非求和有意义) |
| 占比(≤ 5 类) | donut(中间放总数) | pie | bar |
| 占比(> 5 类) | treemap / 排序 bar + 百分比标签 | stacked bar(单条) | pie |
| 两量纲对比 | dual-axes(必须双方都是同时间轴) | 拆两图 | 直接共用 Y 轴 |
| 相关性 | scatter + 趋势线 | bubble(加第三维) | 双 Y 轴 line |
| 分布形态 | histogram | box plot(含统计量) | line(误导为趋势) |
| 漏斗转化 | funnel | bar(横向递减) | pie |
| 流向 | sankey | chord diagram | 散点 |
| 单核心数 | kpi-card(数值 + 对比 + sparkline) | gauge(仅限达成率类) | pie(用饼图表达 80% 是噩梦) |
选型理由必填
每图必须写一句 rationale,不能只填 chart_type。范例:
- ✅
rationale: "区域销售对比,类别 8 个超出 pie 上限,纵向 bar 适配中文长类别名" - ❌
rationale: "用了柱图"
Step 3 — 每图视觉规格 + 状态 + 响应式
对每个选定的图表,逐项填写 visual_spec / interaction / states / responsive / accessibility / sparkdesign_contract。
视觉规格(visual_spec)
- width / height token:用 SparkDesign 的 size token(如
size.chart.lg),不要硬编码 px;未知就标gap_to_fill: "SparkDesign 待补 chart.size token" - palette:从下列五选一,不能自创:
categorical:分类(无序),用 SparkDesign 分类色板 tokenssequential:单一色相浅 → 深,表达有序/数量级diverging:双色相,中点对照(如盈亏)single-hue:品牌色单系列(趋势 / KPI 推荐)brand-accent:品牌强调色 + 中性灰背景对比
- palette_tokens:列出实际用的 token 名(如
["color.chart.cat.1", "color.chart.cat.2"]),不写#3B82F6 - y_axis_start:bar/column 必须
zero;line/area 可auto(但要在rationale解释) - direct_label:≤ 5 数据点首选直接标注,省去 legend
- legend_position:超过 5 系列才考虑 legend,否则
none - annotation:关键峰值 / 谷值 / 目标线 / 异常点必须文字标注
交互(interaction)
至少声明三类:
hover:tooltip 内容(建议含"数值 + 变化率 + 同环比")click:跳转 / 钻取行为(或写"不可点击")filter:是否参与全屏 filter 联动
状态(states)—— 图表层细化,与 /edge 联动
每图必须给出五个状态描述(即使写"沿用屏级 empty 状态"也比留空好):
empty:无数据时如何呈现(推荐:保留坐标轴 + 中部 illustration + 引导文案)loading:< 1s 不必特殊处理;1-3s 用 skeleton(保留坐标轴形态);> 3s 加 progresserror:取数失败时如何呈现 + 重试 CTAsingle_point:只有 1 个数据点时怎么画(line 退化为 dot;bar 不强求条数)overflow:数据超过设计上限时(top N + "查看全部")
响应式(responsive)—— Mobile 不是缩放,是改写
mobile_degradation 必须从以下五选一:
| 策略 | 适用场景 | 范例 |
|---|---|---|
simplify |
数据点 < 10 | 减少 tick / 隐藏次要 series / 移除装饰 |
swap-chart-type |
类别多或精度要求低 | grouped bar → stacked bar;pie → 横向 bar |
table |
精度要求高,对比维度多 | 复杂 dashboard → 表格 + 筛选 |
sparkline |
KPI 卡场景 | 趋势线压缩为 mini sparkline |
hide |
该图在 Mobile 价值低 | 整图隐藏,引导到 Desktop 看完整版 |
红线:≥ 5 系列的多 line 图、含 > 8 数据点的 pie 图、双 Y 轴图 —— 在 Mobile 上不允许简单等比缩放,必须 swap-chart-type 或 table。
可访问性(accessibility)—— 接 /access 的图表专项
四项硬指标:
colorblind_safe: true:调色板必须通过红绿色盲模拟(推荐用 Okabe-Ito 8 色或 ColorBrewer)contrast_ratio_pass: true:数据元素与背景对比 ≥ 3:1(WCAG AA 非文本元素)aria_label:图表必须有简短 aria-label 描述(如"2025 各区域销售柱状图,华东最高 1200 万")keyboard_navigable: true:交互图表必须可 Tab 进入、方向键切换数据点
仅靠颜色编码区分系列 = 不达标,必须叠加 pattern / 形状 / 直接标注其中一项。
SparkDesign 契约(sparkdesign_contract)
这是 SkillsHub 区别于社区 skill 的核心。 每图必须声明:
component:用 SparkDesign 的哪个组件(如<SparkChart variant="bar">),没有就标"待补"tokens_used:调用了哪些 design token(颜色 / 间距 / 字号)gap_to_fill:本图暴露的"SparkDesign 暂缺"项(如"缺 funnel 组件 / 缺 chart.size 系列 token")
跑完所有图表后,coverage.sparkdesign_gaps[] 汇总所有缺口 —— 这就是 AG-UI Design Spec 体系下 SparkDesign 仓库的图表组件需求列表,反推设计系统该建什么。
Step 3.5 — 可选:生成 AntV mock 预览(v1.1)
触发条件(满足任一即询问用户是否生成):
- 用户在调用时显式说"出预览图 / 生成 mock / 让我看看 / preview"
- 输出表面是
surface=dashboard且图表数 ≤ 10(一次性全生成预览成本可控) - 用户在 Step 1 提到"评审 / 提案 / 给 PM 看 / pitch"
不触发:用户明确说"只要规格不要图"、surface=embedded-chart 嵌入式(不需要独立预览)、图表数 > 10(建议挑核心图单独生成)。
执行逻辑:
用
AskUserQuestion二选一确认范围:「全部 N 图生成预览」/「只生成 [候选清单] 这几张」对选中的每图,按 附录 A:chart_type → AntV 映射表 转换
chart.charts[]的字段为 AntV 请求体用
Bash工具调用POST https://antv-studio.alipay.com/api/gpt-vis(curl)解析
resultObj为图片 URL,写回该图的preview字段:"preview": { "generated": true, "provider": "antv-gpt-vis", "antv_type": "column", "request_body": { ... }, "image_url": "https://...", "generated_at": "<ISO8601>" }失败兜底:API 超时 / 返回 success=false / 映射表标记
不支持→ 写preview.generated=false+fallback_reason(如 "AntV 无 heatmap 类型,建议 v1.2 接 ECharts 兜底"),不阻断主流程预览图 URL 在 4.1 Markdown 报告每图条目末尾以
形式插入
红线:
- 预览图是辅助评审,不是设计交付物本身。规格文档 + design token 仍是工程师消费的唯一权威源;预览图随时可能失效(外链)
- 不要因为 AntV 渲染好看就反向修改 chart_type / palette—— v1.1 是规格 → 预览单向流,预览结果不回写规格
Step 3.6 — 工程实现库智能推荐(v1.2,必做)
目的:避免 AI 在不了解项目栈的情况下盲推某个图表库(如在 React+shadcn 项目里推 AntV、在 antd 项目里推 Recharts)。本步强制执行——每个 Chart 输出必须含 implementation_recommendation 段,给出至少 2 个候选 + 1 个首选 + 切换触发。
3.6.1 技术栈检测(按以下信号源依次扫描)
| 优先级 | 信号源 | 提取字段 |
|---|---|---|
| 1 | 项目根 package.json(用 Read / Glob 扫描) |
dependencies 里已安装的图表库(recharts / echarts / @antv/* / chart.js / d3 / visx / plotly / victory)+ framework(react / vue / svelte / react-native)+ UI 库(shadcn 不在 deps 里,扫 components/ui/ 目录 / @radix-ui-* / antd / @mui/* / @chakra-ui/* / element-plus / naive-ui) |
| 2 | flow-web.json / flow-mobile.json 的 framework / ui_library 字段 |
同上备援 |
| 3 | brief.constraints |
"体积限制 < Xkb" / "公司技术栈是 X" / "禁止用 X" |
| 4 | 询问用户(仅当 1-3 全部失败) | 用 AskUserQuestion 二选一关键问题(框架 / UI 库) |
| 加分项 | SparkDesign 偏好(如本仓库 README / CLAUDE.md 明确"AntV-first / AG-UI 战略对齐") | 写入 sparkdesign_alignment = official 给 AntV 系候选加分 |
数据规模判断(影响候选打分):
small:单次渲染 < 100 数据点(默认)medium:100-1000large:1K-10K(卡顿风险,倾向 canvas 渲染)huge:> 10K(必须 ECharts / WebGL 类)
3.6.2 候选库矩阵(按检测到的栈映射)
| 检测到的栈 | 首选 | 备选 | 不建议 | 关键理由 |
|---|---|---|---|---|
| React + shadcn / Radix | Recharts | Visx · AntV G2 | @ant-design/charts(antd 强耦合) | 同源 React、声明式 JSX、与 Tailwind 适配好、~150KB |
| React + antd | @ant-design/charts (G2Plot) | ECharts · AntV G2 | Recharts | antd 同源 token 互通、视觉一致 |
| React + MUI / Chakra | Recharts | Nivo · Visx | 任一 antd 强耦合库 | 中性、与多种 UI 库共存 |
| React + SparkDesign | 看 SparkDesign 官方推荐(sparkdesign_alignment=official);无明确推荐时 Recharts | AntV G2(若 AG-UI 战略对齐) | — | SparkDesign 契约优先;战略层倾向 AntV 系 |
| Vue 3 | ECharts (vue-echarts) | @antv/g2 · Chart.js | Recharts(React only) | Vue 生态主流、社区支持厚 |
| Svelte | Layer Cake | ECharts · Chart.js | Recharts | Svelte 原生 |
| React Native | Victory Native | react-native-svg-charts · react-native-chart-kit | 任何 Web-only 库 | RN 渲染兼容 |
| Vanilla / 无框架 | ECharts | Chart.js · AntV G2 | Recharts | 与框架解耦、体积可裁剪 |
| 大数据量 (data_scale=large/huge) | ECharts (canvas) | Plotly · regl-based | Recharts (SVG 卡顿) | 渲染性能 |
| 关系图 / 桑基 / 大图分析 | AntV G6 | D3 · Cytoscape | Recharts | G6 专攻图分析 |
| 3D / WebGL | Three.js(自渲染) | Plotly 3D · deck.gl | 标准 chart 库 | 不擅长 3D |
3.6.3 已安装库强制复用规则(红线)
- 如
existing_chart_libs非空 → 首选必须从已安装列表里选,理由写"复用既有依赖避免双重打包",候选可列其他但必须把已安装库标 score 加 +30 - 例:项目已装 ECharts → 即使是 React+shadcn 也优先推 ECharts(除非已装库与当前需求严重不匹配,需在 rationale 说明并标
switch_triggers) - 严禁推荐第三个图表库新依赖(项目已装 1 个就只用那个;已装 2 个也尽量复用)
3.6.4 候选打分逻辑(每个候选 0-100)
score = 框架适配度(0-40) + UI 库适配度(0-20) + 已安装加分(0-30) + SparkDesign 战略加分(0-10) - 体积惩罚 - 维护风险惩罚
- 框架不匹配 → 直接淘汰(如 React 项目不列 vue-echarts)
- 已安装 → +30(最强信号)
- SparkDesign 战略对齐(sparkdesign_alignment=official)→ +10
- 体积 > 500KB gzip → -5 / 1MB+ → -15
- 库已停止维护 → -20
3.6.5 输出 implementation_recommendation
填充 schema 中的 implementation_recommendation 块:
detected_stack.detection_sources:列出信号源(如["package.json", "flow-web.framework"]),便于设计师追溯candidates:至少 2 个,按 score 降序;每个含 pros / cons / bundle_kb_gziprecommended.library:score 最高且无红线冲突的recommended.rationale:一句话说明(如"项目已装 recharts,复用避免新增 150KB 依赖")recommended.install_command:若已安装写已安装,无需新增;否则给出pnpm add recharts等recommended.bundle_impact:估算 gzip 增量(已安装 = 0)recommended.sparkdesign_alignment:official / compatible / neutral / conflict / naswitch_triggers:明确"什么情况下应该换库",例:["数据量超过 10K 点 → 换 ECharts", "新增关系图需求 → 加 AntV G6"]confidence:信号源齐全 high / 缺一两项 medium / 全靠询问用户 low
3.6.6 与 Step 3.5 mock 预览的关系
注意区分:
- Step 3.5 的 AntV:用于评审 mock,永远是 AntV gpt-vis(与本步推荐的工程库无关)
- Step 3.6 的推荐:工程实现库,按技术栈来,可能是 Recharts / ECharts / @ant-design/charts / 任意
两者互不冲突:设计师可以用 AntV 出预览图给老板看,工程实现用 Recharts 写代码。规格条目里 preview.image_url(评审用)和 implementation_recommendation.recommended.library(工程用)是两套独立信息。
Step 4 — 输出
4.1 Markdown 报告(输出到对话 + 保存到 spark-output/chart/[project-slug].md)
# Chart Spec — [项目名]
- **生成时间**:[ISO8601]
- **表面类型**:[surface]
- **图表总数**:N(comparison: n / trend: n / part-of-whole: n / ...)
- **Mobile 降级**:N 图(simplify n / swap n / table n / sparkline n / hide n)
- **可访问性通过率**:N/M
- **SparkDesign 缺口**:[列表]
- **数据源**:brief / sitemap / flow-web / flow-mobile
## Dashboard 布局总图
- 阅读路径:[F-shape / Z-shape / top-down]
- 密度:[sparse / balanced / dense]
- 网格:[如 12-col, 4 行]
### 分区结构
| 分区 | 用途 | 含图表 |
| --- | --- | --- |
| 顶部 KPI 行 | 一眼读数 | chart-1, chart-2, chart-3 |
| 中部趋势区 | 时间趋势 | chart-4, chart-5 |
| ... | ... | ... |
## 调色板策略
- **categorical**:[token 列表]
- **sequential**:[token set]
- **diverging**:[token set]
- **色盲检查**:pass / fail
## 图表清单(按 chart_id 组织)
### chart-1 · [图表标题]
- **所在屏**:[screen]
- **意图**:[comparison / trend / ...]
- **图表类型**:[bar / line / ...]
- **选型理由**:[一句话,必填]
- **数据形态**:维度 N / 系列 N / 数据点 N / 时间粒度 [...] / 有目标值 [Y/N]
- **视觉规格**:
- 尺寸:[width_token × height_token]
- 调色板:[palette](tokens: [...])
- Y 轴:[zero / auto] · 直接标注 [Y/N] · 图例 [position]
- 标注:[annotation 列表]
- **交互**:hover [...] · click [...] · filter [...]
- **状态**:empty / loading / error / single_point / overflow
- **响应式**:
- Desktop:[spec]
- Mobile:[degradation 策略] · [spec]
- **可访问性**:colorblind [✓/✗] · contrast [✓/✗] · aria [...] · keyboard [✓/✗]
- **SparkDesign 契约**:组件 [...] · tokens [...] · gap [...]
### chart-2 · ...
(每图完整展开)
## 工程实现库推荐(v1.2)
- **检测到的栈**:framework=[...] · ui_library=[...] · 已装图表库=[...] · data_scale=[...] · 信号源=[...]
- **置信度**:[high / medium / low]
- **候选**(按 score 降序):
| 库 | score | 优点 | 缺点 | gzip |
| --- | --- | --- | --- | --- |
| [推荐项] | [n] | [...] | [...] | [n]KB |
| [备选] | [n] | [...] | [...] | [n]KB |
- **首选**:[library] —— [rationale]
- **安装**:`[install_command]` · 体积增量:[bundle_impact]
- **SparkDesign 对齐**:[official / compatible / neutral / conflict / na]
- **切换触发**(什么情况下换库):
- [trigger 1]
- [trigger 2]
## SparkDesign 反向输入清单
跑完本次 Chart 暴露的 SparkDesign 缺口(按出现频次排序):
1. [gap 描述] · 影响图表数:N · 建议补法
2. ...
4.2 双通道 Context 输出
按 chain-protocol.md §2.1 v1.1 智能适配规则:
Step 1 — 写盘到 spark-output/context/chart.json(必做,主持久化通道;目录不存在先创建)。写入完整 JSON(schema 见 frontmatter)。
Step 2 — chat 输出紧凑 marker(必做,⛔ 不要在 chat 内重复输出 Step 1 的完整 JSON):
<!-- spark-context:chart ref="spark-output/context/chart.json" -->
Chart 已保存:project=[project_name],surface=[surface],[N] 图(trend n / comparison n / part n / ...),mobile 降级 [n],a11y 通过 [n/N],SparkDesign 缺口 [k] 项
<!-- /spark-context:chart -->
降级 fallback:若 Step 1 写盘失败(chat-only 平台),输出完整 JSON marker(无 ref 属性,marker 之间放裸 JSON)作为唯一持久化通道。
Handoff 提示(必输出)
协议:按
_shared/next-skill.md三层结构模板输出;前 5 候选由_shared/skill-graph.json的依赖图算法实时算(done ⊆ ready,按 next_hint.preferred → alternatives → 同阶段 → anchor → fan-out 排序),优先建议从_shared/skill-graph.json#skills[id="chart"].next_hint读取。
首行模板:✅ 数据可视化 已完成,图表规格 + AntV mock + 工程库推荐已沉淀。
本 Skill 的 next_hint(来自 skill-graph.json,不可在此 SKILL.md 内硬编码覆盖):
- preferred:
/flow-web - 优先理由:图表规格已就绪,回主流程把图表组件嵌回页面 Flow。
- alternatives:
/edge(图表的空 / 加载 / 错态需要单独覆盖) ·/check(页面 + 图表完整后整体自检) - emoji:📊
红线:
- ❌ 禁止在本段硬编码候选清单(如「进入 X / Y / Z」)——所有候选必须由算法实时生成
- ❌ 禁止按「文档类 / 视觉类 / 决策类」再分类候选(v0.5.5 起,分类已折叠进 next_hint.alternatives)
- ❌ 禁止与「更新链路面板」段合并——两段必须各自独立成段,中间空一行
- ❌ 禁止漏第 2 行候选清单——即使候选只有 1 个、或为空(终端节点)也要写出来
实操注意事项
图表过多时的策略
单个 Dashboard 超过 10 张图,几乎可以肯定违反了 Data-ink ratio 与认知负荷。处理方式:
- 拆分 Dashboard:按角色 / 任务拆成多屏(管理者总览 vs 运营详情)
- chart 合并:多张 KPI 单值合并为 KPI Row(横向卡片组)
- 降级为表格:高密度数据本质就是表格,不要硬画图
双 Y 轴的红线
双 Y 轴 只在以下两种情况合理:
- 两个序列时间轴完全一致,且业务上需要直接对比相关性(如成本 vs 收入)
- 一个柱图 + 一个折线图,量纲明显不同且各自有独立含义
其他场景一律拆两图。强行用双 Y 轴会让用户错读相关性,是数据可视化最常见的"骗自己"。
与 chart-visualization 工具的关系
.agents/skills/chart-visualization 是纯执行规格(AntV API 调用 + data schema),v1 不在本 Skill 调用范围。设计师如果只想"快速 mock 一张图给 PM 看",可以单独用 chart-visualization;本 Skill 产出的是可交付的设计规格文档,给工程师 / Cursor / Claude Code 消费,不是临时画图工具。
v2 计划:把 chart-visualization 的 API 规格作为 Chart Skill 的可选附录段,让 chart.charts[] 可一键导出 AntV 请求体做预览。
与 PM 套件 /产品指标复盘 的边界
| 场景 | 用谁 |
|---|---|
| "我们 Q3 应该关注哪些指标?怎么拆 OKR?" | PM /产品指标复盘 |
| "Dashboard 上要放哪几张图?每张图什么意图?" | Chart(本 Skill) |
| "上线后怎么追踪设计是否成功?" | /设计度量(metric) |
| "前端把柱图实现错了" | /设计验收(qa) |
Chart 不定义"看什么数",只解决"怎么把数画对"。PM 给出的 KPI 列表是 Chart 的输入,Chart 决定每个 KPI 在 Dashboard 上的视觉承载形式。
已知限制(v1)
- 预览仅作评审辅助:v1.1 的 AntV 预览是 mock 工具,不是工程实现的规格;工程师消费的仍是 chart.json + design token,不要把预览 URL 当成"最终视觉对账图"
- AntV 不覆盖全部 chart_type:heatmap / bubble / kpi-card / gauge / sparkline 五类在 v1.1 内无 AntV 对应,自动走 fallback(详见附录 A);可在 v1.2 接 ECharts 或 SparkDesign 自有渲染补齐
- 工程图表库推荐≠强制:v1.2 起 Skill 会根据技术栈给出 implementation_recommendation(首选 + 候选 + 切换触发),但前端团队仍有最终决定权;规格文档(每图 visual_spec / palette_tokens / a11y)与最终选用的库无关,换库不需重做规格
- 栈检测依赖 package.json 可读性:仓库无 package.json / 权限不足读不到时,confidence 降为 low,需用户在调用时显式说明栈(如"项目是 React + shadcn");否则可能误推
- 不做"美化建议":审美层面(如"这个 dashboard 看起来高级吗")需配合 /board 视觉情绪板
- SparkDesign 图表组件库可能未全:本 Skill 会显式输出
gap_to_fill,但暴露的缺口需 SparkDesign 仓库另行补建 - 极端数据集(10M+ 数据点)的渲染策略不在本范围:本 Skill 解决"选什么图、怎么画",不解决"如何性能优化渲染百万点"
- 地理可视化 (map / choropleth) 未覆盖:v1 不包含地图类,需在 v1.1 增量
- 动态时序播放 / 动画类未覆盖:建议配合 /motion
与兄弟 Skill 的边界(v0.4.0 范本对齐)
| 场景 | 用谁 | 不用谁 |
|---|---|---|
| 选图表类型 + 视觉规格 + Dashboard 布局 | Chart | Flow Web/Mobile(页面 IA 层不到图表细节)、chart-visualization(无设计判断) |
| Dashboard 所在页面的 IA 与导航 | Flow Web / Flow Mobile | Chart(不做页面级 IA) |
| 图表层 empty/loading/error 文案 | Chart(图表层)+ Edge(屏层) | 任一单独 |
| 临时画一张图给 PM 看 | chart-visualization(.agents/skills) | Chart(重型规格文档,不适合临时) |
| 上线后跟踪指标体系 | Metric | Chart(Chart 解决展示,Metric 解决度量) |
| 配色 / token 校验 | Chart(设计阶段)+ Check(走查)+ QA(实现) | 任一单独 |
| 图表无障碍校验 | Chart(标 a11y 项)+ Access(专项审计) | Chart 单独可初判,AA/AAA 完整审计要走 Access |
Chart 不可替代性:意图分类 → 数据约束 → 图表选型 → 调色板规则 → Mobile 降级 → SparkDesign 契约的六维链路,是设计师做 Dashboard / 报表前的唯一系统化规格工具——其他 Skill 都假设"图表已经画好了"在做下游工作。
质量标准
- 选型理由必填且站得住:每图
rationale≥ 一句完整话,能回答"为什么不是其他相邻图表类型" - 调色板纯一:单个 Dashboard 内 categorical / sequential / diverging 不能混用;交叉使用必须显式声明分区
- Y 轴零起点纪律:所有 bar / column 图
y_axis_start = zero;其他图若非 zero 必须在 rationale 内解释 - Mobile 降级率 ≥ 80%:含 ≥ 5 数据点的图表,必须有 mobile_degradation 策略(不能 default 缩放)
- 可访问性四项全过:colorblind_safe / contrast_ratio_pass / aria_label / keyboard_navigable 任一项 fail 视为该图未达交付标准
- SparkDesign 契约显式:每图必填 component / tokens_used / gap_to_fill,不能空着糊
- 意图 → 类型映射有依据:每图的 intent 与 chart_type 组合必须在 Step 2 选型决策表内或在 rationale 明确解释为何破例
- 状态五件套不省:empty / loading / error / single_point / overflow 一个都不能省(即使写"沿用屏级"也比空着好)
红线规则
- 禁止 3D 图表:3D bar / 3D pie 在任何场景都是反模式,扭曲数据视觉
- 禁止双 Y 轴乱配对:仅允许同时间轴 + 直接相关性场景,否则一律拆两图
- 禁止饼图类别 > 6:> 6 自动改 treemap / bar,不接受"凑合用 pie"
- 禁止仅用颜色编码区分系列:必须叠加 pattern / 形状 / 直接标注其中一项(直接对接 Access 红线)
- 禁止硬编码颜色十六进制:palette_tokens 必须用 SparkDesign token,找不到对应 token 也要标
gap_to_fill而非写死#3B82F6 - 禁止 Mobile 等比缩放复杂图:≥ 5 系列多 line / > 8 类 pie / 双 Y 轴 在 Mobile 必须改写
- 禁止把 Chart 当画图工具用:本 Skill 产出规格文档;如果用户只想画一张临时图,引导去 chart-visualization 或直接让 AI 画,不要走 Chart 全流程
- 禁止跳过选型理由:rationale 留空或写"用了 X 图"视为未完成
- 禁止忽略 package.json 已装库:检测到
existing_chart_libs非空时,首选必须从已装列表选;推不同库必须在 rationale 内说明已装库为何不合适(v1.2) - 禁止跨框架推荐:React 项目不推 vue-echarts,Vue 不推 Recharts,RN 不推 Web-only 库(v1.2)
- 禁止"无视栈"盲推:implementation_recommendation 是必填段,confidence=low 时必须显式标 "建议用户确认栈后重跑",不能糊一个推荐了事(v1.2)
附录 A:AntV GPT-Vis API 映射(v1.1 mock 预览)
本附录为 Step 3.5 提供"规格条目 → AntV 请求体"的转换规则。只在用户选择生成预览时才用到;不生成预览的图表无需消费本附录。
A.1 接口
POST https://antv-studio.alipay.com/api/gpt-vis
Content-Type: application/json
请求体(公共):
{
"type": "<chart_type>",
"source": "product-design-chart",
"data": [...],
"title": "<可选>",
"theme": "default | academy | dark",
"width": <number, 默认 600>,
"height": <number, 默认 400>,
"axisXTitle": "<可选>",
"axisYTitle": "<可选>"
}
返回:
{ "success": true, "resultObj": "https://..." }
⚠️
source字段在 chart-visualization 工具中是chart-visualization-skills,本 Skill 使用product-design-chart作为来源标识,便于 SparkDesign 团队追溯调用来源。
A.2 chart_type → AntV type 映射表
| 本 Skill chart_type | AntV type | 数据结构(data 字段) | 特殊参数 | fallback 策略 |
|---|---|---|---|---|
bar |
bar |
[{category, value, group?}] |
stack / group |
— |
column |
column |
[{category, value, group?}] |
group: true 默认 |
— |
line |
line |
[{time, value, group?}] |
stack: false |
— |
area |
area |
[{time, value, group?}] |
stack: true 默认 |
— |
dual-axes |
dual-axes |
categories: string[]series: [{type, data, axisYTitle}] |
series.type ∈ {column, line} | — |
pie |
pie |
[{category, value}] |
— | — |
donut |
pie |
[{category, value}] |
innerRadius: 0.5 |
— |
treemap |
treemap |
[{name, value, children?}] ≤ 3 层 |
— | — |
scatter |
scatter |
[{x, y, group?}] |
— | — |
bubble |
scatter |
[{x, y, group?}] |
第三维 size 暂不支持 | fallback_reason: "AntV scatter 不支持 size 维度,预览仅显示二维" |
heatmap |
— | — | — | generated: false, fallback_reason: "AntV gpt-vis 无 heatmap,建议接 ECharts 兜底" |
histogram |
histogram |
number[] |
binNumber |
— |
boxplot |
boxplot |
[{category, value, group?}] |
— | — |
funnel |
funnel |
[{category, value}] |
— | — |
radar |
radar |
[{name, value, group?}] |
— | — |
sankey |
sankey |
[{source, target, value}] |
nodeAlign |
— |
waterfall |
waterfall |
[{category, value?, isTotal?}] |
— | — |
kpi-card |
— | — | — | generated: false, fallback_reason: "KPI 卡建议直接用 SparkDesign 组件,无需 mock 预览" |
sparkline |
line |
[{time, value}] |
width: 200, height: 60关闭坐标轴 |
降级为 mini line |
gauge |
liquid |
percent: number (0-1) |
shape: "circle" |
近似替代 |
table |
spreadsheet |
Record<string, string|number>[] |
rows / columns / values |
— |
映射核心原则:
- 能 1:1 映射就直接映射(90% 场景)
- 视觉等价的降级允许(如 sparkline → 简化 line)
- 完全不支持的,写
fallback_reason而非硬塞,让评审者知道"为什么这张没图"
A.3 调用模板(curl)
curl -s -X POST https://antv-studio.alipay.com/api/gpt-vis \
-H "Content-Type: application/json" \
-d '{
"type": "column",
"source": "product-design-chart",
"data": [
{"category": "华东", "value": 1200},
{"category": "华北", "value": 980},
{"category": "华南", "value": 1450}
],
"title": "2025 各区域销售对比",
"axisXTitle": "区域",
"axisYTitle": "销售额(万)",
"theme": "default",
"width": 800,
"height": 400
}'
期望响应:
{"success": true, "resultObj": "https://antv-studio.alipay.com/results/xxx.png"}
异常处理:
- 网络超时 / 5xx → 等 2s 重试一次;仍失败写
fallback_reason: "API 不可达" success: false→ 写fallback_reason: <错误 message>- 响应 URL 不可访问(HEAD 校验失败)→ 写
fallback_reason: "返回 URL 不可访问"
A.4 字段映射注意事项
- AntV theme 与 SparkDesign 主题不一致:v1.1 预览统一用
theme: "default",预览只追求"形对",颜色对账以 chart.jsonpalette_tokens为权威源 - AntV 不接受 design token:调用时 palette / 字号 / 间距均用 AntV 默认;如需"品牌色预览"可在 request_body 加
colors: ["#...", ...](但只在评审需要时用,规格本身仍用 token) - title 来源:取 chart.charts[].chart_id 对应的图表标题(Markdown 报告里的
### chart-N · [标题]),非 chart_id 本身 - 轴标题:dual-axes / scatter / line / bar / column 必填 axisXTitle / axisYTitle,否则预览图无法理解
A.5 v1.2 计划(待办)
- heatmap / kpi-card / gauge:接 ECharts 或 SparkDesign 自渲染补齐
- bubble:等 AntV gpt-vis 支持 size 维度
- 预览图本地缓存:避免反复调用同一份数据
- SparkDesign 主题色注入 AntV:实现真正的"品牌色预览"