11 KiB
可数据绑定的原生图表组件
chart_component.py把明确的数据生成一个独立 SVG g:其中包含原生 Chart metadata、同源的可见 SVG fallback,以及标题、单位、图例和来源文字。把它组合进所选 template 的页面;组件不复制母版、版式或页面 UI。它是技术组件接口,不替调用者决定报告应使用哪些图表。
按判断任务选图
先说明当前图表支撑哪个判断、所需数据和比较口径,再选择表达方式。内容方案可能建议箱线图、小提琴图等;这些是表达任务的建议,不表示本组件已支持。当前原生接口只支持下表七类。
建议类型不受支持时,判断已选制作路线能否用原生对象或可验证的 SVG 图示保真实现;明确其实际对象类型和编辑范围。若不能实现,返回受影响页 ID、缺少的能力及具体内容选项。不能把分布静默改成均值、遗漏会改变判断的对照,或以图片宣称原生 Chart;也不静默更换后端、在线服务或安装其他 Skill。
比较前优先统一对象、定义、单位、分母/基线、时间范围、样本和统计方法;保留有效换算、重算或区间对齐的依据。确实无法统一时,分开展示或限定可比较的情境,让结论与实际证据范围一致;仅标“口径不同”不能支撑排名。
支持范围
| type/示例数据 | 用途与适配 | 当前技术边界 |
|---|---|---|
column/column.json |
比较少量类别;多系列分组 | 数轴包含零,显式 min/max/major_unit;支持正、负、零 |
bar/bar.json |
较长类别名称的横向数量比较 | 上游编译器不接受 bar 的 axes;原生应用自动选择范围与刻度,SVG 标尺只作预览;保留真实数值及原生数据标签 |
line/line.json |
按顺序比较变化 | 等间距类别轴、显式数轴;直线与圆点;不把类别轴当成连续日期轴 |
scatter/scatter.json |
展示成对的 X/Y 观测 | points: [[x, y], …];两个显式数轴;圆点,无回归拟合 |
pie/pie.json |
单组非负构成 | 一个系列,总和大于零;零值保留在数据与图例中,不绘制零面积扇形 |
doughnut/doughnut.json |
单组非负构成 | 与 pie 相同;内圈比例75%,与锁定原生编译器一致 |
column-stacked/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保存未缩放的实际数值。
遵循文字与容器约束:数据源、一般范围、统计口径与引用定位可使用小字;直接影响核心判断的条件、实质解释与结论放在相关主体中。先修正有歧义或过强的正文,删除无助于理解的预防性辩解;具体、有用的警示按作用适度表达。字段名不能把必要信息降级为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:
{
"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环境,在任何目录执行:
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组合接口:
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检查核对字形、标尺、单位、图例、数据与页内分区;页面审阅由负责人按已有逐页流程组织。图表导出失败必须报告,不能用fallback截图宣称已得到原生Chart。