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

# 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` 定尺寸。
字段名用**数据里的原名**（中文列名完全可以）。想让轴上显示得更好看，就**在数据里把列名改好**——
flint 0.4.1 没有「显示名」这种字段（写了不报错也不生效）。

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

- [ ] 整块是**合法 JSON**（不是 YAML、没有注释、没有尾逗号、没有单引号）
- [ ] 顶层只有 `data` / `semantic_types` / `chart_spec` / `options` 之内（别的键一律被丢弃）
- [ ] `data.values` 是**对象数组**且**非空**；**没有** `data.url`（渲染端一律拒绝，图不会出现）
- [ ] 每个单元格是**标量**（字符串 / 数字 / 布尔）——不放嵌套对象或数组
- [ ] 行数 **≤ 1000**
- [ ] **类别数别太多**：`color` / `column` / `row` 上的取值超出图表容量时，flint 会**整批丢掉**多余的，
      渲染端据此拒渲并显示「数据被截断」——先做 Top-N 聚合，别把几十个类别硬塞进一张图
- [ ] `chart_spec.chartType` 与参考里的写法**逐字符一致**（**大小写敏感**：`Bar Chart` 对，`Bar chart` 错）
- [ ] 每个 `encodings.*.field` 都能在数据列里找到（**任一行**有即可）
- [ ] 数据形状与图型匹配（`Histogram` 的 `x` 必须是数值列、`Calendar Heatmap` 的 `x` 必须是日期串……见参考）
- [ ] 若写了 `baseSize`：宽高都是**有限正数**（`baseSize` 是**基准不是上限**——flint 会按类别数/
      分面数把它放大，实测 `420×260` 在多序列下会长到 `657×514`）。**不必**为了栏宽去调它：
      渲染端会按正文栏宽让 flint **重新编译**一遍；只有大到离谱（宽 >1600 或高 >1200 仍收不住）
      才会被判「数据过大」

### 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. **超限**——行数 / 块体积 / 画布过大，渲染端保留源码并显示「数据过大」。
7. **类别太多**——`color`/`column`/`row` 的取值被 flint 整批丢弃，渲染端显示「数据被截断」。
   注意这条**不是**「图太大」：删行没用，要减的是**类别数**。

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

## 三条纪律

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