【D3.js in Action 3 精译_026】3.4 小节 DIY 实战:基于 Mocha 在浏览器客户端测试 D3 线性比例尺

news2024/11/19 12:36:07

当前内容所在位置(可进入专栏查看其他译好的章节内容)

  • 第一部分 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.5 加注图表标签
      • 3.6 本章小结

文章目录

  • 基于 Mocha 测试 D3 线性比例尺(DIY 实战)
    • 1 需求描述
    • 2 项目基础环境搭建
    • 3 Mocha 测试环境搭建
    • 4 测试结果分析
    • 5 结语

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

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

基于 Mocha 测试 D3 线性比例尺(DIY 实战)


前言

之前一直在鼓励大家跟着我的介绍把专栏里的代码和数据放到本地跑一跑。想着前面这些基础过于简单,就没当回事。昨天讲到线性比例尺(点 这里 查看原文),作者又让大家测试,刚好也想试试在浏览器环境运行测试工具 Mocha,就顺便动手试了试。没想到问题还挺多的。算是抛砖引玉吧。

1 需求描述

按照 3.4.2 小节最后一张截图(如下所示),将图中的测试数据放到本地实测一遍,看看 D3 的线性比例尺函数是否能得到同样的结果。

图 1 《D3.js in Action》第 3.4.2 节最后的示意图里给出的测试数据

【图 1 《D3.js in Action》第 3.4.2 节最后的示意图里给出的测试数据】

写成代码就是:

xScale(198) // => 83
xScale(414) // => 173
xScale(852) // => 356
xScale(1078) // => 450

2 项目基础环境搭建

根据我自己上传的【附件】,解压后用 VSCode 打开里面的 start 文件夹,初始界面应该是这样的:

图 2 解压文件后用 VSCode 打开 start 文件夹看到的初始目录结构

【图 2 解压文件后用 VSCode 打开 start 文件夹看到的初始目录结构】

既然是本地化改造,D3 的 CDN 远程引用就改成本地引用,于是 index.html 就成了这样:

图 3 将 D3 的 CDN 远程调用改为本地引用

【图 3 将 D3 的 CDN 远程调用改为本地引用】

一不做二不休,再给这个本地项目配个 D3 官方图标:

图 4 从 D3 官网(https://d3js.org/)搬过来的图标(防止 Live Server 首次启动报 404 错误)

【图 4 从 D3 官网(https://d3js.org/)搬过来的图标(防止 Live Server 首次启动报 404 错误)】

效果还不赖:

图 5 添加 D3 图标后的浏览器标签效果

【图 5 添加 D3 图标后的浏览器标签效果】

原来标签页上面的标题还是 3.3 小节的,既然是实测练习,就一起更新了吧:

<title>3.4 Linear scale | D3.js in Action</title>

接着,是按要求修改样式表 main.css

代码清单 DIY-1 修改后的 main.css

.responsive-svg-container {
  margin-inline: auto;  /* 使用 CSS3 的逻辑属性*/
  width: 100%;
  max-width: 800px;  /* 宽度改小到 800px 即可 */
}

然后是精简 main.js 的代码:

代码清单 DIY-2 精简后的页面绘图逻辑

// Append a SVG container
const svg = d3.select(".responsive-svg-container")
  .append("svg")
    .attr("viewBox", "0 0 600 700")  // 同步改小 viewBox 的尺寸
    .style("border", "1px solid black");

// Load, format and measure the dataset
d3.csv("../data/data.csv", d => ({
  technology: d.technology,
  count: +d.count
})).then(data => {
  data.sort((a, b) => b.count - a.count);
  createViz(data);
});

// Create the bar graph
const createViz = (data) => {

  // 创建 X 轴的比例尺函数
  const xScale = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.count)])
    .range([0, 450]); // (= 600 - 100 - 50 (px))

  // 运行测试
  testXScale(xScale);

  // Use data-binding to append rectangles
  const barHeight = 20;
  svg.selectAll('rect')
    .data(data)
    .join('rect')
      .attr('class', d => `bar bar-${d.technology}`)
      .attr('width', d => d.count)
      .attr('height', barHeight)
      .attr('x', 0)
      .attr('y', (d, i) => (barHeight + 5) * i)
      .attr('fill', d => d.technology === 'D3.js' ? 'yellowgreen' : 'skyblue');

};

// 测试 xScale 函数
const testXScale = (xScale) => {
  console.log('Testing the xScale ...');
};

作为对比,先看看使用比例尺函数前的效果:

图 6 比例尺调用前绘制的条形图效果

【图 6 比例尺调用前绘制的条形图效果】

此时只需修改一行 JS 代码就能让比例尺生效(即上段代码第 33 行):

svg.selectAll('rect')
// ...
    .attr('width', d => xScale(d.count))
// ...

效果如下:

图 7 比例尺调用后绘制的条形图效果

【图 7 比例尺调用后绘制的条形图效果】

至此,3.4.2 小节的主线任务就算完成了。接下来是我给自己定的支线任务,这是本次测试的核心环节:用 Mocha 在本地搭一个测试环境,验证原文的图 3.26 中那四组数据。

3 Mocha 测试环境搭建

首先引入测试库 Mocha.js 及断言工具库 Chai.js,由于是用在浏览器客户端(即写入 <script> 标签),因此这两个库 必须是 UMD 版本(这个坑我帮各位提前踩了)。最后再引入 Mocha 的样式表 mocha.css(同样从 CDN 下载到本地,URL:https://unpkg.com/mocha/mocha.css),于是 index.html 就改成了:

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>3.4 Linear scale | D3.js in Action</title>
	<link rel="stylesheet" type="text/css" href="css/main.css">
	<link rel="shortcut icon" href="logo.png" type="image/x-icon">
	<!-- Load Mocha CSS -->
	<link rel="stylesheet" href="css/mocha.css">
</head>
<body>
	<div class="responsive-svg-container"></div>
	<div id="mocha"></div><!-- test result container -->

	<!-- Load your scripts here -->
	<script src="js/d3.v7.min.js"></script>
	<script src="js/main.js"></script>
	<!-- use Mocha to test linear scale xScale -->
	<script src="js/mocha.js"></script>
    <script src="js/chai.min.js"></script>
</body>

接着再来实现具体的测试逻辑,对 testXScale 函数做如下改造:

const testXScale = (xScale) => {
  // console.log('Testing the xScale ...');
  const testData = new Map([
    [198, 83],
    [414, 173],
    [852, 356],
    [1078, 450]
  ]);

  mocha.setup('bdd');
  const { expect } = chai;

  // 测试用例
  describe('Test xScale function:', () => {
    testData.forEach((expected, domain) => {
      it(`Given a domain value ${domain}, should return ${expected}.`, () => {
        expect(xScale(domain)).to.equal(expected);
      });
    });
  });

  // 运行测试
  mocha.run();
};

注意,describeit 原语都是 Mocha 的全局函数,不用像 expect 那样声明。利用 Live Server 重新启动项目(快捷键:Alt + LO),页面滚动到最后,将看到如下效果:

图 8 因计算值存在误差,四组数据有三组未能通过测试

【图 8 因计算值存在误差,四组数据有三组未能通过测试】

4 测试结果分析

原来,D3 线性比例尺只能对观测点数据作 近似处理,除了端点位置能完全相等,其余计算值在拟合过程中都是存在误差的。

这也很好理解,得票数 count 按比例缩放到 450px 以内的宽度显示,肯定存在分母除不尽的情况,加之 JavaScript 自身浮点数就有精度误差,中间的计算值和原始数据完全相同的概率极低。

此时,不妨设置一个误差边界(比如 1),只要实际误差不超过这个边界,就算通过测试:

describe('Test xScale function:', () => {
  testData.forEach((expected, domain) => {
    it(`Given a domain value ${domain}, should return ${expected}.`, () => {
      // expect(xScale(domain)).to.equal(expected);
      const actual = xScale(domain);
      const diff = Math.abs(actual - expected);
      expect(diff).to.be.lessThan(1);
    });
  });
});

这样就全部通过了:

图 9 许用误差放宽到 1 时的数据实测情况:四组数据均测试通过

【图 9 许用误差放宽到 1 时的数据实测情况:四组数据均测试通过】

另外,d3.csv() 方法除了 Promise 这种风格,还支持 async-await 语法糖:

// Load, format and measure the dataset
const drawBarChart = async () => {
  const csvData = await d3.csv('../data/data.csv');
  const data = csvData.map(({technology, count}) => ({
        technology, 
        count: +count
      }))
      .sort((a, b) => b.count - a.count);

  createViz(data);
};
drawBarChart();

这个版本的 JS 代码我也放到项目文件里了(即 main0.js),需要的小伙伴可以尝试尝试。

5 结语

真是应了那句老话 ——

纸上得来终觉浅,绝知此事要躬行。

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

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

相关文章

力扣(leetcode)每日一题 2286 以组为单位订音乐会的门票 | 线段树

2286. 以组为单位订音乐会的门票 题干 一个音乐会总共有 n 排座位&#xff0c;编号从 0 到 n - 1 &#xff0c;每一排有 m 个座椅&#xff0c;编号为 0 到 m - 1 。你需要设计一个买票系统&#xff0c;针对以下情况进行座位安排&#xff1a; 同一组的 k 位观众坐在 同一排座…

物联网实训室建设的必要性

物联网实训室建设的必要性 一、物联网发展的背景 物联网&#xff08;IoT&#xff09;是指通过信息传感设备&#xff0c;按照约定的协议&#xff0c;将任何物品与互联网连接起来&#xff0c;进行信息交换和通信&#xff0c;以实现智能化识别、定位、跟踪、监控和管理的一种网络…

c语言实例 068

大家好&#xff0c;欢迎来到无限大的频道 今天给大家带来的是c语言。 题目描述 创建一个单链表&#xff0c;进行存储数据并且打印 创建一个单链表的基本步骤包括定义链表节点的结构体、实现插入数据的功能&#xff0c;以及打印链表的内容。以下是一个简单的C语言示例&#…

QT将QBytearray的data()指针赋值给结构体指针变量后数据不正确的问题

1、问题代码 #include <QCoreApplication>#pragma pack(push, 1) typedef struct {int a; // 4字节float b; // 4字节char c; // 1字节int *d; // 8字节 }testStruct; #pragma pack(pop)#include <QByteArray> #include <QDebug>int main() {testStruct …

【C++前缀和 数论 贪心】2245. 转角路径的乘积中最多能有几个尾随零|2036

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 质数、最大公约数、菲蜀定理 贪心&#xff08;决策包容性) LeetCode2245. 转角路径的乘积中最多能有几个尾随零 给你一个二维整数数组 grid &#xff0c;大小为 m x …

【有啥问啥】二分图(Bipartite Graph)算法原理详解

二分图&#xff08;Bipartite Graph&#xff09;算法原理详解 引言 二分图&#xff08;Bipartite Graph&#xff09;&#xff0c;又称二部图&#xff0c;是图论中的一个重要概念。在实际应用中&#xff0c;二分图模型经常用于解决如匹配问题、覆盖问题和独立集问题等。本文将…

实验2思科网院项目2.7.2-packet-tracer---configure-single-area-ospfv2---实践练习

实践练习 2.7.2-packet-tracer---configure-single-area-ospfv2---实践练习physical-mode 实验拓扑 相关设备配置 实验目标: 第 1 部分&#xff1a;构建网络并配置设备的基本设置 第 2 部分&#xff1a;配置和验证单区域 OSPFv2 的基本部署 第 3 部分&#xff1a;优化和验…

【STM32】 TCP/IP通信协议(3)--LwIP网络接口

LwIP协议栈支持多种不同的网络接口&#xff08;网卡&#xff09;&#xff0c;由于网卡是直接跟硬件平台打交道&#xff0c;硬件不同则处理也是不同。那Iwip如何兼容这些不同的网卡呢&#xff1f; LwIP提供统一的接口&#xff0c;底层函数需要用户自行完成&#xff0c;例如网卡的…

动态时钟控件:Qt/C++ 项目代码解读

基于Qt的动态时钟控件项目。该项目展示了如何通过Qt的绘图系统绘制一个带有表盘背景、时针、分针、秒针、以及时间日期显示的时钟。同时&#xff0c;这个时钟控件支持背景切换&#xff0c;并且每秒钟刷新一次&#xff0c;实时显示当前时间。 项目结构与功能概述 该时钟控件主…

Redis接口访问优化

说明&#xff1a;之前写过一篇使用Redis接口访问的博客&#xff0c;如下。最近有相关需求&#xff0c;把代码拿出来后&#xff0c;做了一些优化&#xff0c;挺有意思的&#xff0c;本文介绍在原基础上 使用Redis实现接口防抖 优化 总的来说&#xff0c;这次使用Redis实现接口…

自动驾驶汽车横向控制方法研究综述

【摘要】 为实现精确、稳定的横向控制&#xff0c;提高车辆自主行驶的安全性和保障乘坐舒适性&#xff0c;综述了近年来自动驾驶汽车横向控制方法的最新进展&#xff0c;包括经典控制方法和基于深度学习的方法&#xff0c;讨论了各类方法的性能特点及在应用中的优缺点&#xff…

【初阶数据结构】详解插入排序 希尔排序(内含排序的概念和意义)

文章目录 前言1. 排序的概念及其应用1.1 排序的概念1.2 排序的应用 2. 插入排序2.1 基本思想2.2 插入排序的代码实现2.3 插入排序算法总结 3. 希尔排序3.1 基本思想3.2 希尔排序的代码实现3.3 希尔排序的特征总结 前言 初级数据结构系列已经进入到了排序的部分了。相信大家听到…

计算机毕业设计 服装生产信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

记录|Modbus-TCP产品使用记录【德克威尔】

目录 前言一、德克威尔1.1 实验图1.2 DECOWELL IO Tester 软件1.3 读写设置1.4 C#进行Modbus-TCP读写 更新时间 前言 参考文章&#xff1a; 使用的第二款Modbus-TCP产品。 一、德克威尔 1.1 实验图 1.2 DECOWELL IO Tester 软件 这也是自带模块配置软件的。下图就是德克威尔的…

“Xian”(籼)和“Geng”(粳)米怎么读?

2018年&#xff0c;《自然》上刊登了一篇有关亚洲栽培稻基因组变异的重磅论文。研究成果本身自然引人关注&#xff0c;但更引人关注的是&#xff0c;这篇论文首次提出以“Xian”&#xff08;籼&#xff09;和“Geng”&#xff08;粳&#xff09;两个汉语农业术语代替Indica和Ja…

yum使用阿里云的镜像源报错 Failed connect to mirrors.aliyuncs.com:80; Connection refused“

报错&#xff1a;Failed connect to mirrors.aliyuncs.com:80; Connection refused"&#xff0c;如果单独只是这个报错的话&#xff0c;那么原因是由于非阿里云ECS用户无法解析主机“mirrors.cloud.aliyuncs.com”。如果不单单只是这个报错另外还有其它报错请参考我其它文…

Threejs创建正多边体

上一章节实现了球体的绘制&#xff0c;这节来绘制多面体&#xff0c;包括正多面体&#xff0c;平面中&#xff0c;每条边一样长组成的图形叫正多边形&#xff0c;这里每个面一样&#xff0c;叫正多面体。如上文一样&#xff0c;先要创建出基础的组件&#xff0c;包括场景&#…

C++基础---类和对象(上)

1.类的定义 C程序设计允许程序员使用类&#xff08;class&#xff09;定义特定程序中的数据类型。这些数据类型的实例被称为对象 &#xff0c;这些实例可以包含程序员定义的成员变量、常量、成员函数&#xff0c;以及重载的运算符。语法上&#xff0c;类似C中结构体&#xff0…

【机器学习】任务六:分类算法(支持向量机(SVM)在线性可分与不可分数据中的应用与可视化分析)

目录 1.知识简介 2.SVM 支持向量机模型训练与可视化报告 2.1 导入本项目所需的模块和包 &#xff08;1&#xff09;目的 &#xff08;2&#xff09;代码实现 &#xff08;3&#xff09;代码解释 2.2 随机生成线性可分的数据并可视化 &#xff08;1&#xff09;目的 &a…

[数据集][目标检测]电力场景防震锤缺陷检测数据集VOC+YOLO格式705张1类别

重要说明&#xff1a;防震锤缺陷图片太难找&#xff0c;数据集里面存在大量单一场景图片&#xff0c;请仔细查看图片预览谨慎下载&#xff0c;此外数据集均为小目标检测&#xff0c;如果训练map偏低属于正常现象 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径…