ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

OpenMontage D3.js 比例尺(Scale)全参考:从连续映射到颜色编码的完整实战指南

OpenMontage D3.js 比例尺(Scale)全参考:从连续映射到颜色编码的完整实战指南 OpenMontage D3.js 比例尺Scale全参考从连续映射到颜色编码的完整实战指南【免费下载链接】OpenMontageWorlds first open-source, agentic video production system. 12 production pipelines, 100 tools, 700 agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage本篇指南以 OpenMontage 仓库中 d3-viz 技能的 scale-reference.md 为骨架系统梳理 D3.js 全部比例尺类型连续比例尺linear / power / log / time、分箱比例尺quantize / quantile / threshold、颜色比例尺sequential / diverging / sequentialQuantile、序数比例尺band / point / ordinal以及.nice()、.clamp()、.ticks()等实用工具与颜色插值空间。读完你将能够为任意数据集选择合适的比例尺写出坐标轴、柱状图、散点图、热力图和等值区域图choropleth中最核心的「数据→像素」映射代码。什么是 D3 比例尺一切可视化的第一块基石D3.jsData-Driven Documents的核心思想是把数据绑定到 DOM 元素并对元素施加数据驱动的变换。而**比例尺scale**正是数据值与视觉值之间那座桥它把抽象的输入域domain如温度 0100映射到具体的输出范围range如屏幕像素 0500是坐标轴、条长、圆半径、颜色深浅等一切位置/大小/颜色编码的基础。在 OpenMontage 中d3-viz 技能见 SKILL.md被设计为「创建自定义图表、网络图、地理可视化或任何需要精细控制视觉元素的 SVG 可视化」时使用可嵌入 React、Vue、Svelte 或原生 JavaScript 环境。配套的资源体系包括scale-reference.md本文讲解的完整比例尺参考d3-patterns.md树图、热力图、弦图、地理可视化等完整模式colour-schemes.md颜色方案与调色板推荐chart-template.jsx 与 interactive-template.jsx可直接运行的 React 模板sample-data.json时间序列、类别、散点、层级、网络等六类测试数据集。下文将按「连续 → 颜色 → 序数 → 工具 → 插值 → 组合模式」的顺序完整展开。连续比例尺把连续数值映射到连续视觉通道连续比例尺负责把连续输入域映射到连续输出范围是量化数据可视化中使用最频繁的一族。Linear scale最通用的定量比例尺d3.scaleLinear()以线性插值方式把连续输入域映射到连续输出范围OpenMontage 的 d3-viz 技能将其列为「大多数定量数据的首选」。const scale d3.scaleLinear() .domain([0, 100]) .range([0, 500]); scale(50); // Returns 250 scale(0); // Returns 0 scale(100); // Returns 500 // Invert scale (get input from output) scale.invert(250); // Returns 50适用场景定量数据最常用的比例尺坐标轴、柱条长度、位置编码温度、价格、计数、测量值核心方法.domain([min, max])— 设置输入域.range([min, max])— 设置输出范围.invert(value)— 由范围值反推域值.clamp(true)— 将输出限制在范围内.nice()— 将定义域扩展到整洁的取整值一个值得注意的细节当range使用字符串颜色时linear scale 默认执行 RGB 插值详见后文「颜色空间与插值」这使它同时能充当最简单的连续色标。Power scale非线性感知缩放d3.scalePow()以指数变换处理连续映射通过.exponent()控制非线性程度d3.scaleSqrt()则是指数为 0.5 的简写形式const sqrtScale d3.scalePow() .exponent(0.5) // Square root .domain([0, 100]) .range([0, 500]); const squareScale d3.scalePow() .exponent(2) // Square .domain([0, 100]) .range([0, 500]); // Shorthand for square root const sqrtScale2 d3.scaleSqrt() .domain([0, 100]) .range([0, 500]);适用场景感知缩放人类感知本身就是非线性的面积编码用平方根把数值映射为圆的半径避免面积被高估强调小值或大值之间的差异Logarithmic scale跨越多个数量级的数据d3.scaleLog()以对数变换处理连续映射非常适合人口、GDP、财富分布这类跨越多个数量级的数据const logScale d3.scaleLog() .domain([1, 1000]) // Must be positive .range([0, 500]); logScale(1); // Returns 0 logScale(10); // Returns ~167 logScale(100); // Returns ~333 logScale(1000); // Returns 500适用场景跨越多个数量级的数据人口、GDP、财富分布对数坐标轴指数增长可视化重要约束域值必须严格为正0。从代码实现角度看scaleLinear内部存储domain与range两个数组求值时先做双线性归一化再做线性插值scaleLog则先把 domain 映射为Math.log10再走同一套插值管线。理解这一共性后你可以在需要时自行组合interpolate函数替换默认插值器详见后文。Time scale时间序列的专用线性比例尺d3.scaleTime()是专为时间数据定制的线性比例尺域由Date对象组成const timeScale d3.scaleTime() .domain([new Date(2020, 0, 1), new Date(2024, 0, 1)]) .range([0, 800]); timeScale(new Date(2022, 0, 1)); // Returns 400 // Invert to get date timeScale.invert(400); // Returns Date object for mid-2022适用场景时间序列可视化时间线坐标轴时间驱动的动画基于日期的交互方法.nice()— 将域扩展到整洁的时间间隔.ticks(count)— 生成间隔均匀的刻度值所有 linear scale 的方法同样适用Quantize scale连续输入 → 离散输出桶d3.scaleQuantize()把连续输入映射到离散输出桶输入域被等分成range.length段每段对应一个输出值const quantizeScale d3.scaleQuantize() .domain([0, 100]) .range([low, medium, high]); quantizeScale(25); // Returns low quantizeScale(50); // Returns medium quantizeScale(75); // Returns high // Get the threshold values quantizeScale.thresholds(); // Returns [33.33, 66.67]适用场景连续数据分箱热力图颜色风险等级低/中/高年龄段、收入区间Quantile scale按分位数分组d3.scaleQuantile()根据样本数据的分位数把连续输入映射为离散输出其特点是每组元素数量大致相等不受分布形态影响const quantileScale d3.scaleQuantile() .domain([3, 6, 7, 8, 8, 10, 13, 15, 16, 20, 24]) // Sample data .range([low, medium, high]); quantileScale(8); // Returns based on quantile position quantileScale.quantiles(); // Returns quantile thresholds适用场景与分布无关的等量分组基于百分位的分类处理偏态分布Threshold scale自定义断点的分箱d3.scaleThreshold()用自定义阈值把连续输入映射为离散输出。注意其规律域中 n 个阈值把数轴切成 n1 段因此range长度总是domain.length 1const thresholdScale d3.scaleThreshold() .domain([0, 10, 20]) .range([freezing, cold, warm, hot]); thresholdScale(-5); // Returns freezing thresholdScale(5); // Returns cold thresholdScale(15); // Returns warm thresholdScale(25); // Returns hot适用场景自定义断点成绩等级A、B、C、D、F温度类别空气质量指数顺序Sequential颜色比例尺连续值 → 连续色带顺序颜色比例尺把连续输入映射为连续颜色渐变是热力图、等值区域图、密度图的核心编码手段。Sequential colour scaleconst colourScale d3.scaleSequential(d3.interpolateBlues) .domain([0, 100]); colourScale(0); // Returns lightest blue colourScale(50); // Returns mid blue colourScale(100); // Returns darkest blue可用插值器单色相Single hued3.interpolateBlues、d3.interpolateGreens、d3.interpolateRedsd3.interpolateOranges、d3.interpolatePurples、d3.interpolateGreys多色相Multi-hued3.interpolateViridis、d3.interpolateInferno、d3.interpolateMagmad3.interpolatePlasma、d3.interpolateWarm、d3.interpolateCoold3.interpolateCubehelixDefault、d3.interpolateTurbo适用场景热力图、等值区域图choropleth map连续数据可视化温度、海拔、密度补充说明根据同技能包的 colour-schemes.mdinterpolateViridis被推荐为通用首选——它感知均匀、对色盲友好、可安全打印且没有视觉死区每个连续插值器都有对应的 9 步离散版本例如d3.schemeBlues[9]可配合 quantize/threshold 使用。Diverging colour scale带中点的发散色带d3.scaleDiverging()把连续输入映射为以中点为对称的发散渐变用于表达「围绕某个有意义的中点零、均值、中性值偏离」的语义const divergingScale d3.scaleDiverging(d3.interpolateRdBu) .domain([-10, 0, 10]); divergingScale(-10); // Returns red divergingScale(0); // Returns white/neutral divergingScale(10); // Returns blue可用插值器d3.interpolateRdBu— 红到蓝d3.interpolateRdYlBu— 红、黄、蓝d3.interpolateRdYlGn— 红、黄、绿d3.interpolatePiYG— 粉、黄、绿d3.interpolateBrBG— 棕、蓝绿d3.interpolatePRGn— 紫、绿d3.interpolatePuOr— 紫、橙d3.interpolateRdGy— 红、灰d3.interpolateSpectral— 彩虹光谱适用场景具有语义中点的数据零、均值、中性值正负值对比高于/低于基准的比较相关性矩阵domain传入三个值[min, midpoint, max]中点对应的插值位置是 0.5即色带中央颜色非常适合表达盈亏、偏差与相关性。colour-schemes.md 还提醒在做正负对比时若无特殊语义要求优先用蓝-橙BrBG、PuOr替代红-绿以规避色盲问题。Sequential quantile scale顺序色 × 分位数d3.scaleSequentialQuantile()把顺序色与分位数映射结合它从样本域自动计算分位断点再按分位位置分配颜色天然抗离群值与偏态分布const sequentialQuantileScale d3.scaleSequentialQuantile(d3.interpolateBlues) .domain([3, 6, 7, 8, 8, 10, 13, 15, 16, 20, 24]); // Maps based on quantile position适用场景感知均匀的分箱处理离群值偏态分布序数Ordinal比例尺离散类别 → 位置或颜色序数比例尺处理离散类别输入是柱状图、散点图类别轴、图例与多系列图表的基石。Band scale为柱状图而生d3.scaleBand()把离散输入映射为连续的「带」矩形支持内/外间距配置const bandScale d3.scaleBand() .domain([A, B, C, D]) .range([0, 400]) .padding(0.1); bandScale(A); // Returns start position (e.g., 0) bandScale(B); // Returns start position (e.g., 110) bandScale.bandwidth(); // Returns width of each band (e.g., 95) bandScale.step(); // Returns total step including padding bandScale.paddingInner(); // Returns inner padding (between bands) bandScale.paddingOuter(); // Returns outer padding (at edges)适用场景柱状图最常见的用法分组元素类别坐标轴热力图单元格间距选项.padding(value)— 同时设置内、外间距0-1.paddingInner(value)— 带与带之间的间距0-1.paddingOuter(value)— 边缘间距0-1.align(value)— 带的对齐方式0-1默认 0.5bandwidth()与step()的区别值得强调step bandwidth paddingInner × step绘制rect宽度时务必使用bandwidth()而不是step()。Point scale类别位置的锚点d3.scalePoint()把离散输入映射为连续的点位置没有宽度是折线图类别横轴、散点图类别轴与网络图节点定位的标准选择const pointScale d3.scalePoint() .domain([A, B, C, D]) .range([0, 400]) .padding(0.5); pointScale(A); // Returns position (e.g., 50) pointScale(B); // Returns position (e.g., 150) pointScale(C); // Returns position (e.g., 250) pointScale(D); // Returns position (e.g., 350) pointScale.step(); // Returns distance between points适用场景折线图的类别横轴带类别轴的散点图网络图中的节点位置任何类别的点定位Ordinal colour scale类别 → 离散颜色d3.scaleOrdinal()把离散输入映射为离散输出颜色、形状等。其确定性映射保证同一类别始终得到同一颜色const colourScale d3.scaleOrdinal(d3.schemeCategory10); colourScale(apples); // Returns first colour colourScale(oranges); // Returns second colour colourScale(apples); // Returns same first colour (consistent) // Custom range const customScale d3.scaleOrdinal() .domain([cat1, cat2, cat3]) .range([#FF6B6B, #4ECDC4, #45B7D1]);内置颜色方案Categorical分类d3.schemeCategory10— 10 色d3.schemeAccent— 8 色d3.schemeDark2— 8 色d3.schemePaired— 12 色d3.schemePastel1— 9 色d3.schemePastel2— 8 色d3.schemeSet1— 9 色d3.schemeSet2— 8 色d3.schemeSet3— 12 色d3.schemeTableau10— 10 色适用场景类别颜色图例项多系列图表网络节点类型colour-schemes.md 补充了选型建议一般用途默认schemeCategory10仪表盘/商业报告可选schemeTableau10超过 10 个类别时优先schemePaired12 色或对类别分组而不是堆更多颜色。比例尺工具nice、clamp、copy 与刻度生成所有比例尺都共享一组实用工具方法本节完整列出。Nice domain扩展到整洁值.nice()将 domain 扩展到「好看的」取整值让坐标轴刻度更易读const scale d3.scaleLinear() .domain([0.201, 0.996]) .nice(); scale.domain(); // Returns [0.2, 1.0] // With count (approximate tick count) const scale2 d3.scaleLinear() .domain([0.201, 0.996]) .nice(5);可选参数count给出近似刻度数提示scaleTime().nice()则会扩展到整洁的时间间隔。Clamping限制输出边界.clamp(true)把超出域的输出严格限制在 range 范围内防止散点或柱条溢出绘图区const scale d3.scaleLinear() .domain([0, 100]) .range([0, 500]) .clamp(true); scale(-10); // Returns 0 (clamped) scale(150); // Returns 500 (clamped)Copy独立副本.copy()返回与原比例尺互不影响的副本方便基于同一配置派生多个变体const scale1 d3.scaleLinear() .domain([0, 100]) .range([0, 500]); const scale2 scale1.copy(); // scale2 is independent of scale1Tick generation坐标轴刻度.ticks()生成整洁的刻度值.tickFormat()返回对应的格式化函数二者可直接喂给d3.axisBottom()/d3.axisLeft()使用const scale d3.scaleLinear() .domain([0, 100]) .range([0, 500]); scale.ticks(10); // Generate ~10 ticks scale.tickFormat(10); // Get format function for ticks scale.tickFormat(10, .2f); // Custom format (2 decimal places) // Time scale ticks const timeScale d3.scaleTime() .domain([new Date(2020, 0, 1), new Date(2024, 0, 1)]); timeScale.ticks(d3.timeYear); // Yearly ticks timeScale.ticks(d3.timeMonth, 3); // Every 3 months timeScale.tickFormat(5, %Y-%m); // Format as year-month时间比例尺的ticks()可接受d3.timeYear、d3.timeMonth等时间间隔对象tickFormat支持%Y-%m这类 d3-time-format 语法。颜色空间与插值RGB、HSL、Lab、HCL连续比例尺尤其是 linear scale的颜色插值方式可以通过.interpolate()切换不同颜色空间影响过渡的「质感」const scale d3.scaleLinear() .domain([0, 100]) .range([blue, red]); // Default: RGB interpolationconst scale d3.scaleLinear() .domain([0, 100]) .range([blue, red]) .interpolate(d3.interpolateHsl); // Smoother colour transitionsconst scale d3.scaleLinear() .domain([0, 100]) .range([blue, red]) .interpolate(d3.interpolateLab); // Perceptually uniformconst scale d3.scaleLinear() .domain([0, 100]) .range([blue, red]) .interpolate(d3.interpolateHcl); // Perceptually uniform with hueRGB默认分量线性插值简单直接但中间色可能发灰、不够「干净」HSL按色相角走捷径过渡更平滑但可能产生意外的色相环绕Lab感知均匀中间色符合人眼亮度感知适合追求专业过渡的场合HCL感知均匀且保留色相维度是多色相渐变的首选。在自定义发散/顺序渐变时colour-schemes.md 中的做法也是同样的思路d3.scaleLinear().range([...]).interpolate(d3.interpolateLab)即可得到感知均匀的自定义渐变。常见组合模式把比例尺用出生产力本节是原文档的精华实战部分——六个高频组合模式完整保留。自定义中点的发散比例尺const scale d3.scaleLinear() .domain([min, midpoint, max]) .range([red, white, blue]) .interpolate(d3.interpolateHcl);多段渐变比例尺const scale d3.scaleLinear() .domain([0, 25, 50, 75, 100]) .range([#d53e4f, #fc8d59, #fee08b, #e6f598, #66c2a5]);圆的半径比例尺感知正确const radiusScale d3.scaleSqrt() .domain([0, d3.max(data, d d.value)]) .range([0, 50]); // Use with circles circle.attr(r, d radiusScale(d.value));注意这里刻意使用scaleSqrt而不是scaleLinear圆的面积与r²成正比直接用线性比例尺会让大值圆显得「过大」。d3-patterns.md 的 Bubble chart 模式sizeScale d3.scaleSqrt().domain([0, d3.max(data, d d.size)]).range([0, 50])印证了这一约定。基于数据范围的自适应比例尺function createAdaptiveScale(data) { const extent d3.extent(data); const range extent[1] - extent[0]; // Use log scale if data spans 2 orders of magnitude if (extent[1] / extent[0] 100) { return d3.scaleLog() .domain(extent) .range([0, width]); } // Otherwise use linear return d3.scaleLinear() .domain(extent) .range([0, width]); }d3.extent()一次性取回数据的最小值与最大值配合比值判断跨度超过两个数量级时切换为 log即可实现通用自适应。colour-schemes.md 中还有类似的按数据正负动态选择 diverging/sequential 的写法可与本模式结合。带显式类别与未知值回退的颜色比例尺const colourScale d3.scaleOrdinal() .domain([Low Risk, Medium Risk, High Risk]) .range([#2ecc71, #f39c12, #e74c3c]) .unknown(#95a5a6); // Fallback for unknown values.unknown()为未出现在 domain 中的输入提供回退色如灰色「缺数据」避免空值产生undefined或错误颜色。项目侧印证从 D3 比例尺到 Remotion 图表组件OpenMontage 的视频渲染侧remotion-composer提供了不依赖 D3 的图表组件BarChart、LineChart、PieChart、KPIGrid见 charts 目录。对照 BarChart.tsx 的实现可以看到本文所述比例尺思想的「手工版」以const maxValue Math.max(...data.map((d) d.value), 1);求出数据极值等价于d3.max()与.domain([0, max])用barHeightFull (datum.value / maxValue) * chartHeight做线性归一化等价于scaleLinear().domain([0, max]).range([0, chartHeight])网格线通过value (maxValue / gridLineCount) * i均分生成等价于scale.ticks(5)柱宽由barGap、barCount与可用宽度均摊等价于scaleBand().paddingInner()。这说明两件事其一掌握比例尺的本质归一化 插值后即使在没有 D3 的渲染环境如 Remotion 的逐帧渲染管线里也能手动复现同样的编码逻辑其二在需要交互、缩放、复杂布局或颜色插值的自定义可视化中直接用 D3 比例尺仍是生产力最高的路径——这正是 d3-viz 技能及其 scale-reference.md 存在的意义。实战速查与总结按需求快速选型你的数据推荐比例尺定量数据 → 位置/长度scaleLinear配.nice()、.clamp()圆面积/感知缩放scaleSqrt或scalePow跨数量级数据scaleLogdomain 必须 0时间序列scaleTime配ticks(d3.timeMonth)连续值 → 少数几个桶scaleQuantize/scaleThreshold等量分组/抗偏态scaleQuantile连续值 → 色带scaleSequential(interpolateViridis)正负发散含中点scaleDiverging(interpolateRdBu)类别 → 柱条scaleBand用bandwidth()设宽类别 → 点/折线轴scalePoint类别 → 颜色scaleOrdinal(schemeCategory10)最后的工程建议综合本参考与 colour-schemes.md先想清楚「输入是什么、输出编码什么通道」再在连续/序数/颜色三大族中定位坐标轴一律用.ticks().tickFormat()生成需要颜色渐变时优先感知均匀的 Viridis/Cividis 或 Lab/HCL 插值涉及色觉障碍用户时避免红-绿组合并叠加形状、图案、标签等多重编码。掌握本文全部比例尺及其方法你就能从数据直达像素写出清晰、准确且专业的 D3 可视化。【免费下载链接】OpenMontageWorlds first open-source, agentic video production system. 12 production pipelines, 100 tools, 700 agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表