Files

104 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 可数据绑定的原生图表组件
`chart_component.py`把明确的数据生成一个独立 SVG `g`:其中包含原生 Chart metadata、同源的可见 SVG fallback,以及标题、单位、图例和来源文字。把它组合进所选 template 的页面;组件不复制母版、版式或页面 UI。它是技术组件接口,不替调用者决定报告应使用哪些图表。
## 按判断任务选图
先说明当前图表支撑哪个判断、所需数据和比较口径,再选择表达方式。内容方案可能建议箱线图、小提琴图等;这些是表达任务的建议,不表示本组件已支持。当前原生接口只支持下表七类。
建议类型不受支持时,判断已选制作路线能否用原生对象或可验证的 SVG 图示保真实现;明确其实际对象类型和编辑范围。若不能实现,返回受影响页 ID、缺少的能力及具体内容选项。不能把分布静默改成均值、遗漏会改变判断的对照,或以图片宣称原生 Chart;也不静默更换后端、在线服务或安装其他 Skill。
比较前优先统一对象、定义、单位、分母/基线、时间范围、样本和统计方法;保留有效换算、重算或区间对齐的依据。确实无法统一时,分开展示或限定可比较的情境,让结论与实际证据范围一致;仅标“口径不同”不能支撑排名。
## 支持范围
| type/示例数据 | 用途与适配 | 当前技术边界 |
|---|---|---|
| `column`/[column.json](../assets/components/charts/column.json) | 比较少量类别;多系列分组 | 数轴包含零,显式 min/max/major_unit;支持正、负、零 |
| `bar`/[bar.json](../assets/components/charts/bar.json) | 较长类别名称的横向数量比较 | 上游编译器不接受 bar 的 axes;原生应用自动选择范围与刻度,SVG 标尺只作预览;保留真实数值及原生数据标签 |
| `line`/[line.json](../assets/components/charts/line.json) | 按顺序比较变化 | 等间距类别轴、显式数轴;直线与圆点;不把类别轴当成连续日期轴 |
| `scatter`/[scatter.json](../assets/components/charts/scatter.json) | 展示成对的 X/Y 观测 | `points: [[x, y], …]`;两个显式数轴;圆点,无回归拟合 |
| `pie`/[pie.json](../assets/components/charts/pie.json) | 单组非负构成 | 一个系列,总和大于零;零值保留在数据与图例中,不绘制零面积扇形 |
| `doughnut`/[doughnut.json](../assets/components/charts/doughnut.json) | 单组非负构成 | 与 pie 相同;内圈比例75%,与锁定原生编译器一致 |
| `column-stacked`/[column-stacked.json](../assets/components/charts/column-stacked.json) | 比较各类别的总量及组成 | 初版只支持非负堆叠;范围基于各类别总量,不把单个系列最大值当堆叠上界 |
示例全部明确标记 `synthetic-demo`,使用564×464区域,保留单位与来源。它们只演示技术能力,不能作为真实报告证据。图例、文字和轴预留空间不足时工具报错,不自动缩字;改写标签或使用更宽区域后再生成。宽度估算是保守的字符检查,仍需查看目标应用的实际渲染。
这层封装不接受混合图、双轴、百分比堆叠、3D、气泡、时间轴、缺失值、平滑曲线、任意自定坐标轴或额外格式字段。上游可能另有能力,但不能经本组件接口静默转入。需要这些能力时先确认作者路线与支持范围。
## 数据契约
JSON顶层字段:`schema_version: 1`,`data_kind`(`synthetic-demo`/`observed`/`derived`),`type`、非空 `title`、`unit`(允许空字符串)、`series`。`source`可选。scatter可另写`x_unit`,并省略`categories`;其余类型必须提供非空、唯一的`categories`标签。
每个系列有稳定、唯一的`id`、非空`name`,以及与类别同长的`values`,或scatter的非空`points`数组。ID使用`[A-Za-z][A-Za-z0-9_-]{0,63}`。数值必须是JSON数字且有限;布尔值、数字字符串、NaN和无穷均拒绝。为避免SVG/OOXML标量计算溢出或失去有效标签,当前非零数值的绝对值支持`1e-9`至`1e12`,零独立支持。不会补齐长度、删掉零值、改写负数或按百分比重算原始数据。CLI拒绝重复JSON键和未知字段。
`source`只作为显示文字与元数据保留,工具不会读取链接、补充出处或证明其真实性。所有原始数据同时放入marker的`component_data`,供工程审计;原生图表cache及内嵌XLSX保存未缩放的实际数值。
遵循[文字与容器约束](text-and-containers.md):数据源、一般范围、统计口径与引用定位可使用小字;直接影响核心判断的条件、实质解释与结论放在相关主体中。先修正有歧义或过强的正文,删除无助于理解的预防性辩解;具体、有用的警示按作用适度表达。字段名不能把必要信息降级为`source`,也不把正常来源文字改成警告。图表标题、说明和正文承担不同作用时,用字号、字重和/或调色板颜色作出明确区分,不能只换字体。
## 样式来源
`style`和`theme`分别使用`template_ref.py export-style`的`style`、`theme_data`。每个文字角色通过`family_role`解析自己的字体、字号、字重和行高,按`canvas.pt_to_px`换算;不会把所有角色强制映射到body字体。图表标题使用`label`角色与`accent2`;没有`label`的旧样式沿用图表文字角色,通过颜色区分。单位、轴和图例使用显式`components.charts.text_role`(默认`caption`,缺少时为`label`)及`text_palette_index`;来源沿用标注角色的字体和字号,但颜色为`dk2`。组件没有组织、字体名或十六进制配色的固定默认值。
原生Chart轴当前只支持Regular(400),对需要其他轴字重的角色明确报错,不只改变SVG预览。pie/doughnut没有轴,独立标题、图例和来源可按角色保留加粗。普通原生文字/Table使用常规与加粗的字重语义;中间字重仍需目标字体与应用验证,不能仅据SVG的数值声明推断精确字重。
template可选择声明`style.components.charts`:
```json
{
"series_palette_indices": ["accent1", "accent3", "accent4"],
"text_role": "caption",
"text_palette_index": "dk1",
"grid_palette_index": "line"
}
```
未声明时,系列依次使用已有的`accent1`、`accent3`、`accent4`、`accent5`、`accent6`、`accent2`;文字使用`dk1`,网格使用`line`(缺少时`dk2`),图表背景使用`lt1`。颜色必须为调色板中已存在的六位hex值。系列按数组顺序绑定索引,pie按类别顺序绑定。需要的系列或扇形数超过不同索引数量时明确拒绝,不循环复用颜色。组件不会从系列名称推断状态或改动数据语义。
保持简洁的精细化优先处理信息层次:保留轻网格、统一标签与单位、适度留白,并按比较目的分配颜色。平行系列可用两个主题索引;当作者明确选择一个重点系列时,可在该页风格副本中设置 `series_palette_indices: ["dk2", "accent1"]`,用中性参照配合主题色重点。颜色顺序必须对应明确系列,不从名称或数值自动选择“更好”的一组。
`axis_palette_index` 可将轴线绑定到现有调色板索引,默认跟随文字。`value_labels: true` 为非负分组 `column` 同时生成原生数值标签及同源 fallback;标签使用已声明字号,放不下时报错。默认关闭,不给每一种图表都加数字。bar 本身保留数值标签;其他类型或负值柱图需要按其信息特点另行设计。改动页面风格副本不改变全工程的系列语义;同一系列跨页需由作者保持绑定。
column、line、scatter与非负堆叠的显式数轴和SVG fallback使用同一组范围与步长;全零数轴为0至1。bar受锁定编译器限制,由原生应用自动选轴,并带有`data-native-axis-policy="automatic-bar-preview-scale-may-differ"`声明。显式数轴一致不代表原生应用绘图区、轴文字位置与SVG像素级一致。
## 生成与组合
使用安装方准备的Python环境,在任何目录执行:
```sh
python /path/to/skill/scripts/chart_component.py \
--manifest /absolute/path/to/template/manifest.json \
--theme selected-theme \
--data /absolute/path/to/column.json \
--bounds 64 156 564 464 --id results-chart \
--output /absolute/path/to/new-component.svg
```
CLI选择一个外部template/theme,输出对应canvas的独立组件SVG,拒绝覆盖文件及经符号链接写出。它没有页面的Master/Layout契约,不能直接冒充完整模板页面交给结构化原生导出器。
Python组合接口:
```python
from chart_component import render_chart
component = render_chart(data, exported["style"], exported["theme_data"],
(64, 156, 564, 464), "results-chart")
# page_root是已有模板页,保留其Master/Layout、固定UI、占位符与素材引用。
slot = next(node for node in page_root if node.get("id") == "slot-left")
for child in list(slot):
slot.remove(child)
slot.append(component)
```
`render_chart(data, style, theme, bounds, component_id) -> xml.etree.ElementTree.Element`返回SVG `g`。使用当前页真实槽位的bounds;确认当前template确实有该槽位,不能把示例中的ID、坐标当通用约定。component_id在整页必须唯一。生成后不要单独改fallback图形或marker数据;修改JSON并重新生成,保持fallback指纹和元数据一致。
同一种图表容器/变体共用内部排版实现,调用者只提供内容和整体bounds,不逐例移动标题、图例、图标或说明。需要新的说明区时定义共享组合规则,并重新生成整组;一个连续段落优先保持为一个原生文本框,必要拆分也必须共用一个逻辑文本块和换行规则。
图例、标题、单位及来源位于marker外,编译为独立可编辑对象;marker内转换为真正的Chart和内嵌XLSX。此安排保持页面文字位置受模板控制。若在PowerPoint内改图表数据,外部图例或构成数量文字不会自动更新,需要一起修改,或从工程JSON重建。将图表JSON和生成工具声明为工程输入并锁定,可在迁移后重建;不能只交付生成的SVG与PPTX。
## 验证与限制
本项目的`check_chart_components.py`验证两theme的7类组件SVG、错误输入拒绝和已有文件保护;实际通过锁定编译器生成7类Chart及正负/全零边界案例,检查原生Chart类型、显式轴、自动bar轴、数值cache、内嵌XLSX、独立标题与合成数据声明。Chart对象的存在以PPTX关系和XML为证据。
这些检查不代表PowerPoint已实际打开、渲染、编辑或完成投影验收。进入真实页面后需按[PowerPoint检查](powerpoint-checks.md)核对字形、标尺、单位、图例、数据与页内分区;页面审阅由负责人按已有逐页流程组织。图表导出失败必须报告,不能用fallback截图宣称已得到原生Chart。