【D3.js in Action 3 精译_039】4.3 D3 面积图的绘制方法及其边界标签的添加
当前内容所在位置:
- 第四章 直线、曲线与弧线的绘制 ✔️
- 4.1 坐标轴的创建(上篇)
- 4.1.1 D3 中的边距约定(中篇)
- 4.1.2 坐标轴的生成(中篇)
- 4.1.2.1 比例尺的声明(中篇)
- 4.1.2.2 坐标轴的添加(下篇)
- 4.1.2.3 轴标签的添加(下篇)
- 4.2 D3 折线图的绘制
- 4.2.1 直线生成工具的使用
- 4.2.2 对数据点作曲线插值处理
- 4.3 D3 面积图的绘制 ✔️
- 4.3.1 面积图生成工具的用法 ✔️
- 4.3.2 用标签提高图表的可读性 ✔️
- 4.4 D3 弧形图的绘制
文章目录
- 4.3 面积图的绘制 Drawing an area
- 4.3.1 面积图生成工具的用法 Using the area generator
- 4.3.2 用标签提高图表的可读性 Enhancing readability with labels

《D3.js in Action》全新第三版封面
译者按
由于 D3 的折线图和面积图在实现方式上相似度极高,这一篇就趁热打铁,将示例折线图剩下的面积图部分一并学完。看似复杂的面积图在作者精心绘制的示意图的帮助下变得非常简单(至少比我的其他专栏要容易很多),曾在 MSOffice 中盛行的“字不如表、表不如图”的说法用到 D3 数据可视化上依然适用。如果早几年出现这样的扫盲级 D3 参考书,如今国内数据可视化领域 ECharts 一手遮天的局面没准还真能被打破。一起学起来吧!
4.3 面积图的绘制 Drawing an area
本节将实现示例折线图后方的面积图部分,用于展示每个日期最低气温与最高气温的波动范围。D3 绘制面积图的方法与绘制折线图类似,也是通过 SVG 的路径元素来创建。D3 还专门提供了面积图生成工具函数 d3.area() 来处理路径 d 属性的复杂运算。
动手绘制前还需要注意一点:示例中的面积图位于折线图的 后方(behind the line chart)。鉴于屏幕元素的渲染顺序与添加到 SVG 父容器的元素顺序保持一致,因此该面积区域的实现代码应该添加到创建折线图的代码 前面。
4.3.1 面积图生成工具的用法 Using the area generator
首先声明一个面积图生成工具函数(area generator function),并赋给常量 areaGenerator。根据以下示例代码,面积生成工具至少需要三个访问器函数(accessor functions)。一是 x(),用于计算数据点的水平坐标,与直线生成工具完全相同;垂直方向上则略有不同,数据点从一组变为了两组,分别对应面积区域的上下边缘,因此需要设置 y0() 和 y1() 两个访问器函数。注意,示例面积图中的上下边缘数据点具有相同的水平坐标:
const areaGenerator = d3.area().x(d => xScale(d.date)).y0(d => yScale(d.min_temp_F)).y1(d => yScale(d.max_temp_F));
图 4.19 生动直观地展示了面积区域的下边界和上边界情况,以及面积生成工具对相关数据的计算处理过程:

【图 4.19 面积生成工具 d3.area() 与三个及更多访问器函数的组合用法示意图。绘制最高最低气温构成的温差区域,需要用到 x()、y0() 和 y1(),分别用于计算各数据点的水平坐标、面积区下边界(即当日最低气温)的垂直坐标、以及面积区上边界(即当日最高气温)的垂直坐标。】
与折线图类似,我们同样可以在面积生成工具函数上链式调用访问器函数 curve() 来对面积图的上下边缘作曲线插值处理,这里还是沿用上一节介绍过的 D3 内置插值函数 d3.curveCatmullRom,如以下代码所示:
const areaGenerator = d3.area().x(d => xScale(d.date)).y0(d => yScale(d.min_temp_F)).y1(d => yScale(d.max_temp_F)).curve(d3.curveCatmullRom);
面积生成器准备就绪后,就可以在内部图表选择集上添加一个 SVG 路径元素。该元素的 d 属性,可以通过刚才备好的面积生成器计算得到,传入参数为数据集 data。剩下的都是一些与审美相关的属性设置:填充色通过 fill 属性实现,属性值就是前面声明过的紫红色常量 aubergine;为了让面积区域与折线部分清晰可辨,可以给面积图加一点透明度,指定其 fill-opacity 属性为 20%,最终渲染效果如图 4.20 所示。注意,颜色常量 aubergine 必须先声明再使用:
innerChart.append("path").attr("d", areaGenerator(data)).attr("fill", aubergine) // 即 "#75485E".attr("fill-opacity", 0.2);

【图 4.20 由折线图表示的日均气温与面积图表示的当日气温波动范围的绘制效果图】
可以看出,D3 面积图的绘制过程与折线图的绘制十分类似。二者的主要区别在于,折线图只有一组数据点,用直线段进行绘制;而面积图需要处理上下两个边缘,每个边缘对应一组数据点。这就是直线生成器函数只需要两个访问器函数(即 x() 与 y())、而面积生成器需要至少三个访问器函数(本例即为 x()、y0() 与 y1())的根本原因,如图 4.21 所示:

【图 4.21 D3 面积图的绘制步骤】
4.3.2 用标签提高图表的可读性 Enhancing readability with labels
至此,我们实现了 2021 年纽约市日均气温的折线图的绘制,并同步展示了当日最低气温与最高气温的变化区域,效果看上去已经很不错了;但我们还需要确保看到这张图表的人们能够轻松准确地理解折线与面积的含义。添加图表标签(label)就是个不错的想法。
前面学过,图表标签不过是放置在可视化作品里的 SVG 文本元素。在本例中,不妨创建三个标签,分别用于表示折线图末尾的平均气温、位置靠下的当日最低气温、以及靠上放置的当日最高气温。
先从折线图标签开始。先将 SVG 文本元素添加到内部图表选择集中,然后调用 text() 方法设置标签文本为 "Average temperature"(即“平均气温”);接着通过 x 和 y 属性设置标签在绘图区内的坐标。
我们希望标签位于折线图末尾,也就是最后一个数据点的后面;其水平坐标可以通过先前声明的常量 lastDate 由水平比例尺函数 xScale() 算得;另外可以再给标签一个 10px 的间距。
而垂直坐标的计算还需要一个当天的平均气温值,可以先通过 data[data.length - 1] 获取到最后一个数据点;然后利用句点标识符拿到对应的平均气温;接着再调用垂直比例尺函数 yScale() 算得该数据点的垂直坐标。最后复用颜色常量 aubergine,通过 fill 属性来指定标签文本的颜色,如以下代码所示:
innerChart.append("text").text("Average temperature").attr("x", xScale(lastDate) + 10).attr("y", yScale(data[data.length - 1].avg_temp_F)).attr("fill", aubergine);
如果保存项目并在浏览器中查看效果,会发现文本标签的底边与折线图最后一个数据点的中心垂直对齐了。默认情况下,SVG 文本元素的基准线(baseline)位于文本的底边位置,如图 4.22 (左图)所示。这时可以使用 dominant-baseline 属性来手动修改。如以下代码所示,将该属性值设为 middle,基准线就改到了文本的中心位置:
innerChart.append("text").text("Average temperature").attr("x", xScale(lastDate) + 10).attr("y", yScale(data[data.length - 1].avg_temp_F)).attr("dominant-baseline", "middle").attr("fill", aubergine);

【图 4.22 SVG 文本元素的 y 属性可设置其基准线在垂直方向的位置,默认位置在文本底边。可通过 dominant-baseline 进行修改,值为 middle 时基准线与文本中心对齐;值为 hanging 时基准线则位于文本顶部。】
接着再给面积图的下边界添加一个文本标签,代表最低温度的变化趋势。具体做法与刚才一样,先添加一个 SVG 文本元素,并指定文本内容为 "Minimum temperature",即最低气温。
至于标签的坐标方位,可以参考最后一个下凹点(downward protuberance),即下边缘倒数第三个数据点。将该位置的数据值传入垂直坐标尺函数,算得其垂直坐标,然后再下移 20px、右移 13px。这些位移量都是通过在页面上不断尝试不同的位置得到的;借助浏览器的检查工具(inspector tool)是处理这类微调操作的绝佳工具。注意,此时文本标签的 dominant-baseline 属性值改为了 hanging,如图 4.22 所示,表示 y 属性值是相对于文本的顶部而言的。
最后,根据以下代码片段,就能再给图表标签新增一条指示线,将面积图的下凹拐点与标签进行关联,进一步明确标签所代表的含义,如图 4.23 所示。同理,可以使用比例尺分别计算指示线的 x1、y1、x2 和 y2 属性值,最终确定出线段的起点和终点位置:
innerChart.append("text").text("Minimum temperature").attr("x", xScale(data[data.length - 3].date) + 13).attr("y", yScale(data[data.length - 3].min_temp_F) + 20).attr("alignment-baseline", "hanging").attr("fill", aubergine);
innerChart.append("line").attr("x1", xScale(data[data.length - 3].date)).attr("y1", yScale(data[data.length - 3].min_temp_F) + 3).attr("x2", xScale(data[data.length - 3].date) + 10).attr("y2", yScale(data[data.length - 3].min_temp_F) + 20).attr("stroke", aubergine).attr("stroke-width", 2);
同理也可以给面积区的上边缘添加类似的文本标签,用以表示当日最高气温的变化情况。上边缘标签的定位可以参考其倒数第四个数据点的上凸拐点。然后用相同的手法在标签和上凸拐点间绘制一条指示线,如以下代码片段所示:
innerChart.append("text").text("Maximum temperature").attr("x", xScale(data[data.length - 4].date) + 13).attr("y", yScale(data[data.length - 4].max_temp_F) - 20).attr("fill", aubergine);
innerChart.append("line").attr("x1", xScale(data[data.length - 4].date)).attr("y1", yScale(data[data.length - 4].max_temp_F) - 3).attr("x2", xScale(data[data.length - 4].date) + 10).attr("y2", yScale(data[data.length - 4].max_temp_F) - 20).attr("stroke", aubergine).attr("stroke-width", 2);
这样就完成了折线图部分的绘制:

【图 4.23 绘制完毕的 2021 年纽约市全年日均气温及其变化趋势效果图】
另附:专栏文章连载期间 完全免费,后续 不排除 调整为收费专栏。对 D3.js 感兴趣、或者想要从零开始彻底掌握 D3 的朋友们强烈建议及时关注本专栏,一起学习交流,共同进步!
目前译好的其他章节内容如下(可进入专栏查看详情):
- 第一部分 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.4.3.1 使用 Observable 在线绘制 D3 条形图(DIY 实战)
- 3.5 加注图表标签(上篇)
- 3.5.1 人物专访:Krisztina Szűcs(下篇)
- 3.6 本章小结
相关文章:
【D3.js in Action 3 精译_039】4.3 D3 面积图的绘制方法及其边界标签的添加
当前内容所在位置: 第四章 直线、曲线与弧线的绘制 ✔️ 4.1 坐标轴的创建(上篇) 4.1.1 D3 中的边距约定(中篇)4.1.2 坐标轴的生成(中篇) 4.1.2.1 比例尺的声明(中篇)4.1…...
布谷直播源码部署服务器关于数据库配置的详细说明
布谷直播源码搭建部署配置接口数据库 /public/db.php(2019年8月后的系统在该路径下配置数据库,老版本继续走下面的操作) 在项目代码中执行命令安装依赖库(⚠️注意:如果已经有了vendor内的依赖文件的就不用执行了&am…...
Xfce桌面设置右键菜单:用右键打开VSCode
前言 AlmaLinux安装VSCode之后始终没有找到如何用右键菜单打开VSCode,比Windows麻烦多了。每次都需要先找到文件夹,然后用系统自带的Open In Terminal打开终端,再输入code .,才能够在当前文件夹中快速打开VSCode。那么࿰…...
【NLP自然语言处理】深入探索Self-Attention:自注意力机制详解
目录 🍔 Self-attention的特点 🍔 Self-attention中的归一化概述 🍔 softmax的梯度变化 3.1 softmax函数的输入分布是如何影响输出的 3.2 softmax函数在反向传播的过程中是如何梯度求导的 3.3 softmax函数出现梯度消失现象的原因 &…...
Pytorch训练时报nan
0. 引言 Pytorch训练时在batchN时loss为nan。经过断点检查发现在batchN-1时,网络参数非nan,输出非nan,但梯度为nan,导致网络参数已经全部被更新为nan,遇到这种情况应该如何排查,如何避免?由于导…...
JavaScript定时器详解:setTimeout与setInterval的使用与注意事项
在JavaScript中,定时器用于在指定的时间间隔后或周期性地执行代码。JavaScript 提供了两种主要的定时器函数:setTimeout 和 setInterval。以下是它们的详细解释和实现方式: 1. setTimeout setTimeout 函数用于在指定的毫秒数后执行一次函数…...
CSS——选择器、PxCook软件、盒子模型
选择器 结构伪类选择器 作用:根据元素的结构关系查找元素。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&quo…...
Mysql 大表limit查询优化原理实战
文章目录 1 大表查询无条件优化&原理(入门)2 大表查询带 条件 优化&原理(进阶)2.1 where 后面的查询字段只有一个时,要求该字段是索引字段2.2 where 后面的查询字段有多个时,尽量让查询字段为索引字段且字段值基数大 3 大表查询带 排序 优化&…...
在vscode中开发运行uni-app项目
确保电脑已经安装配置好了node、vue等相关环境依赖 进行项目的创建 vue create -p dcloudio/uni-preset-vue 项目名 vue create -p dcloudio/uni-preset-vue uni-app 选择模版 这里选择【默认模版】 项目创建成功后在vscode中打开 第一次打开项目 pages.json 文件会报错&a…...
【JavaEE初阶 — 多线程】Thread的常见构造方法&属性
目录 Thread类的属性 1.Thread 的常见构造方法 2.Thread 的几个常见属性 2.1 前台线程与后台线程 2.2 setDaemon() 2.3 isAlive() Thread类的属性 Thread 类是JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的Thread 对象与之关联&am…...
ctfshow(316)--XSS漏洞--反射性XSS
Web316 进入界面: 审计 显示是关于反射性XSS的题目。 思路 首先想到利用XSS平台解题,看其他师傅的wp提示flag是在cookie中。 当前页面的cookie是flagyou%20are%20not%20admin%20no%20flag。 但是这里我使用XSS平台,显示的cookie还是这样…...
ubuntu22.04安装conda
在 Ubuntu 22.04 上安装 Conda 可以通过以下步骤进行: 下载 Miniconda(轻量级版本的 Conda): 打开终端并运行以下命令以下载 Miniconda 安装脚本: wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-…...
D58【python 接口自动化学习】- python基础之异常
day58 异常捕获 学习日期:20241104 学习目标:异常 -- 74 自定义异常捕获:如何定义业务异常? 学习笔记: 自定义异常的用途 自定义异常的方法 # 抛出一个异常 # raise ValueError(value is error) # ValueError: val…...
Java项目实战II基于Spring Boot的便利店信息管理系统(开发文档+数据库+源码)
目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在快节奏的…...
Java-日期计算工具类DateCalculator
DateCalculator是用于日期计算的工具类。这个工具类将包括日期的加减、比较、周期计算、日期 范围生成等功能。 import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Period; import java.time.temporal.ChronoUnit;…...
单片机串口接收状态机STM32
单片机串口接收状态机stm32 前言 项目的芯片stm32转国产,国产芯片的串口DMA接收功能测试不通过,所以要由原本很容易配置的串口空闲中断触发DMA接收数据的方式转为串口逐字节接收的状态机接收数据 两种方式各有优劣,不过我的芯片已经主频跑…...
ipv6的 fc00(FC00::/7) 和 fec0(FEC0::/10)
ipv6的 fc00(FC00::/7)(唯一本地地址) 替代了 fec0(FEC0::/10) (站点本地地址,已弃用) ipv6的 fc00(FC00::/7) 替代了 fec0(FEC0::/10) , 在IPv6地址中,FC00::/7(通常简写为FC00)和…...
Chat GPT英文学术写作指令
目录 Chat GPT英文学术写作指令 Chat GPT英文学术写作指令 1."为我捉供一些建议和技巧,以提高我的学术写作质最和风格" (Provide me with some suggestions andtips to improve the quality andstyleofmyacademic writing.) 2."帮我提写一个清晰而有逻辑的…...
超详细Pycharm安装汉化教程,Python环境配置和使用指南,Python零基础入门看这个就够了!
包含编程资料、学习路线图、源代码、软件安装包等!【[点击这里]】! PyCharm 是由 JetBrains 打造的一款 Python IDE (集成开发环境,Integrated Development Environment),带有一整套可以帮助用户在使用 Py…...
react-native:解决使用webView后部分场景在安卓10崩溃闪退问题
app闪退问题原因: 安卓7以上版本(7和7以下版本不会出现闪退):在屏幕不可视区域加载webView或者webView不在可视区域内切换页面时app崩溃闪退(在屏幕可视区域加载webView或者webView在可视区域内切换页面不会闪退&…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...
【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验
2024年初,人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目(一款融合大型语言模型能力的云端AI编程IDE)时,技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力,TRAE在WayToAGI等…...
前端工具库lodash与lodash-es区别详解
lodash 和 lodash-es 是同一工具库的两个不同版本,核心功能完全一致,主要区别在于模块化格式和优化方式,适合不同的开发环境。以下是详细对比: 1. 模块化格式 lodash 使用 CommonJS 模块格式(require/module.exports&a…...
CppCon 2015 学习:Reactive Stream Processing in Industrial IoT using DDS and Rx
“Reactive Stream Processing in Industrial IoT using DDS and Rx” 是指在工业物联网(IIoT)场景中,结合 DDS(Data Distribution Service) 和 Rx(Reactive Extensions) 技术,实现 …...
