【D3.js in Action 3 精译_026】3.4 小节 DIY 实战:基于 Mocha 在浏览器客户端测试 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.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 rectanglesconst 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.xdnf.cn/news/1551941.html

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

相关文章

Python 机器学习:预测国庆黄金周的消费趋势

摘要&#xff1a;国庆黄金周作为中国一年中重要的消费高峰期&#xff0c;吸引了众多商家、政府和分析师关注。利用 Python 和机器学习技术&#xff0c;可以通过历史数据和多维因素构建模型&#xff0c;预测这一期间的消费趋势。本文介绍了数据获取、特征工程、模型选择和优化的…

Master PDF Editor 下载及详细安装教程

具体安装方式如下&#xff1a; 下载&#xff1a; MasterPDFEditor 先解压&#xff0c;将解压后的如下文件发送到桌面快捷方式 启动发送后桌面图标 选择要打开的pdf文档&#xff0c;可以看到打开速度是超级快&#xff0c;正常使用&#xff0c;操作简单方便

【网络安全】内部应用中的多重漏洞利用

未经许可,不得转载。 文章目录 初步发现:帐户枚举利用帐户枚举发现 IDOR 导致帐户接管拦截请求洪水攻击:注册拒绝服务目标网站:https://redacted.com 初步发现:帐户枚举 在最近的一次渗透测试中,我对一个仅供员工使用的内部应用程序进行了评估,重点关注身份验证和帐户…

Golang | Leetcode Golang题解之第448题找到所有数组中消失的数字

题目&#xff1a; 题解&#xff1a; func findDisappearedNumbers(nums []int) (ans []int) {n : len(nums)for _, v : range nums {v (v - 1) % nnums[v] n}for i, v : range nums {if v < n {ans append(ans, i1)}}return }

【原创】基于websocket的实时文本转语音功能

功能实现&#xff0c;将长文本分段实时转成音频流&#xff0c;达到边转换边播放的效果&#xff0c;减少等待效果&#xff0c;像豆包通义千问chatgpt差不多也是这样实现的&#xff0c; 下面的效果展示 20240930_084035_哔哩哔哩_bilibili【原创】基于websocket的实时文本转语音…

共和国勋章获得者:李振声

李振声&#xff0c;1931年2月出生于山东淄博&#xff0c;是中共党员、著名遗传学家和小麦遗传育种专家&#xff0c;兼任中国科学院院士和第三世界科学院院士。 他被誉为“中国小麦远缘杂交之父”和“当代后稷”&#xff0c;是中国小麦远缘杂交育种的奠基人。 教育背景与早年经…

【基于布尔的盲注】

一、sql基础 Substr 我们看一下用法1里面的str就是我们需要截取的字符&#xff0c;pos是需要截取的位置&#xff0c;len是我们需要截取的长度&#xff0c;例如右边的substr(123456,1,1)意思就是截取’123456’从第一位开始截取&#xff0c;截取两位&#xff0c;到2为止&#…

如何在C语言中实现Doris异步执行Insert语句

如何在C语言中实现Doris异步执行Insert语句 Doris(原名Apache Doris)是一个现代化的MPP(Massively Parallel Processing)分析型数据库,适用于超大规模数据的实时查询和分析。为了在C语言中实现向Doris数据库异步插入数据,我们需要解决以下几个关键问题: 设置Doris客户端…

Thinkphp/Laravel基于vue的实验室上机管理系统

目录 技术栈和环境说明具体实现截图设计思路关键技术课题的重点和难点&#xff1a;框架介绍数据访问方式PHP核心代码部分展示代码目录结构解析系统测试详细视频演示源码获取 技术栈和环境说明 采用PHP语言开发&#xff0c;开发环境为phpstudy 开发工具notepad并使用MYSQL数据库…

基于投影滤波算法的rick合成地震波滤波matlab仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 RICK合成地震波模型 4.2 投影滤波算法原理 5.完整工程文件 1.课题概述 基于投影滤波算法的rick合成地震波滤波matlab仿真。分别通过标准的滤波投影滤波以及卷积滤波投影滤波对合成地震剖面进行滤波…

了解华为计算产品线,昇腾的业务都有哪些?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 随着 ChatGPT 的现象级爆红&#xff0c;它引领了 AI 大模型时代的深刻变革&#xff0c;进而造成 AI 算力资源日益紧缺。与此同时&#xff0c;中美贸易战的持续也使得 AI 算力国产化适配成为必然趋势。 …

B站字幕提取方法

1.获取json文件内容 1.点击F12进入开发者模式&#xff0c;选择网络模块&#xff1b; 2.输入关键字&#xff0c;例如json、ai_subtitle、subtitle等&#xff1b; 3.点击视频下方的字幕功能&#xff0c;开启&#xff1b;再点击响应单元&#xff0c;复制内容&#xff1b; 2.去jso…

TI DSP TMS320F280025 Note13:CPUtimer定时器原理分析与使用

TMS320F280025 CPUtimer定时器原理分析与使用 ` 文章目录 TMS320F280025 CPUtimer定时器原理分析与使用框图分析定时器中断定时器使用CPUtimers.cCPUtimers.h框图分析 定时器框图如图所示 定时器有一个预分频模块和一个定时/计数模块, 其中预分频模块包括一个 16 位的定时器分…

【数学分析笔记】第4章第1节 微分和导数(1)

4. 微分 4.1 微分和导数 考虑一个函数 y f ( x ) yf(x) yf(x)&#xff0c;当 x x x做一些微小的变动&#xff0c;函数值也会有微小的变动&#xff0c;比如&#xff1a; x → x △ x x\to x\bigtriangleup x x→x△x&#xff0c;则 f ( x ) → f ( x △ x ) f(x)\to f(x\bi…

【有啥问啥】卡尔曼滤波(Kalman Filter):从噪声中提取信号的利器

卡尔曼滤波&#xff08;Kalman Filter&#xff09;&#xff1a;从噪声中提取信号的利器 什么是卡尔曼滤波&#xff1f; 卡尔曼滤波&#xff08;Kalman Filter&#xff09;是一种高效的递归滤波器&#xff0c;专为处理包含噪声的线性动态系统而设计。它能够从一系列不完全且含…

网盘能否作为FTP替代产品?企业该如何进行FTP国产化替代?

近年来&#xff0c;信创的概念引入和高效实践落地让更多的行业企业自发性地进行国产化替代&#xff0c;目前信创国产化替代还多发生在操作系统和应用层面&#xff0c;软件工具等目前还在下一阶段规划&#xff0c;但很多企业未雨绸缪&#xff0c;已经在做调研和尝试。 FTP作为世…

大屏娱乐体验新标杆:海信发布全新一代AI电视

在金秋送爽的9月29日&#xff0c;海信以一场盛大的“BIG PLAN百吋风暴”秋季新品发布会&#xff0c;正式揭开了AI电视新时代的序幕。 作为本场发布会上最耀眼的明星&#xff0c;海信AI电视E7N系列凭借无与伦比的AI画质技术和极致性能&#xff0c;引领大屏娱乐体验迈入全新境界&…

仿真设计|基于51单片机的多模式音乐跑马灯

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现&#xff08;protues8.7&#xff09; 程序&#xff08;Keil5&#xff09; 全部内容 资料获取 具体实现功能 1、16个发光二极管做跑马灯&#xff0c;跑马灯有10种模式。 2、按键可以切换跑马灯模式&#xff0…

Java笔试02

在网络操作系统中&#xff0c;TCP和UDP是传输层中两个非常重要的协议。TCP提供的是面向连接的、可靠的端到端通信机制&#xff0c;因此TCP协议在注重数据安全的场景下获得了极为广泛的应用。 TCP采用了确认和重发机制来确保数据的可靠传输。 相较于UDP&#xff0c;TCP的优势在…

.NET CORE程序发布IIS后报错误 500.19

发布IIS后浏览时报错误500.19&#xff0c;同时配置文件web.config的路径中也存在问号“?”。 可能原因&#xff1a;没有安装运行时