Claude Code Dataviz 参考调色板:一份可验证的数据可视化默认色板及其背后的计算式校验
本文以 Claude Code 的 dataviz skill 中的参考调色板文件(references/palette.md)为主体,完整讲解这份"设计系统无关"默认色板的全部参数:分类色 8 槽位的明暗双模式取值、顺序/发散色阶、固定状态色、图表墨水与界面色、纹理填充通道,并对照仓库中 validate_palette.js / validate_palette.py 的阈值常量与校验逻辑,说明这些数值是如何被计算验证的,以及替换为品牌色后如何复验。读完后你可以直接复制这份色板到 HTML/SVG 图表中,并用同一套校验脚本对任意自定义色板做六项可计算检查。
参考调色板是什么:方法的"填好参数的实例"
palette.md 的定位非常明确:它是整个数据可视化方法的参考实例(reference instance)——方法所需的每一个参数,都被填入了一套经过验证的默认值。方法本身是品牌无关(brand-neutral)的:要适配自己的品牌,只需替换本文件的取值并重跑校验器,方法的其他部分一律不变。这一点在 SKILL.md 中同样强调:方法不变,设计系统提供一组参数(色阶、分类顺序、发散对、状态色、纹理、表面色、筛选控件),参考实例就是"每行都填好的那张参数表"。
所有取值都是纯 hex。文档给出的落地方式是:在 HTML 图表顶部的局部 <style> 块中,把你用到的槽位定义成 CSS 自定义属性,正文按"角色"引用而不是按裸 hex 引用——这样明暗两套值只在一处切换,图表主体始终对着角色书写:
.viz-root {
color-scheme: light;
--surface-1: #fcfcfb; /* chart surface */
--text-primary: #0b0b0b;
--text-secondary: #52514e;
--series-1: #2a78d6; /* categorical slot 1 */
/* ...only the roles this chart uses */
}
@media (prefers-color-scheme: dark) {
:root:where(:not([data-theme="light"])) .viz-root {
color-scheme: dark;
--surface-1: #1a1a19;
--text-primary: #ffffff;
--text-secondary: #c3c2b7;
--series-1: #3987e5;
}
}
:root[data-theme="dark"] .viz-root {
color-scheme: dark;
--surface-1: #1a1a19;
--text-primary: #ffffff;
--text-secondary: #c3c2b7;
--series-1: #3987e5;
}
文档要求暗色值同时声明在上述两个作用域下:媒体查询覆盖操作系统设置,data-theme 作用域覆盖页面内的主题切换按钮,且两者必须双向生效——:not([data-theme="light"]) 守卫让"页面显式设为浅色"能压过"系统暗色",:where() 则保证媒体查询块的优先级低于切换作用域。这是该文件中一个容易踩坑的实现细节:少写任何一个作用域,暗色切换都会出现一种"赢不了"的场景。
分类调色板:8 个槽位、明暗双模式,以及顺序即安全机制
分类色板共 8 个槽位。暗色列不是另一套色板,而是同样的 8 个色相针对暗色表面重新步进(re-step)的结果:
| Slot | 色相 | Light | Dark |
|---|---|---|---|
| 1 | blue | #2a78d6 |
#3987e5 |
| 2 | orange | #eb6834 |
#d95926 |
| 3 | aqua | #1baf7a |
#199e70 |
| 4 | yellow | #eda100 |
#c98500 |
| 5 | magenta | #e87ba4 |
#d55181 |
| 6 | green | #008300 |
#008300 |
| 7 | violet | #4a3aa7 |
#9085e9 |
| 8 | red | #e34948 |
#e66767 |
这组顺序在两种模式下都通过了全部硬性门槛(默认 adjacent 配对清单,适用于堆叠、条形、折线):
- 相邻 CVD Delta E(OKLab ×100)最差值:9.1(light)/ 8.4(dark),目标 ≥ 8;
- 相邻正常视觉 Delta E 最差值:19.6(light)/ 19.3(dark),地板 ≥ 15。
关键理解是:槽位顺序本身就是 CVD 安全机制,不是装饰。候选顺序被枚举过,只有两种模式下都通过每一道相邻门槛的顺序被保留,这套默认值只是合格顺序之一,因"开头颜色更和谐"被选中(详见 color-formula.md 的 Themes 一节)。当你换入自己品牌的色相时,也必须做同样的事:对候选顺序跑校验器,只在通过者中选择。
文件还记录了 2026 年 7 月的一次重排历史,值得了解它说明的规则边界:
- 重排前后是同样的 8 个色相与步进,零 hex 变更,只是顺序变了;
- 前一代顺序能通过"前 4 槽全对(all-pairs)"验证,但其暗色序列落在 CVD 6–8 的告警带,需要二级编码补偿;
- 当前顺序主动放弃了第 4 槽(yellow 现在与 orange 相邻),换取更顺眼的开头色。
由此引出 --pairs all(散点、气泡、分级统计图、small multiples 等任意两标记可能并排的图表形式)下的系列数上限:完整 8 色在 all-pairs 下不可能过地板(28 个对子不再依赖顺序,而重步进又受"只用已文档化色板"规则限制),因此这些图表形式携带一个系列上限——前 3 个槽位在两种模式下通过全部对子验证(最差对 CVD Delta E 9.2 light / 9.4 dark,正常视觉 24.0 light / 20.9 dark,都高于 CVD 告警带)。超过 3 个系列就必须折叠进 "Other" 或改用 facet:第 4 槽会把 yellow 和 orange 同时放上屏幕,而这一对过不了 all-pairs 地板(正常视觉 13.7 light;CVD 4.8 dark)。
另一条硬性规定是救济规则(relief rule):light 模式下 magenta、yellow、aqua 三个槽位在浅色表面上的对比度低于 3:1,此时必须随图表提供可见的直接标签或表格视图。这条规则在 SKILL.md 的"Non-negotiables"中同样被列为不可豁免项。暗色步进则是按暗色带(OKLCH L ≈ 0.48–0.67,在暗色表面上 ≥ 3:1)选取并作为整体验证的。
顺序色(Sequential)与序级色(Ordinal):默认蓝色,一次只许一种色相
默认单一色相是蓝色,方向 light→dark。当同一页面同时出现两个顺序色上下文时,第二个上下文取下一个分类槽位的色相(orange),各自仍是独立的一色相色阶。完整 100→700 步进如下:
| step | hex | step | hex | step | hex | step | hex |
|---|---|---|---|---|---|---|---|
| 100 | #cde2fb |
250 | #86b6ef |
400 | #3987e5 |
550 | #1c5cab |
| 150 | #b7d3f6 |
300 | #6da7ec |
450 | #2a78d6 |
600 | #184f95 |
| 200 | #9ec5f4 |
350 | #5598e7 |
500 | #256abf |
650 | #104281 |
| 700 | #0d366b |
文档区分了两种用途,这个区分直接决定允许使用的范围:
- Sequential 编码(连续量级——热力图、分级统计图):完整 100→700 范围都可用,最浅步进表示"接近零",允许向表面色退隐;
- Ordinal 色阶(离散有序标记——漏斗阶段、层级,用
--ordinal验证):离表面最近的那步进仍须过 2:1 对比。light 下不浅于 step 250(#86b6ef,实测 2.06:1);dark 下不深于 step 600(#184f95,实测 2.15:1)。
从源码可以印证 ordinal 模式的完整判定集:validate_palette.py 与 validate_palette.js 的 validate_ordinal / validateOrdinal 函数共做四项检查——亮度单调(按 L 排序须与输入顺序或其逆一致)、相邻步进 ΔL ≥ ORDINAL_MIN_DL = 0.06、最浅步进对表面 ≥ ORDINAL_LIGHT_FLOOR = 2.0、单一色相(OKLab 色相展布 ≤ 40°)。文档特别指出:把顺序色阶拿去跑分类六项检查会按设计 FAIL(它横跨亮度带、浅步进会跌破色度地板),这是预期行为而非真实失败,不要为了"修好"而破坏一条好色阶。
发散色对:蓝 ↔ 红,中性中点为灰
发散编码(极性)默认取 blue ↔ red——一暖一冷的两极,读起来天然像"对立面"。中性中点是灰色:light #f0efec、dark #383835,两臂步数相等。文档还记录了被否决的备选:blue↔aqua 因两端都偏冷、中点读不出"零/无"而被拒绝。这也呼应 SKILL.md 的不可协商项:发散色永远是两色相加中性灰中点,永不使用彩虹、也永不在中点放一个色相。
状态色板:固定四档,永不随主题变化
状态色(good/warning/serious/critical)是固定的、从不主题化的,独立于分类色存在:
| role | hex | light 表面对比 | dark 表面对比 |
|---|---|---|---|
| good | #0ca30c |
3.27 | 5.19 |
| warning | #fab219 |
1.79 | 9.49 |
| serious | #ec835a |
2.57 | 6.60 |
| critical | #d03b3b |
4.68 | 3.62 |
设计上分三层考虑:
- 暗色下同四步进:全部 ≥ 3:1 于暗色表面
#1a1a19,且与暗色分类槽位保持可区分; - 浅色下 warning 与 serious 故意低于 3:1:缓解手段是图标 + 标签的强制配对,所以状态色从不单独承载语义;
- 与分类槽位"恰好不同":按系列地板自己的尺子(未模拟 Delta E ≥ 15)量,每种模式下约有 9 组"分类 vs 状态"对低于 15——light 下 red↔critical 与 yellow↔warning 都只有 4.8,slot-2 orange 距 status-serious 5.8,light 的成功文字绿
#006300距系列绿 10.1;green↔status-good 为 9.7,因两个 hex 均不随模式变化,两种模式都保持。也就是说区分度"够用但不够靠色相",通用规则是:任何系列色与同色相族的状态/delta 提示并排时,依赖图标 + 标签与摆放位置,永不依赖色相本身。
纹理填充:可访问性专用通道
纹理通道只用一种手绘 "Lines" 填充,且只允许 45° 及其 135° 镜像两个方向,用填充自身色阶中更深的一档做 tone-on-tone 着墨。在量级色阶上它是有序的:旋转角度随数值步进,臂的角度携带发散的正负号。触发条件只有三类——辅助功能设置开启、打印、forced-colors;它永不做装饰、默认永不开启。
校验器:这些数值是如何算出来的
文档给出了校验器的两个内建默认表面色:
- Light 图表表面:
#fcfcfb - Dark 图表表面:
#1a1a19
换入自己的色板时必须对着自己的表面重跑:--surface <your-light> --mode light 与 --surface <your-dark> --mode dark——对比度和亮度带结果只有相对于图表真实渲染的表面才有意义。
对照仓库源码,参考色板的每一项声称都能落到具体的阈值常量上。validate_palette.js(与 Python 孪生 validate_palette.py 保持同步)中:
const BAND = { light: [0.43, 0.77], dark: [0.48, 0.67] }; // OKLCH L
const CHROMA_FLOOR = 0.10; // OKLCH C
const CVD_TARGET = 8.0, CVD_FLOOR = 6.0; // OKLab ΔE×100, min(protan, deutan)
const NORMAL_FLOOR = 15.0; // 未模拟视觉,当前配对清单上的最差对
const CONTRAST_MIN = 3.0; // WCAG vs surface
const DEFAULT_SURFACE = { light: "#fcfcfb", dark: "#1a1a19" };
CVD 模拟采用的是 Machado, Oliveira & Fernandes (2009) 严重度 1.0 的色盲变换矩阵(validate_palette.js 中的 MACHADO 常量,覆盖 protan/deutan/tritan 三矩阵)。源码注释强调:该模拟模型是标准的一部分而非实现细节——换成例如 Viénot-1999 会使边缘对子的测量值移动,需要重新校准这些阈值。
实际运行 Python 孪生版校验参考色板 light 模式,输出与文档声称一致:
$ python3 Anthropic/claude-code/skills/dataviz/scripts/validate_palette.py \
"#2a78d6,#eb6834,#1baf7a,#eda100,#e87ba4,#008300,#4a3aa7,#e34948" --mode light
Palette (light, surface #fcfcfb, categorical): 8 slots
[PASS] Lightness band all 8 inside L 0.43–0.77
[PASS] Chroma floor all 8 >= 0.1
[PASS] CVD separation worst adjacent #eda100↔#1baf7a ΔE 9.1 (protan) · tritan 5.8
[PASS] Normal-vision floor worst adjacent #e87ba4↔#eda100 ΔE 19.6 (normal)
[WARN] Contrast vs surface below 3:1 — relief required (visible labels or table view):
[["#1baf7a",2.74],["#eda100",2.11],["#e87ba4",2.62]]
→ ALL CHECKS PASS
这正是文档所说的"最坏相邻 CVD ΔE 9.1 light""正常视觉 19.6 light"以及"三个浅色槽位低于 3:1 触发救济规则"的出处。运行注意事项:
- JS 版是 ES module(
export const contrast),直接node validate_palette.js在 CJS 环境会报语法错误;按文件名约定它会作为 CLI 自执行,也可在页面中以<script type="module">引入——此时它读取<body>上的data-palette(以及data-mode/data-surface/data-pairs/data-ordinal)并用console.table输出报告; - Python 版可直接
python3 validate_palette.py "<hex,...>" --mode light|dark [--surface #hex] [--pairs adjacent|all] [--ordinal]; - 退出码:无硬 FAIL 即 0;WARN 带(CVD 6–8 地板带、低于 3:1 的救济带)仍退出 0,但各自只允许在强制二级编码(直接标签、间距或纹理)下合法;正常视觉地板 < 15 是硬门槛,二级编码不能豁免它。
图表墨水与界面色(Chart chrome & ink)
除数据色外,参考实例还完整给出了图表"骨架"的明暗取值:
| Role | Light | Dark |
|---|---|---|
| Chart surface | #fcfcfb |
#1a1a19 |
| Page plane | #f9f9f7 |
#0d0d0d |
| Primary ink | #0b0b0b |
#ffffff |
| Secondary ink | #52514e |
#c3c2b7 |
| Muted (axis/labels) | #898781 |
#898781 |
| Gridline (hairline) | #e1e0d9 |
#2c2c2a |
| Baseline / axis | #c3c2b7 |
#383835 |
| Delta up good (success text) | #006300 |
#0ca30c |
| Border (hairline ring) | rgba(11,11,11,0.10) |
rgba(255,255,255,0.10) |
筛选控件与字体:参考实例的行为规格
筛选控件属于标准 UI 而非图表组件——dataviz 只补充组合规则(详见 interaction.md)。参考规格为:日期范围控件是预设行的列表(today、last 7/30/90 days、month-to-date),选中用 16px 加粗对勾标记,hover 为 ghost wash,自定义范围放在页脚的一条 hairline 之后;维度筛选是标准 combobox。
字体与数字:全部内容——包括 hero 数字——都留在系统无衬线栈:system-ui, -apple-system, "Segoe UI", sans-serif,任何位置不用展示体或衬线体。大号独立数字(hero figure、stat-tile 数值)用默认比例数字;font-variant-numeric: tabular-nums 只保留给必须纵向对齐的列(表格行、轴刻度)。品牌适配时在此处替换成自己的 UI sans。
替换为品牌色板时的操作要点
把这份参考实例换成品牌色板,全部动作收敛为四步:
- 只改 palette.md 这一文件里的取值(分类 8 槽、顺序色阶、发散对、状态色、纹理、表面、墨水),方法与结构不动;
- 槽位顺序不要猜:枚举候选顺序,对每条跑校验器,只从通过者中选(color-formula.md 的 snap-to-passing 流程:每个槽取落在该模式亮度带内且 C ≥ 0.10 的步进,相邻对 ΔE < 8 时保持色相、只动亮度再跑);
- 对着自己的表面重跑:
--surface <your-light> --mode light与--surface <your-dark> --mode dark,散点/气泡/地图/small multiples 加--pairs all,序级色阶加--ordinal; - 任一 WARN 都须落实对应缓解(CVD 6–8 带 → 二级编码;低于 3:1 → 可见标签或表格视图),WARN 不可忽略,也不可用"换个图就没事了"绕过。
这套参考色板的价值不在于某个具体 hex,而在于它示范了"一份色板如何变成一组可计算、可复验、可替换的参数":同样的检查,任何设计系统都跑得动。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00