【D3.js in Action 3 精译_038】4.2 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 本章小结
    • 第四章 直线、曲线与弧线的绘制 ✔️
      • 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.2 折线图的绘制 Drawing a line chart
      • 4.2.1 直线生成工具的使用 Using the line generator
      • 4.2.2 对数据点作曲线插值处理 Interpolating data points into a curve

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

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

译者按
上一节我们学习了 D3 时间坐标轴与线性轴的绘制方法,这一节就可以正式开始折线图的绘制了,根据最终的示例效果,该折线图包含折线部分和面积图部分,本篇只涉及纯折线部分;面积图的实现则放到下一节介绍。

4.2 折线图的绘制 Drawing a line chart

下面实现数据可视化最常见的一类图表:折线图。折线图由连接各数据点的线段、或对这些数据点作插值计算而得到的曲线组成。它们通常用于展示某个现象随时间的演变过程。在 D3 中,这些线条和曲线由 SVG 路径元素(path elements)构建,其形状由 SVG 路径元素的 d 属性(attribute)决定。通过第 1 章的学习,我们知道了 d 属性是由一系列命令组成的;这些命令决定了绘制的形状。此外还提到过,d 属性很容易变得很复杂。所幸 d3-shape 模块提供了生成直线和曲线的工具函数,专门负责 d 属性的计算,从而简化了折线图的创建。

本节将绘制一条反映 2021 年纽约市平均气温变化趋势的直线/曲线,具体效果参考线上项目(http://mng.bz/5orB)或前面章节中的图 4.1。在此之前,先来绘制每个数据点。尽管折线图未必非要画出数据点,但它们有助于理解 D3 折线生成工具的工作原理。

由于专栏文章是分章节发表,这里直接给出图 4.1 的效果:

图 4.1 本章实现项目:2021 年纽约市温度变化及全年降水天数占比情况可视化

【图 4.1 本章实现项目:2021 年纽约市温度变化及全年降水天数占比情况可视化】

在函数 drawLineChart() 中,通过 D3 的数据绑定为数据集 weekly_temperature.csv 中的每一行创建一个 circle 元素,然后添加到选择集 innerChart 中,半径设为 4px。然后用 xy 方向的比例尺分别计算每个圆心的横纵坐标。

回忆一下第 3 章介绍的数据绑定相关知识点,这里需要用到访问器函数(accessor function)来访问每个圆上的绑定数据。在以下代码片段中,d 即为每个 circle 元素绑定的数据项。由于 data 是一个 JavaScript 对象,这里可以通过句点表示法拿到对应的日期和平均气温。相关知识点详见第 3 章 3.3.1 小节。

注意,这里特地声明了一个名为 aubergine (译注:读作 /ˈəʊbəʒiːn/,紫红色)的颜色常量,用于指定圆的 fill 属性值。因为示例项目还会多次用到该颜色,因此单独声明为一个常量。您也可以根据自己的喜好启用任意颜色:

const aubergine = "#75485E";
innerChart.selectAll("circle") // 利用数据绑定模式为数据集中的每一行添加一个圆.data(data)          .join("circle")      .attr("r", 4).attr("cx", d => xScale(d.date)) // 根据绑定数据使用比例尺来定位数据点.attr("cy", d => yScale(d.avg_temp_F)) .attr("fill", aubergine);

保存项目并在浏览器中查看图形,就能看到这些 circle 元素呈穹顶状分布于 29°F80°F 之间,如图 4.13 所示:

图 4.13 平均气温随时间变化的数据点绘制效果图

【图 4.13 平均气温随时间变化的数据点绘制效果图】

此处也可以绘制散点图(scatterplots)

走到这一步必须要强调的一个惊喜是,您已经在不知不觉间学会了 D3 散点图(scatterplots)的绘制!散点图 是一种简单的图表,用于展示 x 轴与 y 轴的数据点集合,可以直观地揭示两个或多个变量间的相关关系。

只要知道了坐标轴的绘制方法,再结合绑定数据定位屏幕上的每个数据点,您就完全可以绘制出一个散点图效果——这正是 D3 的魅力所在——不必特地去学怎样绘制特定的图表类型,而是通过创建并组合一些基本要素来构建可视化效果。对于散点图而言,这些基本要素甚至可以简单到仅仅包含两个坐标轴和一组 circle 元素。第 7 章我们还将实现一个散点图,让圆的面积根据变量的值而同步变化。

图 4.13.1 D3 散点图示例效果

【图 4.13.1 D3 散点图示例效果】

4.2.1 直线生成工具的使用 Using the line generator

至此,每个数据点的位置就画好了,接下来介绍 D3 的直线生成工具(line generator)。直线生成工具 d3.line() 是一个函数,它以各数据点的横纵坐标为输入,并将穿过这些数据点的 SVG 路径元素或折线(polyline)的 d 属性值作为输出。通常需要在直线生成器上链式调用 x()y() 两个访问器函数,并分别传入水平和垂直位置的坐标值,如图 4.14 所示:

图 4.14 直线生成工具 d3.line() 函数与访问器函数 x() 和 y() 的组合式写法。后者需分别将各数据点的横纵坐标作为参数传入。

【图 4.14 直线生成工具 d3.line() 函数与访问器函数 x() 和 y() 的组合式写法。后者需分别将各数据点的横纵坐标作为参数传入。】

下面来给折线图创建一个直线生成工具函数。首先调用 d3.line() 方法,然后分别链式调用访问器函数 x()y()x() 需要传入各数据点的水平坐标,这里通过参数 d 来访问每个绑定数据项,类似遍历数组时用到的循环变量。数据点的水平坐标可以通过对应的日期和水平比例尺函数 xScale() 计算得出;同理,垂直坐标则可以通过当天的平均气温结合纵向比例尺 yScale() 得到。最后将生成的工具函数赋给常量 lineGenerator 备用:

const lineGenerator = d3.line().x(d => xScale(d.date)) // 每个数据点的水平位置.y(d => yScale(d.avg_temp_F)); // 每个数据点的垂直位置

接着,调用该工具函数,并将数据集 data 作为参数传入,其结果作为 path 元素 d 属性的属性值。

SVG 路径元素默认按黑色渲染图形,如果只想看到一条折线,则需要令 fill 属性为 nonetransparent,并将 stroke 属性(attribute)指定为想要的描边色;本例中即为 aubergine 紫红色。绘制效果如图 4.15 所示:

innerChart.append("path").attr("d", lineGenerator(data)) // 利用行生成工具将数据集作为参数传入.attr("fill", "none").attr("stroke", aubergine);

图 4.15 利用 D3 直线生成工具创建的 SVG 路径元素穿过每个数据点,形成了一条折线

【图 4.15 利用 D3 直线生成工具创建的 SVG 路径元素穿过每个数据点,形成了一条折线】

4.2.2 对数据点作曲线插值处理 Interpolating data points into a curve

在这个示例折线图中,离散数据点分布在整个数据范围内,用普通的折线段来连接数据点就能实现既定目标;但偶尔也会在数据点之间对数据作插值处理 1。为此,D3 提供了多种插值函数(interpolation functions)来生成曲线。

曲线生成工具是以 d3.line() 的访问器函数的形式出现的。要将刚才的直线工具函数变为曲线工具函数,只需要再链式调用一个访问器函数 curve() 即可,参数为 D3 的某个内置插值函数。如以下代码片段所示,传入参数为 d3.curveCatmullRom 2,它可以生成一个 立方样条曲线(cubic spline) (根据各数据点并结合三阶多项式函数计算得到的平滑而灵活的图形)。其渲染效果如图 4.16 所示。

const curveGenerator = d3.line().x(d => xScale(d.date)).y(d => yScale(d.avg_temp_F).curve(d3.curveCatmullRom);

图 4.16 利用 Catmull-Rom 插值算法绘制的折线图效果

【图 4.16 利用 Catmull-Rom 插值算法绘制的折线图效果】

关于最佳插值算法 What’s the best interpolation?

插值处理会修改数据呈现方式,不同的插值函数会产生不同的可视化效果。数据的可视化方式多种多样,从编程角度理解,这些方式方法都是合理的;但关键是让可视化效果传递客观实际(actual phenomena)。

由于数据可视化涉及统计原理的视觉呈现,因此也面临着误用统计数据带来的风险(dangers of misusing statistics)。其中线性插值是数据误用的重灾区,因为它能将看似粗糙的直线段处理成平滑自然的曲线段。

如图 4.17 所示,同一组折线数据在不同的曲线插值处理下将呈现不同的视觉效果。选择适当的插值函数很大程度上取决于目标数据集。在本节演示的折线图中,d3.curveBasis 会拉直曲线段的同时减少其变化,这显然不适合我们的示例数据。如果不在图表上绘制出数据点作对比,就无从知晓曲线段与这些数据点的误差。因此,甄选和测试曲线插值函数就显得尤为重要了。

图 4.17 不同的曲线插值处理对数据都有不同程度地修改

【图 4.17 不同的曲线插值处理对数据都有不同程度地修改】

与此同时,函数 d3.curveMonotoneXd3.curveCatmullRom 创建的插值曲线则紧挨数据点,与原始折线图相似;此外,d3.curveStep 函数还可以在适当的情况下对数据作另类处理。图 4.17 只给出了部分插值情况对比,还有一些插值工具还可以设置一些影响最终曲线形状的参数,具体配置情况,详见 d3-shape 模块相关文档。

这样 D3 折线图的绘制就完成了!再复盘梳理一下:首先需要初始化一个直线生成工具函数,并设置其访问函数 x()y(),如图 4.18 所示。这两个函数分别用于计算每个数据点的水平与垂直坐标;接着可以链式调用 curve() 访问器函数并指定插值算法,将直线段改为曲线段;最后,在绘图区添加 SVG 路径元素 path,并通过调用直线生成工具函数、传入数据集 data 来设置路径元素的 d 属性。第 7 章还将利用工具提示(tooltip)组件提升折线图的可交互性。如果想立即学习,也可以直接跳到该章节(译注:待翻译)。

图 4.18 D3 折线图的实现步骤

【图 4.18 D3 折线图的实现步骤】


  1. 插值 是一个数学和统计学领域的专用术语,指的是在已知数据点之间估算出新的数据点,常用于图表或曲线的平滑处理。 ↩︎

  2. d3.curveCatmullRomCatmull-Rom 样条,也叫 卡特穆尔-罗姆插值,它在计算机图形学和数据可视化领域应用广泛,是一种能够有效生成平滑曲线的数学方法描述。所谓样条(Spline),则是一种由多段多项式函数组成的分段函数,用于平滑地连接一组给定的点(即控制点)。样条通过一组控制点来定义,它们通常是数据的离散采样值。 ↩︎

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

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

相关文章

Git 的分支管理

一、分支介绍 1、分支是什么 Git作为一个分布式版本控制系统,提供了强大而灵活的分支管理功能,使得开发团队能够高效地协作开发、管理不同的功能和版本。 2、为什么有分支 一般情况下主分支(master/main)应始终保持可部署的状…

Linux环境基础和基础开发工具使用

文章目录 一、yum软件管理器1、包管理器2、yum3、apt4、安装源 二、编辑器vim1、各种模式2、打开时直接让光标定位到指定号3、!加命令字符 三、命令模式1、i 进入插入模式2、**Shift :** 进入底行模式3、光标定位4、ZZ(大写)保存并退出vim5、…

【java】哈希<两数之和> 理解哈希

两数之和 题目描述: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。 你…

【Linux】信号三部曲——产生、保存、处理

信号 1. 信号的概念2. 进程如何看待信号3. 信号的产生3.1. kill命令3.2. 终端按键3.2.1. 核心转储core dump3.2.2. OS如何知道键盘在输入数据 3.3. 系统调用3.3.1. kill3.3.2. raise3.3.3. abort 3.4. 软件条件3.4.1. SIGPIPE信号3.4.2. SIGALRM信号 3.5. 硬件异常3.5.1. 除零异…

Vue 计算属性和监听器

文章目录 一、计算属性1. 计算属性定义2. computed 比较 methods3. 计算属性完整写法 二、监听器1. 普通监听2. 添加额外配置项 一、计算属性 1. 计算属性定义 概念:基于现有的数据,计算出来的新属性,依赖的数据变化,自动重新计…

【计网】实现reactor反应堆模型 --- 框架搭建

没有一颗星, 会因为追求梦想而受伤, 当你真心渴望某样东西时, 整个宇宙都会来帮忙。 --- 保罗・戈埃罗 《牧羊少年奇幻之旅》--- 实现Reactor反应堆模型 1 前言2 框架搭建3 准备工作4 Reactor类的设计5 Connection连接接口6 回调方法 1 …

外包干了2年,快要废了。。。

先说一下自己的情况,普通本科毕业,在外包干了2年多的功能测试,这几年因为大环境不好,我整个人心惊胆战的,怕自己卷铺盖走人了,我感觉自己不能够在这样蹉跎下去了,长时间呆在一个舒适的环境真的会…

linux驱动-i2c子系统框架学习(2)

linux驱动-i2c子系统框架学习(1) 在这篇博客里面已经交代了i2c设备驱动层,主要的功能就是编写具体i2c的外设驱动,和创建设备接点给上层使用 ,按之前学习的字符设备,有了设备节点,就可以对硬件操作了,在i2c…

Webserver(4.6)poll和epoll

目录 pollclient.cpoll.c epollepoll.cclient.c epoll的两种工作模式水平触发边沿触发 poll poll是对select的一个改进 select的缺点在于每次都需要将fd集合从用户态拷贝到内核态,开销很大。每次调用select都需要在内核遍历传递进来的所有fd,这个开销也…

Stable Diffusion的解读(一)

Stable Diffusion的解读(一) 文章目录 Stable Diffusion的解读(一)摘要Abstract一、机器学习部分1. Stable Diffusion的早期工作1.1 从编码器谈起1.2 第一条路线:VAE和DDPM1.3 第二条路线:VQVAE1.4 路线的交…

计算机网络——TCP篇

TCP篇 基本认知 TCP和UDP的区别? TCP 和 UDP 可以使用同一个端口吗? 可以的 传输层中 TCP 和 UDP在内核中是两个完全独立的软件模块。可以根据协议字段来选择不同的模块来处理。 TCP 连接建立 TCP 三次握手过程是怎样的? 一次握手:客户端发送带有 …

ROS话题通信机制理论模型的学习

话题通信是ROS(Robot Operating System,机器人操作系统)中使用频率最高的一种通信模式,其实现模型主要基于发布/订阅模式。 一、基本概念 话题通信模型中涉及三个主要角色: ROS Master(管理者&#xff0…

【Android】名不符实的Window类

1.“名不符实”的Window类 Window 是一个窗口的概念,是所有视图的载体,不管是 Activity,Dialog,还是 Toast,他们的视图都是附加在 Window 上面的。例如在桌面显示一个悬浮窗,就需要用到 Window 来实现。Wi…

后端java——如何为你的网页设置一个验证码

目录 1、工具的准备 2.基本方法 3.实现类 4.实践 HTML文件: Java文件1:创建验证码 Java文件2:验证验证码 本文通过HUTOOL实现:Hutool参考文档Hutool,Java工具集https://hutool.cn/docs/#/ 1、工具的准备 如果我们通过hutool来实现这个…

【go从零单排】Strings and Runes 字符串和字符

Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 概念 在Go语言中,rune 是一个内置的数据类型,用于表示一个Unicode字符。它实际上是一个别名…

如何在本地Linux服务器搭建WordPress网站结合内网穿透随时随地可访问

文章目录 前言1. 安装WordPress2. 创建WordPress数据库3. 安装相对URL插件4. 安装内网穿透发布网站4.1 命令行方式:4.2. 配置wordpress公网地址 5. 配置WordPress固定公网地址 前言 本文主要介绍如何在Linux Ubuntu系统上使用WordPress搭建一个本地网站&#xff0c…

vue data变量之间相互赋值或进行数据联动

摘要: 使用vue时开发会用到data中是数据是相互驱动,经常会想到watch,computed,总结一下! 直接赋值: 在 data 函数中定义的变量可以直接在方法中进行赋值。 export default {data() {return {a: 1,b: 2};},methods: {u…

在 Java 中使用脚本语言

在 Java 中使用脚本语言,特别是在 Java 平台上集成如 Python、JavaScript 或 Ruby 等语言,通常可以通过 Java 的 Scripting API 来实现。这个 API 基于 JSR 223(“Scripting for the Java Platform”),提供了一种标准方…

大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…

微服务系列六:分布式事务与seata

目录 实验环境说明 前言 一、分布式事务问题与策略 1.1 分布式事务介绍 1.2 分布式事务解决策略分析 二、分布式事务解决方案 Seata 2.1 认识Seata 2.2 Seata的工作原理 2.3 部署Seata微服务 2.3.1 准备数据库表 2.3.2 准备配置文件 2.3.3 docker部署 2.4 微服务集…