- 向图表添加轴并应用边距约定
- 使用线条生成器功能绘制折线图
- 插值数据点以将直线转换为曲线
- 使用面积生成器绘制面积
- 使用电弧发生器创建电弧
您已经熟悉我们使用和组合用于制作数据可视化的常见 SVG 形状:线条、矩形和圆形。您甚至已经使用矩形从头开始创建了条形图。但是我们可以用原始形状画出的东西太多了。为了创建更复杂的可视化,我们通常转向 SVG 路径。正如我们在第 1 章中所讨论的,SVG 路径是所有 SVG 元素中最灵活的,几乎可以采用任何形式。我们在 D3 项目中广泛使用它们,最简单的例子是在折线图中绘制线条和曲线或在圆环图中绘制弧线。
SVG 路径的形状由其 d 属性确定。此属性由指示路径的起点和终点、用于更改方向的曲线类型以及路径是打开还是闭合的命令组成。路径的 d 属性可能很快变得又长又复杂。大多数时候,我们不想自己创作它。这就是 D3 的形状生成器功能的用武之地!
在本章中,我们将构建如图 4.1 所示的项目:温度演变的折线图和一组弧线,可视化 2021 年纽约市降水天数的百分比。您可以在 https://d3js-in-action-third-edition.Github.io/new-york-city-weather-2021/ 在线找到此项目。基础数据来自地下天气(www.wunderground.com/)。
图 4.1 我们将在本章中构建的项目:2021 年纽约市温度演变的折线图和一组显示降水天数百分比的弧线图。
我们将使用 D3 的形状生成器函数创建这两个可视化效果。但在开始之前,我们将讨论 D3 的边距约定以及如何向图表添加轴。
4.1 创建轴开发数据可视化通常需要提前规划如何使用 SVG 容器中的可用空间。首先开始玩很酷的东西是非常诱人的,也就是可视化的核心,但相信我们。一点点的准备可以为您节省大量的执行时间。所有编程任务都是如此,在一般生活中也是如此!在此规划阶段,我们不仅要考虑图表本身,还要考虑使图表可读的互补元素,例如轴、标签和图例。
在本节中,我们将介绍边距约定,这是一种便于为这些不同元素分配空间的方法。然后,我们将讨论如何向可视化添加轴以及组成 D3 轴的多个 SVG 元素。我们将这些概念应用于图 4.1 所示的折线图。
在我们开始之前,请转到第 4 章的代码文件。您可以从本书的 Github 存储库下载它们(如果您还没有 (https://github.com/d3js-in-action-third-edition/code-files)。在名为 chapter_04 的文件夹中,代码文件按节进行组织。要开始本章的练习,请在代码编辑器中打开 4.1-Margin_convention_and_axes/start 文件夹并启动本地 Web 服务器。如果您需要有关设置本地开发环境的帮助,请参阅附录 A。
您可以在位于本章代码文件根目录下的自述文件中找到有关项目文件夹结构的更多详细信息。
警告使用本章的代码文件时,在代码编辑器中仅打开一个开始文件夹或一个结束文件夹。如果一次打开章节的所有文件并使用 Live Server 扩展为项目提供服务,则数据文件的路径将无法按预期工作。
我们将开始在文件折线图中工作.js并使用方法 d3.csv() 加载每周温度数据集。
d3.csv("../data/weekly_temperature.csv");
在第 3 章中,我们解释了 D3 在加载表格数据集时执行的类型转换会影响值的类型。例如,原始数据集中的数字变成字符串,我们需要将它们变回数字以方便操作它们。我们已经看到 d3.csv() 的回调函数 ,我们可以逐行访问数据,是执行此类转换的好地方。在这里,我们将介绍一个小技巧。我们可以调用方法 d3.autoType ,而不是手动转换数字。此函数检测常见的数据类型,如日期和数字,并将它们转换为相应的 JavaScript 类型。
d3.csv("../data/weekly_temperature.csv", d3.autoType);
请注意,数据类型可能不明确,并且 d3.autoType 有时会选择错误的类型。因此,在数据数组完全加载后仔细检查数据数组非常重要。在下面的代码片段中,我们使用 JavaScript Promise 访问加载的数据集,并将其登录到控制台,以确认日期被格式化为 JavaScript 日期,温度被格式化为 数字。您可以在图 4.2 中看到结果。
d3.csv("../data/weekly_temperature.csv", d3.autoType).then(data => {
console.log("temperature data", data);
});
图 4.2 由于 d3.autoType 方法,日期被格式化为 JavaScript 日期,温度被格式化为数字。
我们使用 JavaScript Promise 来访问数据集,因为加载数据是一个异步过程(如果您需要复习有关使用 D3 加载和访问数据的信息,请参阅第 3 章)。但是现在我们知道我们的数据集已完全加载并正确格式化,我们可以开始构建图表了。
文件折线图.js已经包含一个名为 drawLineChart() ,我们将在其中创建折线图。在 JavaScript Promise 的回调函数中,调用函数 drawLineChart() 并将数据集作为参数传递。
d3.tsv("../data/weekly_temperature.csv", d3.autoType).then(data => {
console.log("temperature data", data);
drawLineChart(data);
});
我们现在准备讨论保证金惯例并将其应用于我们的图表!
4.1.1 边距约定D3 边距约定旨在以系统和可重用的方式为轴、标签和图例保留图表周围的空间。该约定使用四个边距:图表的上方、右侧、下方和左侧,如图 4.3 所示。通过说明这些边距,我们可以知道图表核心剩余区域的位置和大小,我们称之为内部图表。
图 4.3 D3 边距约定设置图表顶部、右侧、底部和左侧的边距值。
边距值在边距对象中声明,该对象由上边距、右边距、下边距和左边距组成。让我们为折线图创建边距对象。在函数 drawLineChart() 中,声明一个名为 margin 的常量。如以下代码片段所示,为上边距、右边距、下边距和左边距分别指定 40、170、25 和 40px 的值。
const drawLineChart = (partialData) => {
const margin = {top: 40, right: 170, bottom: 25, left: 40};
};
事先确切知道轴和标签需要多少空间通常是不可能的。我们从一个有根据的猜测开始,如果需要,稍后会进行调整。例如,查看图 4.1 中的折线图或托管项目 (https://d3js-in-action-third-edition.github.io/new-york-city-weather-2021/)。您将看到可视化效果右侧显示的标签相对较长,因此右边距为 170px。另一方面,轴的标签不占用太多空间;因此,剩余的边距可以小得多。
声明边距对象后,我们就可以开始考虑 SVG 容器的大小了。知道了 SVG 容器的大小和边距,我们最终可以计算出两个新常量,分别名为 innerWidth 和 innerHeight ,它们代表内部图表的宽度和高度。这些尺寸如图4.4所示。
图 4.4 知道 SVG 容器的尺寸和边距,我们可以计算内部图表的宽度和高度。