当前内容地点位置
- 第一部门 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.2.1 将数据集加载到 D3 项目 ✔️
- 3.2.2 格式化数据 ✔️
- 3.2.3 测量数据集 ✔️
- 3.3 将数据绑定到 DOM 元素(精译中 ⏳)
- 3.4 让数据适应屏幕
- 3.5 加注图表标签
- 3.6 本章小结
3.2 数据预备 Preparing data
有了数据集,下一步就是用 D3 将其 加载 到项目中,如图 3.8 中的步骤 2 所示。然后就是确保数据按正确的格式进行处理,其间也可能需要对数据进行多方位的测量。本节先容的 D3 方法都是为了完成上述预备工作,并为示例条形图的创建提供有效数据。
图 3.8 D3 数据工作流的第二步即使用 D3 的数据获取方法,将数据集加载到项目中
3.2.1 将数据集加载到 D3 项目 Loading a dataset into a D3 project
D3 提供了极为方便的工具函数来处理项目数据的加载。详细工具函数的选择,取决于当前数据集的特定格式。例如,CSV 格式的数据集使用 d3.csv() 进行加载,JSON 数据集则使用 d3.json()。这些函数的第一个参数均为该数据文件的路径。此外,D3 还专门提供了用于加载文本以致 XML 格式数据的工具函数。它们都分属 d3-fetch 模块(详见 https://d3js.org/d3-fetch)。
注意
本章代码已放到 GitHub 仓库(详见 http://mng.bz/Y7Po)。各章节代码都存放在代码仓库相应的文件夹下。在 3.2 开头的文件夹中可以看到本小节示例代码,数字后跟章节主题,如 3.2-Preparing_data。各文件夹下都有一组子文件夹 start 与 end。若需从最基本的代码开始练习,请使用 start 文件夹。要是遇到困难,可以在 end 文件夹找到对应的参考代码。分章节练习时,建议一次只打开一个 start 或一个 end 文件夹。假如用 Live Server 工具一次性打开所有章节的文件并启动当地服务器,某些路径可能无法正常工作,尤其是往项目中加载数据集时,需要特别注意。
下面再回到上一章先容过的那个条形图练习,将我们从《2021 年数据可视化行业状态调查》中搜集的样本数据集(详见 www.datavisualizationsociety.org/survey)加载到示例中。该数据集为 CSV 格式,位于 /data 文件夹下。数据集的详细内容如代码清单 3.1 所示。第一行为列标题,technology 与 count 分别表示调查中涉及的数据可视化工具(即从 ArcGIS 到 P5)、以及选用该工具的从业者投票数。其中 D3.js 为 414 票,Python 为 530 票:
代码清单 3.1 数据从业职员最常用的工具统计情况(data.csv)
- technology,count
- ArcGIS,147
- D3.js,414
- Angular,20
- Datawrapper,171
- Excel,1078
- Flourish,198
- ggplot2,435
- Gephi,71
- Google Data Studio,176
- Highcharts,58
- Illustrator,426
- Java,29
- Leaflet,134
- Mapbox,167
- kepler.gl,24
- Observable,157
- Plotly,223
- Power BI,460
- PowerPoint,681
- Python,530
- QGIS,193
- Qlik,61
- R,561
- React,145
- Tableau,852
- Vega,48
- Vue,51
- Web Components,79
- WebGL,65
- Pen & paper,522
- Physical materials,69
- Canvas,121
- P5/Processing,55
复制代码 鉴于目的数据集为 CSV 文件,因此选用 d3.csv() 进行数据加载,并将文件路径 "../data/data.csv" 作为第一参数。这里的双句点符号 .. 表示上一层目录,即文件夹 /js 地点的项目根目录。然后进入 /data 文件夹,终极定位到数据文件 data.csv:
- d3.csv("../data/data.csv");
复制代码 如许就完成了数据工作流中的第 2 步。接下来需要对数据做格式化处理并完成相关测量工作。在此之前,还要知道数据的访问方法。注意,这里的数据加载是一个 异步过程(asynchronous process),所涉及的异步操纵,是指那些数据结果不会立刻返回的数据请求。我们可以通过访问 d3.csv() 的回调函数,大概 JavaScript 的 Promise 接口,确保数据在执行相关操纵前已加载完毕。
3.2.2 格式化数据 Formatting a dataset
本节先容 D3 处理数据格式的详细方法,对应工作流中的第三步,如图 3.9 所示:
图 3.9 数据工作流的第三步,从数据格式化开始,以便在构建可视化时使用
d3.csv() 中的回调函数,又称为 行转换函数(row conversion function),能够逐行访问数据。在下面的代码中,d3.csv() 的第一个参数为数据路径,第二个参数即为回调函数。该函数将访问到的数据输出到控制台显示。复制本段代码到 main.js 并保存项目:
- const svg = d3.select(".responsive-svg-container")
- .append("svg")
- .attr("viewBox", "0 0 1200 1600")
- .style("border", "1px solid black");
- d3.csv("../data/data.csv", d => {
- console.log(d);
- });
复制代码 打开欣赏器检查工具,转到控制台(即 Console)标签,将会看到如图 3.10 所示的输出结果。数据逐行记录,每一行都是一个包罗 technology 和 count 的 JavaScript 对象:
图 3.10 获取到数据后,由 d3.csv() 回调函数输出到控制台的部门数据显示情况
- d3.csv("../data/data.csv", d => {
- return {
- technology: d.technology,
- count: +d.count
- };
- });
复制代码 这里的关键在于,回调函数中返回的这些键值对(key-value pairs),是数据集加载完毕后唯一可以访问的内容。该战略可以有效过滤原始数据中的无关字段列。但假如需要保留的列过多,逐一返回目的键值对可能稍显冗余。这时可能需要跳过回调函数中的处理逻辑,待 D3 返回完备数据集后再统一进行格式化。完备数据集的详细访问方法将在下一节进行先容。
3.2.3 测量数据集 Measuring a dataset
D3 数据工作流的第三步还可以包罗一个可选操纵,即数据测量,如图 3.11 所示。只管逐行读取数据很实用,但偶尔也需要访问整个数据集。这就要用到 JavaScript 的期约接口 Promise 了。Promise 是异步操纵的结果,并以对象的形式存在。例如函数 d3.csv() 返回的对象。读取 Promise 结果的一个简单方法是调用其 then() 方法。
图 3.11 在第三步的第二小步,可以测量并探索数据
在以下代码段中,工具函数 d3.csv() 链式调用了 then() 方法。一旦数据加载完毕,Promise 即转为 兑现(fulfilled) 状态,完备数据集将在 then() 方法中的回调函数中备用。按如下代码将该数据集一次性输出到控制台,并保存项目:
- d3.csv("../data/data.csv", d => {
- return {
- technology: d.technology,
- count: +d.count
- };
- }).then(data => {
- console.log(data);
- });
复制代码 在控制台中,您会看到一个被转换为对象数组的完备数据集,其中的每个对象对应 CSV 原始数据会合的某一行。此时 D3 让该数据集变为可迭代对象,对于后续可视化开发非常有效。如图 3.12 所示,还可以确认计数值已正确转为数字形式。查察数组末了一项,还能看到经过 D3 处理后的原始 CSV 数据的列标题数组。只管我们的条形图小练习暂不需要,但它偶尔也可以派上用场。
图 3.12 完备的数据集以对象数组的形式记录在控制台中
在数据工作流的第 3.a 步骤中,我们已经完成了数据格式化的工作,此时仍旧可以使用 D3 来探索并测量获取到的数据。测量数据的特定维度有助于提前做好相关预备工作。
固然从那边开始探索数据并没有严酷的规范,但从数据集 Promise 的 then() 方法切入不失为一个好思路。首先要观察数据集包罗了多少种技术。这可以通过数组的 length 属性直接查察。打印到控制台,将得到结果 33。也就是说,条形图将包罗 33 个矩形元素:
- d3.csv("../data/data.csv", d => {
- ...
- }).then(data => {
- console.log(data.length); // => 33(数据集包含的总行数)
- });
复制代码 此外,我们还想知道哪种技术最受接待,以及有多少从业职员在定期使用它;最热门的有了,最冷门的情况又如何?这些指标都可以通过 d3.max() 和 d3.min() 函数得到。如以下代码段所示,这些函数都接受两个参数:第一个参数是包罗这些极值的可迭代对象(即数据集自己),由 Promise 提供;第二个参数是一个 访问器函数(accessor function),用于指定到场比较的健(本例中即为 count)。
若要在控制台中分别输出最大值和最小值,同样可使用 Promise 的 then() 方法,分别得到结果 1078 和 20:
- d3.max(data, d => d.count) // => 1078
- d3.min(data, d => d.count) // => 20
- d3.extent(data, d => d.count) // => [20, 1078]
复制代码 注意
还可以使用 d3.extent() 方法,它接受类似的参数并返回一个包罗最小值和最大值的结果数组。
观察数据中的最大值与最小值有助于预判图表中条形区域的长度,并能预估最高值和最低值之间的差异对比是否易于在屏幕上渲染。
条形图中的数据常按降序排列,如许可读性更强,观众看了也能一览无余,明白哪些技术使用频率较高、哪些较低。JavaScript 的原生方法 sort() 可以轻松实现排序。它接受一个 比较函数(compare function) 作参数,如以下代码所示。该函数用于比较两个技术的 count 值,参数 a 和参数 b 分别表示到场比较的两个技术对象。若 b 中的 count 值大于 a 中的,则 b 应该排在 a 的前面,以此类推:
- data.sort((a, b) => b.count - a.count);
复制代码 排序逻辑可以放到 then() 方法内。假如打印到控制台,会看到 Excel 位于技术列表的首位,计数为 1078;其次是 Tableau,计数值 852;Angular 则以 20 的最小计数值垫底,如图 3.13 所示。
此外,d3-array 模块(详见 https://d3js.org/d3-array)还包罗大量用来测量及转换数据的实用方法,本书后续将选取一部门进行先容。但 d3.max()、d3.min() 与 d3.extent() 函数应该这当中是最常用的。
图 3.13 输出到控制台并按降序排列的数据集
完成了数据的加载、转换与测量工作,接下来通常需要将数据集通报给另一个函数进行处理。该函数负责可视化结果的构建。如以下代码段所示,可以看到此时 main.js 中的内容;注意观察在 then() 方法的末端,数据是怎样通报给 createViz() 函数的。该函数的实现逻辑将在下一节进行先容。
代码清单 3.2 数据的加载、转换与测量逻辑(main.js)
- const svg = d3.select(".responsive-svg-container") .append("svg") // 添加一个 SVG 容器 .attr("viewBox", "0 0 1200 1600") .style("border", "1px solid black"); d3.csv("../data/data.csv", d => { // 加载数据集 // 对数据进行格式化处理 return { technology: d.technology, count: +d.count };}).then(data => { // 对数据集进行测量 console.log(data.length); // => 33 console.log(d3.max(data, d => d.count)); // => 1078 console.log(d3.min(data, d => d.count)); // => 20 console.log(d3.extent(data, d => d.count)); // => [20, 1078] // 让数据集按降序排列 data.sort((a, b) => b.count - a.count);
- // 将数据集传给另一个函数作进一步处理 createViz(data);});// 构建条形图的处理函数const createViz = (data) => {};
复制代码 在结束本节内容前,您可以参照图 3.14 中的内容,简要回顾一下前面学过的数据加载、行转换以及 Promise 等相关概念。总结归纳如下:
- 加载数据要用到 D3 的数据获取函数(fetch function),如 d3.csv()。
- 数据的格式化是在行转换函数中进行的。
- 数据加载完毕后,可以通过链式调用 then() 方法来访问整个数据集。该方法也是探究数据及执行其他数据操纵的理想场所。
- 将终极的数据通报给另一个函数,由该函数负责详细的可视化构建。
图 3.14 D3 中数据加载、转换及测量的实现方法与位置示意图
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |