D3.js - 比例尺 API
D3.js - 比例尺 API (d3-scale)
Section titled “D3.js - 比例尺 API (d3-scale)”比例尺(Scales)是 D3.js 的基石,它提供的函数可以将输入数据域(Domain)(你的数据值,例如 0 到 100)映射到输出范围(Range)(视觉值,例如 0 到 500 像素,或一组颜色)。这种转换对于将数据适配到 SVG 画布等视觉媒介至关重要。d3-scale 模块提供了各种类型的比例尺。
设置 D3.js
Section titled “设置 D3.js”要使用 D3.js 比例尺 API,需要包含主 D3.js 库,其中包含 d3-scale 模块及其依赖项,如 d3-array、d3-interpolate 等。
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>D3.js Scales Example</title> <script src="https://d3js.org/d3.v7.min.js"></script> </head> <body> <svg id="chart" width="500" height="150"></svg> <script> // Your D3.js code using scales will go here </script> </body></html>理解数据域和范围
Section titled “理解数据域和范围”- 数据域(Domain): 数据域定义了输入数据值的范围。对于定量数据,它通常是两个数字构成的数组
[min, max]。对于定性数据,它是一个包含不同类别名称的数组["A", "B", "C"]。 - 范围(Range): 范围定义了输出视觉值的范围。对于定位,它可能是
[0, width]或[height, 0](用于 y 轴)。对于颜色,它可能是一个数组["red", "blue"]或一组颜色代码。
常见的比例尺类型和方法
Section titled “常见的比例尺类型和方法”D3 为不同的数据特征和视觉映射提供了几种类型的比例尺:
这些比例尺将连续的、定量的输入数据域映射到连续的输出范围。
d3.scaleLinear(): 构造一个线性比例尺。它是定量数据最常用的比例尺,输入和输出之间呈线性关系。scale(value)返回映射后的值。.domain([min, max]): 设置输入数据域。.range([start, end]): 设置输出范围。.invert(value): 返回对应于某个输出范围值的输入数据域值(反向映射)。.nice(): 将数据域扩展到更容易理解的整数或 round 值。d3.scalePow(): 一个幂次比例尺(output = m * input^k + b)。使用.exponent(k)设置幂次。d3.scaleSqrt(): 一个平方根比例尺(相当于d3.scalePow().exponent(0.5))。d3.scaleLog(): 一个对数比例尺。当数据量级变化很大时非常有用。.base(b): 设置对数底(默认为 10)。d3.scaleTime(): 用于时间数据(JavaScriptDate对象)的线性比例尺。d3.scaleSequential(interpolator): 将连续的数据域(通常是[0, 1])映射到由插值器(interpolator)函数定义的范围(例如,d3.interpolateViridis用于颜色方案)。
定性比例尺和带状比例尺
Section titled “定性比例尺和带状比例尺”这些比例尺将离散的输入数据域(类别)映射到离散或连续的输出范围。
d3.scaleOrdinal(): 将离散的数据域映射到离散的范围(例如,将类别名称映射到颜色)。如果范围的值少于数据域,它会重复使用。.domain(["A", "B", "C"]).range(["red", "green", "blue"])或d3.schemeCategory10(一个包含 10 种分类颜色的数组)。d3.scaleBand(): 用于定性数据,其输出范围是连续且数值型的,通常用于条形图。它将范围分割成均匀的条带(bands)。.domain(["A", "B", "C"]).range([0, width]).padding(value): 设置条带之间的填充(padding)(值在 0 到 1 之间)。scale.bandwidth(): 返回每个条带的宽度。d3.scalePoint(): 类似于scaleBand,但用于点标记(例如,坐标轴上的刻度线)。bandwidth()始终为 0。
分段比例尺和分位数比例尺
Section titled “分段比例尺和分位数比例尺”这些比例尺将连续的输入数据域映射到离散的输出范围(例如,用于分级统计地图 choropleth maps)。
d3.scaleQuantize(): 将连续的数据域划分为均匀的段,并将其映射到范围中的离散值。.domain([0, 100]).range(["low", "medium", "high"])d3.scaleQuantile(): 根据样本分位数将连续的数据域映射到离散范围。值根据其在输入数据中的排名被分配到范围内的各个桶(buckets)。d3.scaleThreshold(): 根据指定的阈值将任意连续数据域子集映射到离散范围值。
工作示例:d3.scaleLinear()
Section titled “工作示例:d3.scaleLinear()”让我们使用 d3.scaleLinear() 创建一个简单的条形图,将数据值映射到条的宽度。
步骤 1:定义数据和 SVG 尺寸。
const data = [100, 200, 50, 300, 150];const svgWidth = 500;const barHeight = 20;const barMargin = 1; // 条之间的边距const svgHeight = (barHeight + barMargin) * data.length;步骤 2:创建线性比例尺。
const xScale = d3.scaleLinear() .domain([0, d3.max(data)]) // 输入数据:0 到数据中的最大值 .range([0, svgWidth]); // 输出:0 到 SVG 宽度,用于条的长度这里,d3.min(data) 和 d3.max(data)(来自 d3-array)用于查找数据域边界很方便。我们将 0 用作数据域的最小值,这在条形图通常从零基线开始时很常见。
步骤 3:设置 SVG 画布。
const svg = d3.select("#chart") // 假设 <svg id="chart"> 存在 .attr("width", svgWidth) .attr("height", svgHeight);步骤 4:为每个条创建分组并应用变换。
const barGroups = svg.selectAll("g") .data(data) .enter() .append("g") .attr("transform", (d, i) => `translate(0, ${i * (barHeight + barMargin)})`);步骤 5:为条添加 <rect> 元素,使用比例尺确定宽度。
barGroups.append("rect") .attr("width", d => xScale(d)) // 在这里使用比例尺! .attr("height", barHeight) .attr("fill", "steelblue");步骤 6:为标签添加 <text> 元素,也使用比例尺定位。
barGroups.append("text") .attr("x", d => xScale(d) + 5) // 将文本定位在条的末端稍微靠后的位置 .attr("y", barHeight / 2) .attr("dy", ".35em") // 垂直对齐 .text(d => d) .attr("fill", "black");完整的示例 HTML:
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>D3.js scaleLinear Example</title> <script src="https://d3js.org/d3.v7.min.js"></script> <style> #chart text { font-size: 10px; font-family: sans-serif; } </style> </head> <body> <svg id="chart"></svg> <script> const data = [100, 200, 50, 300, 150]; const svgWidth = 500; const barHeight = 20; const barMargin = 1; const svgHeight = (barHeight + barMargin) * data.length;
const xScale = d3.scaleLinear() .domain([0, d3.max(data)]) .range([0, svgWidth]);
const svg = d3.select("#chart") .attr("width", svgWidth) .attr("height", svgHeight);
const barGroups = svg.selectAll("g") .data(data) .enter() .append("g") .attr("transform", (d, i) => `translate(0, ${i * (barHeight + barMargin)})`);
barGroups.append("rect") .attr("width", d => xScale(d)) .attr("height", barHeight) .attr("fill", "steelblue");
barGroups.append("text") .attr("x", d => xScale(d) + 5) .attr("y", barHeight / 2) .attr("dy", ".35em") .text(d => d) .attr("fill", "black"); </script> </body></html>在浏览器中打开时,此代码将显示一个水平条形图,其中每个条的长度与其数据值成比例,并根据 SVG 宽度进行缩放。文本标签将显示每个条旁边的原始数据值。