# Flint Chart Author

> 从结构化、表格或查询结果生成数据图表：选择适合对比、趋势、分布、相关性或层级关系的图型， 生成、修复、解释或校验 Flint 图表规格，输出可直接渲染的 ```flint 围栏块。 Trigger on: "画图", "画个图", "可视化", "出个图表", "flint", "chart", "visualize", "plot this", "graph these numbers", "对比一下…（给出多行数据时）", "趋势", "分布", "占比", "相关性", 或用户已给出表格/查询结果并要求"看得更直观"。 也在需要**修复**一个渲染失败的 ```flint 块、或**解释**某个 flint 规格含义时使用。

- Skill: `jin-bo/flint-chart-author` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add jin-bo/flint-chart-author`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jin-bo/flint-chart-author/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jin-bo (https://skillmd.com/u/jin-bo)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/jin-bo/flint-chart-author

---


# flint-chart-author — Flint 图表规格作者

你把**已经拿到手的结构化数据**变成一个合法的 ` ```flint ` 围栏块。
[Flint](https://github.com/microsoft/flint-chart) 是微软研究院的可视化中间语言：给它
「数据 + 图型 + 编码」，它自己推导刻度、轴、标签、图例、布局——所以你**不需要**写任何
Vega-Lite / ECharts 的底层配置，写多了反而会被丢弃。

图型清单、通道语义、语义类型表、完整示例与失败模式对照见
[`references/flint-spec.md`](references/flint-spec.md)，**按需载入**。

## 边界

| | |
|---|---|
| **输入** | 已有的结构化数据、表格、或查询结果（对象数组形态） |
| **职责** | 选图型与编码 · 必要时先聚合 · 生成 / 修复 / 解释 / 校验 flint 规格 |
| **输出** | 一个 ` ```flint ` 围栏块（JSON），块外配一句人话说明它在说什么 |
| **不负责** | 数据库连接与取数权限 · 知识库/wiki 维护 · markdown 存放在哪一页 · 浏览器端渲染 |

数据从哪来、图放到哪儿去，都由调用你的那条工作流决定；你只对**「这段 JSON 合法且画出来是对的」**负责。

## 工作流

### 1. 先看数据，再选图

看三件事：**行数**、**每列的类型**（数值 / 类别 / 日期）、**你想让读者看出什么**。
最后一件决定图型——参考的图型表按用途分组（对比 / 趋势 / 分布 / 相关 / 构成层级 / 流向 / 时间安排）。

拿不准就选最朴素的那个：类别比大小用 `Bar Chart`，随时间变化用 `Line Chart`，两个数值的关系用
`Scatter Plot`。**朴素的图被读懂的概率远高于花哨的图。**

### 2. 必要时先聚合——这是你的活，不是 flint 的

flint **不做聚合**（`encodings.*.aggregate` 只在部分模板生效，别指望）。原始明细表要先自己算成
结论性的聚合结果再内联：`GROUP BY` 之后的几行、十几行，而不是几百行明细。

> 判据：**这张图要说的那句话，需要几行数据才够？** 只要那几行。
> 搬原始表进来既撞行数上限，也让读者自己去找结论——那是表格的活，不是图的活。

### 3. 写块

最小形态（`semantic_types` 可整段省略，flint 会自行推断）：

````markdown
```flint
{"data":{"values":[{"模型":"model-a","评测得分":72.4},{"模型":"model-b","评测得分":81.9}]},
 "chart_spec":{"chartType":"Bar Chart",
               "encodings":{"x":{"field":"模型"},"y":{"field":"评测得分"}}}}
```
````

写清楚一点（推荐）：加 `semantic_types` 让刻度/格式/排序更合理，加 `baseSize` 定尺寸。
字段名用**数据里的原名**（中文列名完全可以），不要为了图去改名——要改显示名用 `field_display_names`。

### 4. 自校验（**每次输出前逐条过，不要跳**）

- [ ] 整块是**合法 JSON**（不是 YAML、没有注释、没有尾逗号、没有单引号）
- [ ] 顶层只有 `data` / `semantic_types` / `chart_spec` / `field_display_names` / `options` 五个键之内
- [ ] `data.values` 是**对象数组**且**非空**；**没有** `data.url`
      （flint 的类型接受 url，但渲染端一般拒绝取远端数据，图不会出现）
- [ ] 每个单元格是**标量**（字符串 / 数字 / 布尔）——不放嵌套对象或数组
- [ ] 行数 **≤ 1000**（这是**宿主渲染端**的上限、不是 flint 的规格；换宿主时按那边确认。
      不过真要画到接近上限，多半是第 2 步的聚合没做够）
- [ ] `chart_spec.chartType` 与参考里的写法**逐字符一致**（**大小写敏感**：`Bar Chart` 对，`Bar chart` 错）
- [ ] 每个 `encodings.*.field` 都能在数据列里找到（**任一行**有即可）
- [ ] 数据形状与图型匹配（`Histogram` 的 `x` 必须是数值列、`Calendar Heatmap` 的 `x` 必须是日期串……见参考）
- [ ] 若写了 `baseSize`：宽高都是**有限正数**、且在 **160–1600** × **120–1200** 内
      （注意：`baseSize` 是**基准不是上限**——flint 会按类别数/分面数把它**放大**，实测 `420×260`
      在多序列下会长到 `657×514`。渲染端卡的是**放大后**的尺寸，所以类别特别多时要么减少类别、
      要么用 `canvasSize` 给一个硬上限，它是真会生效的钳制）

### 5. 块外补一句人话

图是**取数那一刻的快照**，不会自己刷新。所以在块外正文写一句：这张图在说什么，数据来自哪、口径是什么、
什么时候取的。这是通用建议、**不是** flint 规格的一部分——不要试图把来源塞进 JSON，任何自定义字段都会被丢弃。

## 修复一个画不出来的块

按这个顺序查，命中率从高到低（都是实测出来的失败模式，详见参考的对照表）：

1. **JSON 语法**——最常见，先 parse 一遍。
2. **`chartType` 大小写**——写错会直接抛 `Unknown ECharts chart type: …`。
3. **列名对不上**——`encodings.*.field` 写了数据里没有的列。**这种最坏：不报错，画出一张空图**。
4. **数据形状不匹配图型**——列名全对也可能空，例如给 `Histogram` 喂了类别列当 `x`。
5. **该图型的「必给」通道缺了**——flint 会**静默回吐一个不是 ECharts 图的中间态**，渲染端只能判失败。
   实测 `Sunburst Chart` 缺 `color` 即如此（见参考第 2 节的备注列）。
6. **超限**——行数 / 块体积 / 画布尺寸越界，渲染端会保留源码并显示「数据过大」。
   （这一类的具体阈值由**宿主渲染端**定，不是 flint 规格的一部分。）

修完**重跑第 4 步的整份清单**，不要只验你刚改的那一条。

## 三条纪律

- **数据必须内联。** 图要能只靠这段 markdown 重建；引用外部 URL 的块不会被渲染。
- **不画装饰图。** 一张图对应一个结论。没有结论就不画——一段话比一张没有话说的图强。
- **失败要看得见。** 拿不准某个图型能不能成，就退回 `Bar Chart`/`Line Chart`，别赌。

