比例尺与坐标轴
比例尺(Scale)是 D3 中将**数据域(domain)映射到视觉范围(range)**的核心工具。坐标轴(Axis)则是比例尺的可视化表达。
1. 比例尺体系
图表渲染中…
2. 连续型比例尺
2.1 scaleLinear(线性)
最常用的比例尺,数据与视觉呈线性关系。
javascript
import { scaleLinear } from 'd3'
const yScale = scaleLinear()
.domain([0, 100]) // 数据范围
.range([400, 0]) // 像素范围(SVG y 轴向下,所以反转)
yScale(0) // → 400(底部)
yScale(50) // → 200(中间)
yScale(100) // → 0(顶部)
// 反向映射:像素 → 数据
yScale.invert(200) // → 50常用配置:
javascript
const scale = scaleLinear()
.domain([0, 100])
.range([0, 600])
.clamp(true) // 超出 domain 时截断到 range 边界
.nice() // 将 domain 扩展到"好看"的整数边界
.interpolate(d3.interpolateRound) // 输出整数像素2.2 scaleTime(时间)
javascript
import { scaleTime, timeMonth, timeFormat } from 'd3'
const xScale = scaleTime()
.domain([new Date(2024, 0, 1), new Date(2024, 11, 31)])
.range([0, 800])
xScale(new Date(2024, 5, 15)) // → 约 397(年中)
// 生成刻度(每月一个)
xScale.ticks(timeMonth) // [Jan, Feb, Mar, ...]2.3 scaleLog(对数)
适用于跨数量级的数据(如人口、收入)。
javascript
import { scaleLog } from 'd3'
const scale = scaleLog()
.domain([1, 10000])
.range([0, 400])
scale(1) // → 0
scale(10) // → 100
scale(100) // → 200
scale(1000) // → 300
scale(10000) // → 400domain 不能包含 0
对数比例尺的 domain 不能包含 0(log(0) = -∞)。如果数据有 0 值,使用 scaleSymlog()。
3. 离散型比例尺
3.1 scaleBand(带状)
柱状图的标准选择,将离散类目映射为等宽带状区域。
javascript
import { scaleBand } from 'd3'
const xScale = scaleBand()
.domain(['React', 'Vue', 'Angular', 'Svelte'])
.range([0, 600])
.padding(0.2) // 带宽的 20% 作为间距
// .paddingInner(0.2) // 仅内部间距
// .paddingOuter(0.1) // 仅外部间距
xScale('Vue') // → 150(该类目起始 x)
xScale.bandwidth() // → 120(每个柱子的宽度)
xScale.step() // → 150(带宽 + 间距)图表渲染中…
3.2 scalePoint(点)
折线图/散点图的 x 轴,将类目映射为点位置。
javascript
import { scalePoint } from 'd3'
const xScale = scalePoint()
.domain(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
.range([0, 500])
.padding(0.5)
xScale('Wed') // → 250(中间点)
xScale.step() // → 100(点间距)3.3 scaleOrdinal(序数)
将离散输入映射到离散输出(常用于颜色)。
javascript
import { scaleOrdinal, schemeCategory10 } from 'd3'
const colorScale = scaleOrdinal()
.domain(['A', 'B', 'C', 'D'])
.range(['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4'])
colorScale('A') // → '#ff6b6b'
colorScale('B') // → '#4ecdc4'
// 使用内置配色方案
const color10 = scaleOrdinal(schemeCategory10)4. 序列型比例尺(颜色映射)
4.1 scaleSequential
将连续数据映射到颜色渐变。
javascript
import { scaleSequential, interpolateViridis } from 'd3'
const colorScale = scaleSequential()
.domain([0, 100])
.interpolator(interpolateViridis)
colorScale(0) // → 深紫色
colorScale(50) // → 青绿色
colorScale(100) // → 黄色4.2 scaleQuantize(量化)
将连续域切分为有限个离散输出。
javascript
import { scaleQuantize } from 'd3'
const scale = scaleQuantize()
.domain([0, 100])
.range(['#fee', '#fcc', '#f99', '#f66', '#f33'])
scale(10) // → '#fee'
scale(90) // → '#f33'5. 坐标轴
5.1 创建坐标轴
javascript
import { axisBottom, axisLeft, axisRight, axisTop } from 'd3'
// 底部 x 轴
const xAxis = axisBottom(xScale)
.ticks(10) // 刻度数量(建议值)
.tickFormat(d3.format('.0f')) // 刻度格式化
.tickSize(6) // 刻度线长度
.tickPadding(8) // 文字与刻度线间距
// 左侧 y 轴
const yAxis = axisLeft(yScale)
.ticks(5)
.tickFormat(d => `${d}%`)
// 渲染到 SVG
svg.append('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0,${height})`)
.call(xAxis)
svg.append('g')
.attr('class', 'y-axis')
.call(yAxis)5.2 时间轴格式化
javascript
import { timeFormat, timeMonth } from 'd3'
const xAxis = axisBottom(xTimeScale)
.ticks(timeMonth.every(2)) // 每 2 个月一个刻度
.tickFormat(timeFormat('%Y-%m')) // 格式:2024-065.3 自定义坐标轴样式
javascript
// 移除轴线
svg.select('.x-axis .domain').remove()
// 虚线网格线
svg.select('.y-axis')
.call(axisLeft(yScale)
.tickSize(-width) // 负值 = 横跨整个图表
.tickFormat('') // 隐藏文字
)
.selectAll('line')
.attr('stroke', '#e0e0e0')
.attr('stroke-dasharray', '3,3')
// 隐藏刻度线
svg.select('.y-axis .domain').remove()5.4 坐标轴过渡动画
javascript
// 数据更新时平滑过渡坐标轴
function updateChart(newData) {
yScale.domain([0, d3.max(newData, d => d.value)]).nice()
svg.select('.y-axis')
.transition()
.duration(750)
.call(axisLeft(yScale))
}6. 比例尺选型指南
| 图表类型 | x 轴比例尺 | y 轴比例尺 |
|---|---|---|
| 柱状图 | scaleBand | scaleLinear |
| 折线图 | scaleTime / scalePoint | scaleLinear |
| 散点图 | scaleLinear | scaleLinear |
| 面积图 | scaleTime | scaleLinear |
| 饼图/环形图 | 不需要(用 arc 生成器) | 不需要 |
| 热力图 | scaleBand | scaleBand |
| 气泡图 | scaleLinear | scaleLinear |
| 雷达图 | scaleLinear(径向) | scalePoint(角度) |
7. 最佳实践
始终调用 .nice()
javascript
yScale.domain([0, maxValue]).nice()
// 将 [0, 97] 扩展为 [0, 100],刻度更美观颜色比例尺使用内置方案
D3 提供 schemeCategory10、interpolateViridis、interpolatePlasma 等经过色彩学验证的方案,避免自行配色。
注意 range 方向
SVG 坐标系 y 轴向下,因此 y 比例尺的 range 通常是 [height, 0](反转),使数据越大位置越高。