【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),则是一种由多段多项式函数组成的分段函数,用于平滑地连接一组给定的点(即控制点)。样条通过一组控制点来定义,它们通常是数据的离散采样值。 ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《机器学习by周志华》学习笔记-神经网络-04全局最小误差与局部极小误差

1、神经网络中误差的概念及公式 根据上文《逆误差传播算法》我们可以知道误差公式的演化: ① 第k个训练样例的误差函数: ②该训练集的累积误差函数: ③正则化误差目标函数: 其中: :表示第k个训练样例的误差;:表示连接权重和阈值任意参数;根据上文我们可知需要确定的参…

每日读则推(十四)——Meta Movie Gen: the most advanced media foundation models to-date

premiere n.首映,首次公演 v.首次公演(戏剧、音乐、电影) a.首要的,最早的 Today we’re premiering Meta Movie Gen: the most advanced media foundation models to-date. 迄今,到现在为止 …

大模型面试题全面总结:每一道都是硬核挑战

节前,我们组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂同学、参加社招和校招面试的同学,针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 今天分享…

c++文件操作中的seekp函数使用方法

seekp函数能设置输出流的位置 比如我先向文件输入了123456&#xff0c;现在我想在第四个字符后面再加上ABC&#xff0c;这个时候我们就可以用seekp函数来设置输出的位置 #include <iostream> #include <fstream> #include <string>using namespace std;int …

Python小白学习教程从入门到入坑------第二十三课 封装(语法进阶)

面向对象的三大特征&#xff1a;封装、继承、多态 一、封装 1.1 何为封装 封装&#xff1a;在Python中指的是隐藏对象中一些不希望被外部所访问到的属性或者方法。将复杂的信息、流程给包起来&#xff0c;内部处理&#xff0c;让使用者只需要通过简单的操作步骤&#xff0c;…

less解决function中return写法在浏览器被识别成Object导致样式失败的问题

问题描述&#xff1a; 一开始写的是: baseFontSize: 37.5px;//基于屏幕尺寸/10得出的基准font-size// return失败,浏览器显示为[object Object],[object Object] .pxToRem(px){value: px / baseFontSize * 1rem;return value; } 使用height: .pxToRem(40px);之后浏览器却是这…

OpenCV视觉分析之目标跟踪(4)目标跟踪类TrackerDaSiamRPN的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::TrackerDaSiamRPN 是 OpenCV 中用于目标跟踪的一个类&#xff0c;它实现了 DaSiam RPN&#xff08;Deformable Siamese Region Proposal Net…

高效视频制作大提速,视频剪辑软件的高级自定义命令功能批量调整视频的色调、饱和度和亮度,轻松驾驭视频编辑技巧

在浩瀚的数字海洋中&#xff0c;视频如同璀璨的星辰&#xff0c;而每一颗星辰都渴望被精心雕琢&#xff0c;闪耀出最独特的光芒。想象一下&#xff0c;你手握一把神奇的钥匙&#xff0c;能够轻松解锁批量视频剪辑的奥秘&#xff0c;让每一帧画面都跃动着你的创意与激情。这把钥…

Vue3入门--[vue/compiler-sfc] Unexpected token, expected “,“ (18:0)

新手小白学习Vue–入门就踩坑系列 问题描述 创建了一个Person.vue&#xff0c;保存后直接报错&#xff1a; [plugin:vite:vue] [vue/compiler-sfc] Unexpected token, expected "," (18:0) 在网上搜了半天也没找到原因&#xff0c;最后还得靠自己&#xff0c;现将解…

【制造业&盒子】箱子检测系统源码&数据集全套:改进yolo11-swintransformer

改进yolo11-MLCA等200全套创新点大全&#xff1a;箱子检测系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.11.01 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者视频可能为…

Spring Security 框架篇-深入了解 Spring Security 的认证功能流程和自定义实现登录接口(实现自定义认证过滤器、登出功能)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Spring Security 框架概述 2.0 Spring Security 核心功能-认证功能 2.1 过滤器链 2.2 登录认证流程 2.3 思路分析 3.0 登录认证具体操作 3.1 环境搭建 3.2 实现 U…

HBuilderx修改主题色-改变编辑器背景颜色等

效果图&#xff1a; 第一步我们打开HBuilderX 选择工具 – 主题 – 选择&#xff08;雅蓝&#xff09; 然后再设置&#xff0c;源码视图里面打开Setting.json文件 3.将一下代码赋值到右侧用户设置即可 {"workbench.colorCustomizations": {// "[Defau…

食堂采购系统源码:实现供应链管理平台功能模块的技术实践

在当前数字化转型浪潮中&#xff0c;餐饮和食堂管理的需求越来越高&#xff0c;食堂采购系统逐渐成为企业和组织优化管理、降低成本的关键工具。 一、食堂采购系统的核心功能概述 一个完善的食堂采购系统不仅需要具备传统的订单管理、库存管理、供应商管理功能&#xff0c;还…

Python 工具库每日推荐 【Sphinx】

文章目录 引言文档工具的重要性今日推荐:Sphinx 文档生成工具主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:为 Python 项目生成 API 文档案例分析高级特性自定义主题国际化支持扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 TypeScript …

stm32不小心把SWD和JTAG都给关了,程序下载不进去,怎么办?

因为想用STM32F103的PA15引脚&#xff0c;调试程序的时候不小心把SWD和JTAD接口都给关了&#xff0c;先看下罪魁祸首 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关掉JTAG&#xff0c;不关SWGPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//关掉SW&am…

Transformer+KAN系列时间序列预测代码

前段时间&#xff0c;来自 MIT 等机构的研究者提出了一种非常有潜力的替代方法 ——KAN。该方法在准确性和可解释性方面表现优于 MLP。而且&#xff0c;它能以非常少的参数量胜过以更大参数量运行的 MLP。 KAN的发布&#xff0c;引起了AI社区大量的关注与讨论&#xff0c;同时…

【OD-支持在线评测】文本统计分析(200分)

📎 在线评测链接 https://app5938.acapp.acwing.com.cn/contest/11/problem/OD1076 🍓 OJ题目截图 🍿 最新机试E卷,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 🌍 评测功能需要 ⇒ 订阅专栏 ⇐ 后私信联系解锁~ 文章目录 📎…

C++(友元、异常机制、静态成员、单例模式)

友元 友元可以访问与其好友关系的类中的私有成员&#xff0c;使用friend关键字进行修饰。&#xff08;友元破坏了类的封装性&#xff09;。 特点 &#xff08;1&#xff09;友元是单向的 &#xff08;2&#xff09;友元不能传递 &#xff08;3&#xff09;友元…

HTML 基础标签——表格标签<table>

文章目录 1. `<table>` 标签:定义表格2. `<tr>` 标签:定义表格行3. `<th>` 标签:定义表头单元格4. `<td>` 标签:定义表格单元格5. `<caption>` 标签:为表格添加标题6. `<thead>` 标签:定义表格头部7. `<tbody>` 标签:定义表格…

ElementUI中el-table双击单元格显示输入框

效果图 实现 <el-table:data"formData.products"row-key"id":show-header"true"style"width: 100%; margin-top: 16px"class"zq-table-theme-info"bordercell-dblclick"handleDbClick"> <el-table-col…