# 可数据绑定的原生图表组件 `chart_component.py`把明确的数据生成一个独立 SVG `g`:其中包含原生 Chart metadata、同源的可见 SVG fallback,以及标题、单位、图例和来源文字。把它组合进所选 template 的页面;组件不复制母版、版式或页面 UI。它是技术组件接口,不替调用者决定报告应使用哪些图表。 ## 支持范围 | 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保存未缩放的实际数值。 ## 样式来源 `style`和`theme`分别使用`template_ref.py export-style`的`style`、`theme_data`。字体从`typography.families.body`取得,字号默认取`caption`角色,缺少时取`label`;按`canvas.pt_to_px`换算。组件没有组织、字体名或十六进制配色的固定默认值。 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指纹和元数据一致。 图例、标题、单位及来源位于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。