【D3.js in Action 3 精译_040】4.4 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.4.1 D3 中的极坐标系 ✔️
      • 4.4.2 圆弧生成器的使用 ✔️
      • 4.4.3 圆弧形心的计算 ✔️
      • 4.4.4 人物专访:Francis Gagnon、Patricia Angkiriwang 和 Olivia Gélinas
    • 4.5 本章小结

文章目录

    • 4.4 D3 弧形图的绘制 Drawing arcs
      • 4.4.1 D3 中的极坐标系 The polar coordinate system
      • 4.4.2 圆弧生成器的使用 Using the arc generator
      • 4.4.3 圆弧形心的计算 Calculating the centroid of an arc

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

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

译者按
终于来到了第四章的最后一节——弧形图的绘制。有了前面几节的知识储备,看似云遮雾绕的 D3 弧形图绘制也可以立马手到擒来。这也是 D3 可视化的另一个强大之处——掌握相关基础知识后可以快速触类旁通其他图表类型!

4.4 D3 弧形图的绘制 Drawing arcs

在本章最后一节,一起再来看看 D3 弧形图的绘制方法。弧形是数据可视化中的常见形状,经常用于绘制饼图、旭日图(sunburst diagrams)和南丁格尔玫瑰图(Nightingale rose charts)等,用于呈现目标数量与总量之间的关系。此外还可以在自定义的径向可视化作品(custom radial visualizations)中见到它们的身影。

与折线图和面积图一样,弧形图也是通过 SVG 路径元素绘制的。可能您已经猜到了,D3 内置了一个便捷的弧形生成工具专门用于计算弧形路径的 d 属性。在详细介绍弧形生成器之前,先要做好示例项目的相应准备工作。本节要绘制的弧形图,即本章最开始介绍的图 4.1 中右边的“降水天数”环形图,也可以在该图形的线上版本进行查看(详见 http://mng.bz/5orB)。其中蓝色弧线表示 2021 年纽约市全年降水天数的百分比(35%),灰色弧线则表示无降水天数。

首先打开 arc.js 文件,本节后续实现逻辑都将写到这里。同往常一样,这里需要加载一个数据集,即 data 文件夹下的降水量数据文件 daily_precipitation.csv。查看该 CSV 文件,会看到当中只包含两列,其中 date 列为 2021 年的每一天,而 total_precip_in 列则为每一天的总降水量,单位为英寸。

在下面的代码段中,我们使用 d3.csv() 读取数据集,并利用格式转换函数 d3.autoType 得到正确的日期和数字;然后链式调用 Promisethen 方法,并将得到的数据集输出到控制台:

d3.csv("./data/daily_precipitation.csv", d3.autoType).then(data => {console.log("precipitation data", data);
});

注意

这里不会展开讨论 d3.csv() 方法的细节,相关内容详见第三章,或者参考本章 4.1 小节了解 d3.autoType 函数的用法。

如果查看控制台中的数据,就会看到日期和数字的格式都是正确的。接下来就可以将处理好的数据集传入 drawArc() 函数。该函数已经事先在 arcs.js 中定义好了(译注:只是不完整):

d3.csv("../data/daily_precipitation.csv", d3.autoType).then(data => {console.log("precipitation data", data);drawArc(data);
});

drawArc() 函数中,可以添加一个新的 SVG 容器,如以下代码所示。先指定 SVG 容器的宽高为 300px,并添加到一个 ID 为 arcdiv 元素中。该 ID 值已在 index.html 文件中声明。这里利用第一章介绍的知识将 SVG 元素设为响应式容器:忽略其 widthheight 属性,直接指定 viewBox 属性并传入指定的宽高。这样,SVG 容器就能自适应父容器的大小,并保持恒定纵横比不变。最后,再将 SVG 容器的选择集赋给常量 svg 备用:

const pieChartWidth = 300;
const pieChartHeight = 300;
const svg = d3.select("#arc").append("svg").attr("viewBox", [0, 0, pieChartWidth, pieChartHeight]);

4.4.1 D3 中的极坐标系 The polar coordinate system

回顾 4.1 小节介绍的内容,当时的图表是绘制在一个 SVG 分组元素中并通过平移到达容器指定位置;而本节的实现策略不太一样,由于无需为坐标轴和标签预留足够空间,因此边距约定环节可以省略。但与目前创建的所有可视化效果不同,弧形图是基于极坐标系绘制的,并非之前的直角坐标系。

如图 4.24 所示,SVG 容器的坐标系为直角坐标系(也称笛卡尔坐标系)。它通过两个相互垂直的维度 xy 来描述二维平面空间中的位置;而平面极坐标系也有两个维度:半径与角度。其中半径为坐标原点与空间中某个点之间的距离,而角度则基于 12 点方向沿顺时针算得。这种空间坐标的描述方式在处理圆弧时特别管用。

图 4.24 直角坐标系的两个维度相互垂直,而极坐标系通过半径和角度来描述空间中的方位

【图 4.24 直角坐标系的两个维度相互垂直,而极坐标系通过半径和角度来描述空间中的方位】

由于元素在极坐标系中相对于原点定位,因此我们可以说,待绘制的弧形可视化效果的原点位于 SVG 容器的中心,如图 4.25 所示。

图 4.25 通过在 SVG 容器的分组元素中绘制弧形图,然后平移至容器正中,可以很方便地实现弧形图的绘制。此时各圆弧相对于图表中心定位,也就是极坐标系的原点位置。

【图 4.25 通过在 SVG 容器的分组元素中绘制弧形图,然后平移至容器正中,可以很方便地实现弧形图的绘制。此时各圆弧相对于图表中心定位,也就是极坐标系的原点位置。】

以下代码片段将在 SVG 容器内添加一个分组元素,然后平移至容器正中,并将该选择集赋给常量 innerChart

const innerChart = svg.append("g").attr("transform", `translate(${pieChartWidth/2}, ${pieChartHeight/2})`);

要绘制圆弧,还需要计算弧形图中降水天数对应的角度值。使用 D3 创建饼图或环形图时,通常使用饼图布局生成工具(即 pie layout generator)来处理相关计算,该生成器工具将在下一章中重点介绍。本节只涉及两条弧线,因此计算起来很简单。

首先,通过数据集的 length 属性,我们知道了 2021 年全年数据点的总天数为 365 天。接着筛选出降水量大于 0 的天数,即 126 天,从而得到当年有降水记录的天数。最后用降水天数除以总天数,得到 35% 的占比:

const numberOfDays = data.length;
const numberOfDaysWithPrecipitation = data.filter(d => d.total_precip_in > 0).length;
const percentageDaysWithPrecipitation =   Math.round(numberOfDaysWithPrecipitation / numberOfDays * 100);

接下来需要计算降水天数对应的角度,用占比乘以 360 度(即一整圈的度数),得到 126 度。用角度进行计算更加直观,但使用时需转换为弧度值,即用角度值乘以 π/180,算得弧度约为 2.2。最后将该结果赋给常量 angleDaysWithPrecipitation_rad

之所以需要转换,是因为后续会用到的弧形生成器需要弧度制单位而非角度单位。根据经验,在处理角度时 JavaScript 通常使用弧度制,而 CSS 样式表中则采用角度制计量:

const angleDaysWithPrecipitation_deg = percentageDaysWithPrecipitation * 360 / 100;
const angleDaysWithPrecipitation_rad = angleDaysWithPrecipitation_deg * Math.PI / 180;

4.4.2 圆弧生成器的使用 Using the arc generator

终于讲到最有意思的部分:圆弧的生成了!首先需要像折线图和面积图那样,声明一个圆弧生成器(arc generator)。圆弧生成器函数 d3.arc() 位于 d3-shape 模块;本例中需要两个关键的访问器函数(accessor functions):圆弧的内圆半径和外圆半径,分别通过 innerRadius() 函数和 outerRadius() 函数进行设置,传入参数分别为 80px120px。如果内圆半径为 0,则会得到一个饼图。

const arcGenerator = d3.arc().innerRadius(80).outerRadius(120);

如图 4.26 所示,可以调用访问器函数 padAngle() 设置圆弧的填充角来定制圆弧形状。该函数接受一个弧度单位的角度值。这里用的是 0.02 弧度,相当于 1° 多一点点。此外还可以调用 cornerRadius() 函数对圆弧的拐角作圆化处理,其参数为一个基于像素的数字。该访问器函数的效果于 CSS 中的 border-radius 属性类似:

const arcGenerator = d3.arc().innerRadius(80).outerRadius(120).padAngle(0.02).cornerRadius(6);

图 4.26 圆弧生成器利用多个访问器函数计算弧形的 d 属性。图中声明生成器时分别指定了内圆半径、外圆半径、填充角及拐角半径。添加路径元素时需要传入每个圆弧的起始角与终止角。

【图 4.26 圆弧生成器利用多个访问器函数计算弧形的 d 属性。图中声明生成器时分别指定了内圆半径、外圆半径、填充角及拐角半径。添加路径元素时需要传入每个圆弧的起始角与终止角。】

您也许会问,为什么不使用访问器函数来处理圆弧覆盖的角度呢?本例中的角度值是手动计算的,因此在添加路径时将其直接传给圆弧生成器会更简单。在下一章中,我们还将介绍另一些不同的情况。

下面来添加代表降水天数的弧线。在以下代码片段中,先往内部图表的选择集内添加一个 path 元素;接着通过调用前面声明的圆弧生成器来指定其 d 属性。

注意观察,绘制圆弧时需要向生成器中传入一个包含起始角与终止角的配置对象:起始角 startAngle 的值为 0,对应 12 点钟方向;终止角 endAngle 的值为前面算好的降水天数对应的弧度值。最后指定圆弧的填充色为青蓝色 #6EB7C2

innerChart.append("path").attr("d", () => {return arcGenerator({startAngle: 0,endAngle: angleDaysWithPrecipitation_rad});}).attr("fill", "#6EB7C2");

同理可添加第二段圆弧。此时弧线从上一条圆弧的终止位置开始,并在整个圆的终止处结束(对应的弧度为 2*Pi)。接着再给第二段圆弧指定填充色 #DCE2E2,即更接近灰色的颜色,表明这些日子没有降水:

innerChart.append("path").attr("d", () => {return arcGenerator({startAngle: angleDaysWithPrecipitation_rad,endAngle: 2 * Math.PI});}).attr("fill", "#DCE2E2");

图 4.27 用以展示降水天数与无降水天数对比情况的弧线图效果

【图 4.27 用以展示降水天数与无降水天数对比情况的弧线图效果】

保存项目后,本地页面的弧形图应该与图 4.27 中的版本类似。您可以自行尝试变换传入圆弧生成器各访问器函数中的参数值,例如半径和拐角尺寸,观察它们对圆弧外观的影响。

如图 4.28 所示,弧形图的绘制过程与折线图及面积图类似,主要区别在于,弧线在平面空间中的位置坐标是通过极坐标描述的,并非之前的直角坐标系。这一点在圆弧生成器的访问函数中也有所体现。

图 4.28 弧形图的绘制步骤

【图 4.28 弧形图的绘制步骤】

4.4.3 圆弧形心的计算 Calculating the centroid of an arc

饼图和环形图近期在数据可视化领域可谓负面新闻不断,主要原因时人们发现肉眼并不擅长估算角度所代表的比例大小。不过,在包含少量数据类别时,这些图表的表现还是可圈可点的;但我们绝对可以通过添加标签来提高它们的可读性,这就是本节要实现的目标。

在表示降水天数的圆弧上,我们希望添加一个 “35%” 的标签,即之前算出的降水天数占比。该标签的最佳位置应该在圆弧的中心处,即形心(centroid)位置(也叫质心,即 center of mass)。该位置坐标可通过圆弧生成器计算得到。

在下面的代码片段中,我们调用了此前声明的圆弧生成器上的方法。此时,起始角与终止角也可以通过链式调用 startAngle()endAngle() 这两个访问器函数进行设置,最后再链式调用形心计算方法 centroid(),得到该圆弧的中点坐标:

const centroid = arcGenerator.startAngle(0).endAngle(angleDaysWithPrecipitation_rad).centroid();

将中点坐标输出到控制台,可以看到形心为包含两个坐标值的数组组成,分别为形心的水平与垂直坐标值,本例即为 [89, -45]

在以下代码片段中,我们向内部图表选择集添加了一个 text 元素来创建文本标签。为了让标签值带有百分号 %,这里用到了 D3 的格式化方法 d3.format(".0%"),然后在后面的括号中传入指定的数值。该方法可以轻松实现数字的各种格式化表示,如货币、百分比及指数形式;也可以为数字添加指定的后缀,如表示百万的 M 以及表示微米数量级的 μ。具体的格式转换列表详见 d3-format 模块的官方文档。

接着,我们使用 centroid() 方法返回的坐标数组完成 xy 属性的设置。注意,这里还指定了 text-anchor 属性和 dominant-baseline 属性,以确保文本标签在水平与垂直方向均相对 xy 属性居中渲染。

最后,将标签的字体颜色改为白色,粗细设为 500,以提高标签的可读性。保存项目后,带文本标签的弧形图效果应该与图 4.29 一致:

图 4.29 带文本标签的弧形图最终效果

【图 4.29 带文本标签的弧形图最终效果】

innerChart.append("text").text(d => d3.format(".0%")(percentageDaysWithPrecipitation/100)).attr("x", centroid[0]).attr("y", centroid[1]).attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("fill", "white").style("font-weight", 500);

至此,我们已经掌握了 D3 折线图、面积图以及弧形图的绘制方法。下一章,我们将利用布局生成工具(layout generators)让这些图形的绘制再提高一个档次!



另附:专栏文章连载期间 完全免费,后续 不排除 调整为收费专栏。对 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 本章小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/474949.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

element ui 走马灯一页展示多个数据实现

element ui 走马灯一页展示多个数据实现 element ui 走马灯一页展示多个数据实现 element ui 走马灯一页展示多个数据实现 主要是对走马灯的数据的操作,先看js处理 let list [{ i: 1, name: 1 },{ i: 2, name: 2 },{ i: 3, name: 3 },{ i: 4, name: 4 },]let newL…

使用MaxKB搭建知识库问答系统并接入个人网站(halo)

首发地址(欢迎大家访问):使用MaxKB搭建知识库问答系统并接入个人网站 前言 从OpenAI推出ChatGPT到现在,大模型已经渗透到各行各业,大模型也逐渐趋于平民化;从最开始对其理解、生成、强大的知识积累的惊叹&…

Linux进阶:软件安装、网络操作、端口、进程等

软件安装 yum 和 apt 均需要root权限 CentOS系统使用: yum [install remove search] [-y] 软件名称 install 安装remove 卸载search 搜索-y,自动确认 Ubuntu系统使用 apt [install remove search] [-y] 软件名称 install 安装remove 卸载search 搜索-y&…

如何解决飞书网页文字无法复制的问题

如何解决网页文字无法复制的问题?特别推荐提词宝防复制文案功能! 在日常工作和学习中,我们经常遇到一些网页文字无法复制的情况,无论是因为权限限制还是其他原因,手动输入内容不仅耗时费力,还容易出错。那…

STM32电源管理—实现低功耗

注: 本文是学习野火的指南针开发板过程的学习笔记,可能有误,详细请看B站野火官方配套视频教程(这个教程真的讲的很详细,请给官方三连吧) 在响应绿色发展的同时,在很多应用场合中都对电子设备的功…

Linux网络:守护进程

Linux网络:守护进程 会话进程组会话终端 守护进程setsiddaemon 在创建一个网络服务后,往往这个服务进程是一直运行的。但是对于大部分进程来说,如果退出终端,这个终端上创建的所有进程都会退出,这就导致进程的生命周期…

基于深度学习的文本信息提取方法研究(pytorch python textcnn框架)

💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

Seatunnel解决Excel中无法将数字类型转换成字符串类型以及源码打包

需求 需要实现将Excel中的数字类型的单元格像数据库中字符串类型的字段中推送 问题原因 Seatunnel在读取字段类型的时候都是使用强转的形式去获取数据的 假如说数据类型不一样的话直接强转就会报错 修改位置 org/apache/seatunnel/api/table/type/SeaTunnelRow.java org…

AntFlow 0.11.0版发布,增加springboot starter模块,一款设计上借鉴钉钉工作流的免费企业级审批流平台

AntFlow 0.11.0版发布,增加springboot starter模块,一款设计上借鉴钉钉工作流的免费企业级审批流平台 传统老牌工作流引擎比如activiti,flowable或者camunda等虽然功能强大,也被企业广泛采用,然后也存着在诸如学习曲线陡峭,上手难度大&#x…

UniAPP快速入门教程(一)

一、下载HBuilder 首先需要下载HBuilder开发工具,下载地址:https://www.dcloud.io/hbuilderx.htmlhttps://www.dcloud.io/hbuilder.html 选择Windows正式版.zip文件下载。下载解压后直接运行解压目录里的HBuilderX.exe就可以启动HBuilder。 UniApp的插件市场网址…

计算机网络 (5)数据通信的基础知识

前言 数据通信是一种以信息处理技术和计算机技术为基础的通信方式,它通过数据通信系统将数据以某种信号方式从一处传送到另一处,为计算机网络的应用和发展提供了技术支持和可靠的通信环境,是现代通信技术的关键部分。 一、数据通信的基本概念…

K8s学习笔记之了解k8s的网络模型

文章目录 docker 网络模型容器与容器之间,容器与宿主机之间如何通信容器访问外部网络外部网络访问容器 k8s 网络模型CNIpod 网络配置流程 k8s 热门网络插件介绍Flannel 来源Calico 来源Cilium 来源 k8s 网络插件的工作模式Flannel 的工作模式Calico 的工作模式BGP 和…

Python 三种方式实现自动化任务

在这篇文章中,我们将介绍一些用Python实现机器人过程自动化的包。机器人流程自动化(Robotic process automation,简称RPA)是指将鼠标点击和键盘按压自动化的过程,即模拟人类用户的操作。RPA用于各种应用程序&#xff0…

时代变迁对传统机器人等方向课程的巨大撕裂

2020年之后,全面转型新质课程规划,传统课程规划全部转为经验。 农耕-代表性生产关系-封建分配制度主要生产力-人力工业-代表性生产关系-资本分配制度工业分为机械时代,电气时代,信息时代;主要生产力-人力转为人脑&…

流程图图解@RequestBody @RequestPart @RequestParam @ModelAttribute

RequestBody 只能用一次,因为只有一个请求体 #mermaid-svg-8WZfkzl0GPvOiNj3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8WZfkzl0GPvOiNj3 .error-icon{fill:#552222;}#mermaid-svg-8WZfkzl0GPvOiNj…

学习记录:js算法(九十九):冗余连接

文章目录 冗余连接思路一 冗余连接 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数…

ISUP协议视频平台EasyCVR私有化部署视频平台如何实现RTMP推流将大疆无人机的视频画面回传?

在现代视频监控和流媒体技术领域,EasyCVR视频融合云平台以其卓越的性能和灵活性,成为了跨区域、网络化视频监控综合管理的理想选择。作为TSINGSEE青犀视频“云边端”架构体系中的核心组件,私有化部署视频平台EasyCVR不仅能够实现视频数据的集…

【Linux】Linux入门实操——进程管理(重点)

1. 概述 在 LINUX 中,每个执行的程序都称为一个进程。每一个进程都分配一个ID号(pid,进程号)。>windows > linux每个进程都可能以两种方式存在的。前台与后台,所谓前台进程就是用户目前的屏幕上可以进行操作的。后台进程则是实际在操作&#xff0…

Postman之安装及汉化基本使用介绍

Postman之安装及汉化 1.安装及汉化postman2.基本使用介绍2.1.基本功能:2.2.编辑、查看、设置环境、全局、集合变量2.3.复制代码片段2.4.运行集合中的所有请求及引用外部文件进行参数化 1.安装及汉化postman 下载安装包 首先可以到官网下载安装包,需要注…

百度AI人脸检测与对比

1.注册账号 打开网站 https://ai.baidu.com/ &#xff0c;注册百度账号并登录 2.创建应用 3.技术文档 https://ai.baidu.com/ai-doc/FACE/yk37c1u4t 4.Spring Boot简单集成测试 pom.xml 配置&#xff1a; <!--百度AI--> <dependency> <groupId>com.baidu.…