【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法

时间:2024-10-05 13:41:18

当前内容所在位置(可进入专栏查看其他译好的章节内容)

  • 第一部分 D3.js 基础知识
    • 第一章 D3.js 简介(已完结)
      • 1.1 何为 D3.js?
      • 1.2 D3 生态系统——入门须知
      • 1.3 数据可视化最佳实践(上)
      • 1.3 数据可视化最佳实践(下)
      • 1.4 本章小结
    • 第二章 DOM 的操作方法(已完结)
      • 2.1 第一个 D3 可视化图表
      • 2.2 环境准备
      • 2.3 用 D3 选中页面元素
      • 2.4 向选择集添加元素
      • 2.5 用 D3 设置与修改元素属性
      • 2.6 用 D3 设置与修改元素样式
      • 2.7 本章小结
    • 第三章 数据的处理 ✔️
      • 3.1 理解数据(已完结)
      • 3.2 准备数据(已完结)
      • 3.3 将数据绑定到 DOM 元素(已完结)
        • 3.3.1 利用数据给 DOM 属性动态赋值
      • 【3.4 让数据适应屏幕】 ✔️
        • 3.4.1 比例尺简介(上篇)
        • 3.4.2 线性比例尺(中篇)
          • 3.4.2.1 基于 Mocha 测试 D3 线性比例尺(DIY 实战)
        • 3.4.3 分段比例尺(下篇) ✔️
      • 3.5 加注图表标签(待翻译 ⏳)
      • 3.6 本章小结

文章目录

      • 3.4.3 分段比例尺 Band scale

《D3.js in Action》全新第三版封面

《D3.js in Action》全新第三版封面

3.4.3 分段比例尺 Band scale

绘制示例条形图要用到的第二种比例尺为 分段比例尺(band scale)。它属于之前介绍的第四类(详见 3.4.1 节内容):接受离散型输入、返回连续型输出。要在可用空间内处理离散的各矩形条的分布,这正是 D3 分段比例尺的强项。

声明一个分段比例尺,需要调用 d3.scaleBand() 函数。在以下代码片段中,分段比例尺赋给了常量 yScale,表示它将负责 y 轴方向的元素排布。该比例尺的定义域,是一个包含数据集所有技术(technology)名称的数组,可通过 JavaScriptmap() 函数生成(关于 map() 的用法,可参考前面的 1.2.5 节内容)。至于比例尺的值域,则覆盖所有可用的垂直空间,即从 SVG 容器顶部的 0 像素一直到其底部的 700px

const yScale = d3.scaleBand()
  .domain(data.map(d => d.technology))
  .range([0, 700]);

createViz() 内部加入该比例尺,并写在数据绑定逻辑的代码前面。当使用数据集中的某项技术调用该函数时,会得到该技术对应的矩形条垂直坐标。例如,将字符串 "Excel" 传给 yScale,将得到 0,因为与 Excel 对应的矩形条是条形图中的第一个矩形,位于最上方;同理,若传入 "D3.js",则返回 272.72,它代表 D3 对应的矩形条左上角的垂直坐标:

yScale("Excel")   // => 0
yScale("D3.js")   // => 272.72

之前每个矩形条的 y 属性值是通过手动计算得到的,还有印象吗?现在有了分段比例尺,我们可以非常轻松地用它来算出各矩形条的实际纵坐标:

svg
  .selectAll("rect")
  .data(data)
  .join("rect")
    ...
    .attr("y", d => yScale(d.technology))
    ...

分段比例尺还提供了一个非常方便的工具方法:bandwidth()。它会返回矩形条的厚度。该厚度与矩形条的数量和可用空间成正比。本例中,该厚度即为矩形条的 height 属性值。如以下代码段所示,可以通过分段比例尺的 bandwidth() 方法来设置 height 属性:

svg
  .selectAll("rect")
  .data(data)
  .join("rect")
    ...
    .attr("height", yScale.bandwidth())
    ...

保存项目并在浏览器中查看,会看到如图 3.27 所示的效果。条形图填满了 SVG 容器所有可用的垂直空间。由于各矩形条间没有间隙,条形图看起来十分拥挤,阅读体验极差。

图 3.27 配置了分段比例尺但没有设置间距的条形图效果

【图 3.27 配置了分段比例尺但没有设置间距的条形图效果】

间距的问题可以通过分段比例尺的 paddingInner() 属性(property)来解决。该属性专门用于指定各矩形条间的内边距(padding)大小,并接受一个 01 之间的值,这里设置为 0.2,表示大小为矩形条高度的 20%

const yScale = d3.scaleBand()
  .domain(data.map(d => d.technology))
  .range([0, 700])
  .paddingInner(0.2);

完成以上设置后,重新加载示例页面,条形图的布局看起来就好多了,如图 3.28 所示:

图 3.28 配置了分段比例尺并添加间隙后的条形图效果

【图 3.28 配置了分段比例尺并添加间隙后的条形图效果】

而图 3.29 则梳理并复盘了 D3 分段比例尺的工作原理。首先是接受一个定义域,即数据集中的技术列表,并令其均匀分布到指定的值域内(即 SVG 容器垂直方向上的可用空间)。各矩形条的左上角垂直坐标可以通过调用分段比例尺函数计算得到(如 yScale("PowerPoint"));同理,调用该比例尺的 bandwidth() 方法可以得到矩形条的高度值(即 yScale.bandwidth())。最后是各矩形条的间距,默认情况下为 0,手动设置间距可以通过指定分段比例尺的 paddingInner() 属性实现(property)。它接受一个 01 之间的值,代表当前每个矩形条间的内边距大小(同时也表示其相对于矩形条高度 height 的百分比值)。

图 3.29 分段比例尺在垂直方向的可用空间内均匀排布技术列表时的原理图

【图 3.29 分段比例尺在垂直方向的可用空间内均匀排布技术列表时的原理图】

译注
虽然作者没有提及,但本节附带的练习源码中我也加入了 Mocha.js 相关的测试代码,可以对分段比例尺的相关特性展开测试。感兴趣的小伙伴可以下载到本地试试,这里就不展开了。我本人实测过程中,发现最后的条形图并未居中,原来是上一次练习线性比例尺时忘了修改 x 属性的值,将 0 更正为 100 就和书中截图一样了。特此说明。