首页
/ D3 中 d3-array 刻度(Ticks)API 详解:ticks、tickStep、nice 与 range 的完整使用指南

D3 中 d3-array 刻度(Ticks)API 详解:ticks、tickStep、nice 与 range 的完整使用指南

2026-09-05 22:25:59作者:郁楠烈Hubert

本文围绕 d3 官方文档 docs/d3-array/ticks.md 展开,系统讲解 d3-array 提供的五个刻度相关 API:d3.ticksd3.tickIncrementd3.tickStepd3.niced3.range。读完本文,你将理解 d3 如何为连续数值区间生成"整齐、等距、数量约可控"的刻度值,掌握 tickIncrement 返回负逆步长的 IEEE 754 精度设计意图,并知道如何把这些函数与 d3-scale 线性比例尺d3-axis 坐标轴d3-format 组合,产出可直接用于图表的刻度与标签。

概览:这组 API 解决什么问题

在图表中,给定数据区间(如坐标轴域 [1, 9]),我们需要一组"好看的"刻度值:等距、数量接近期望值、且为人类友好的整数或半整数。d3-array 把这组能力拆成两个正交的函数族:

  • 刻度生成族d3.ticks 返回刻度值数组;d3.tickStep 返回相邻刻度的步长;d3.tickIncrement 是步长的整数化变体(供高精度内部计算使用)。
  • 区间扩展族d3.nice 把一个任意区间向外扩成与刻度步长对齐的"整齐"区间。
  • 等差数列族d3.range 生成等差序列,类似 Python 内置 range,常用于索引遍历或按固定步长取样。

src/index.js 可以看到,d3 主包以 export * from "d3-array" 的方式重导出 d3-array 的全部 API,因此上述函数在 d3 主包中均以 d3. 前缀直接可用;package.json 中声明的依赖为 d3-array: ^3.2.4test/d3-test.js 中的测试还保证了 d3 主包重导出每个子模块(包括 d3-array)的每一个导出,因此 d3.ticksd3.nice 等入口与子模块一一对应。

d3.ticks(start, stop, count)

返回一个数组,包含 startstop 之间(含两端,视情况)大约 count + 1 个等距、整齐取整的值。每个刻度值都是 10 的某次幂乘以 1、2 或 5:

d3.ticks(1, 9, 5) // [2, 4, 6, 8]
d3.ticks(1, 9, 20) // [1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9]

两个要点值得注意:

  1. 数量是"约 count + 1"。d3 不保证恰好 count + 1 个值,而是在"整齐步长"与"期望密度"之间取平衡:第一个例子 count 为 5 只返回 4 个值,第二个例子 count 为 20 返回 17 个值。
  2. 端点是条件包含的。原文档的表述是:ticks 是 inclusive 的,即"仅当 startstop 本身是与推断出的 tickStep 一致的精确整齐值时,才可能包含在结果中"。更严格地说,每个返回的刻度 t 都满足 startttstop。在上例中 19 恰好是 0.5 步长的整齐刻度,所以都被包含;若端点是 1.2、9.7 这类值,则不会出现在结果里。

d3.tickStep(start, stop, count):先看步长

d3.tickStep 返回"若用相同参数调用 d3.ticks,相邻刻度值之间的差",即一个 10 的幂乘以 1、2 或 5 的整齐值:

d3.tickStep(1, 9, 5) // 2

如果 stop 小于 start,可以返回负的刻度步长,表示刻度递减:

d3.tickStep(9, 1, 5) // -2

文档特别提醒:受 IEEE 754 浮点精度限制,返回的步长可能不是精确的十进制小数(例如看似 0.3 的值实际是 0.30000000000000004)。展示给人看之前,应使用 d3-format 进行格式化取整显示。

d3.tickIncrement(start, stop, count):为浮点精度而生的整数步长

d3.tickIncrementd3.tickStep 类似,但有两个关键差异(以官方文档表述为准):

  1. 要求 start 始终小于等于 stop(不允许递减区间);
  2. 若按给定 startstopcount 计算出的刻度步长小于 1,则返回负逆步长(negative inverse tick step)。
d3.tickIncrement(1, 9, 5) // 2
d3.tickIncrement(1, 9, 20) // -2, meaning a tick step 0.5

第二条示例是理解这个 API 的钥匙:步长 0.5 本身是小数,浮点加法 t += 0.5 在多次累加后可能漂移出整齐值(比如产生 3.5000000000000004)。tickIncrement 返回 -2 意味着"步长 = 1/2"——d3.ticks 内部可以用整数 2 做除法/缩放计算,把累加漂移降到最低。文档原文指出:此方法保证总是返回整数,并被 d3.ticks 用来保证返回的刻度值在 IEEE 754 浮点中被尽可能精确地表示。

d3.nice(start, stop, count):把区间扩成整齐边界

d3.nice 返回一个新区间 [niceStart, niceStop],它覆盖给定区间 [start, stop],且 niceStartniceStop 保证与对应的 刻度步长 对齐:

d3.nice(1, 9, 5) // [0, 10]

即原本 [1, 9] 的区间被向外扩成 [0, 10],两端都落在 2 的整数倍上,坐标轴刻度从 0 和 10 起步,视觉上更整洁。与 d3.tickIncrement 相同,此方法也要求 start 小于等于 stop

d3.range(start, stop, step):等差数列生成器

d3.range 返回一个等差数列数组,行为类似 Python 内置 range(原文档以该文档表述为准,此处不给出外部链接,语义即:起点、终点(不含)、步长)。它常用于遍历等距数值序列,例如数组索引或线性比例的固定刻度:

d3.range(6) // [0, 1, 2, 3, 4, 5]

参数规则(完整继承自官方文档):

  • step 省略时默认为 1;start 省略时默认为 0;
  • stop开区间端点,不会出现在结果中;
  • step 为正时,最后一个元素是小于 stop 的最大 start + i * stepstep 为负时,最后一个元素是大于 stop 的最小 start + i * step
d3.range(5, -1, -1) // [5, 4, 3, 2, 1, 0]

无限区间返回空数组:若返回数组将包含无穷多个值,则返回空 range:

d3.range(Infinity) // []

参数不必是整数,但整数结果更可预期。返回数组中的值定义为 start + i * step,其中 i 从 0 到"数组总长度减一"的整数。注意这是"按下标乘步长"的定义,而非逐步累加:

d3.range(0, 1, 0.2) // [0, 0.2, 0.4, 0.6000000000000001, 0.8]

这个 0.6000000000000001 来自 IEEE 754 双精度浮点(0.2 × 3 的精确结果就是 0.6000000000000001)。展示给人前应使用 d3-format 做合适的舍入格式化;也参见 d3-scale 中 linear.tickFormat

需要固定长度时,用整数 range 加 map。原文档给出了一个反模式对照:

d3.range(0, 1, 1 / 49) // 👎 returns 50 elements!
d3.range(49).map((d) => d / 49) // 👍 returns 49 elements

直接写 1/49 作步长会得到 50 个元素(浮点误差让端点判定"多走了一步");先用整数 d3.range(49) 再映射,长度精确可控。

与 d3-scale、d3-axis 的配合

这组 ticks 函数不是孤立存在的,它们是 d3 刻度生态的底层原语:

典型工作流是:用 *linear*.ticks(count)(或直接用 d3.ticks)取刻度位置,用 *linear*.tickFormat(count) 生成与之配套的标签格式(精度由 d3.tickStep 推断的步长决定),必要时先对域调用 *linear*.nice() 让坐标轴起止点更整齐。

实践要点小结

  1. d3.ticks(start, stop, count) 返回约 count + 1 个整齐等距刻度,端点仅在恰好整齐时包含;
  2. d3.tickStep 给出整齐步长(可为负表示递减),d3.tickIncrement 给出整数化的步长表示(步长小于 1 时返回负逆步长),专供浮点精度敏感的内部计算;
  3. d3.nice(start, stop, count) 把区间外扩到与步长对齐的整齐边界;
  4. d3.range 生成等差数列,stop 为开区间,步长可为负,无限序列返回空数组;
  5. 涉及小数的输出(如 0.6000000000000001)在展示前用 d3-format 格式化;需要精确长度的序列优先 d3.range(n).map(...) 的整数映射写法。

相关文档入口:d3-array 刻度 API 原文档d3-scale 线性比例尺d3-format 数字格式化docs/api.md 全量 API 索引

登录后查看全文
热门项目推荐
相关项目推荐