【D3.js in Action 3 精译_034】4.1 D3 中的坐标轴的创建(中篇):定义横纵坐标轴的比例尺

news2024/10/20 15:50:05

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

  • 第一部分 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.1.1 D3 的边距约定 The margin convention
    • 4.1.2 坐标轴的生成 Generating axes
      • 1 比例尺的声明 Declaring the scales

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

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

译者按
继第四章概述部分交代本章任务,并完成绘制图表前的相关数据准备工作后,本篇开始将逐步深入介绍 D3 的边距约定以及坐标轴的基础核心概念,一定要用心学习。D3 的知识结构非常严密,一步跟不上,后面再想补回来就非常吃力了,主打一个步步为营。不要在意内容的多寡,潜心积累,持续深耕就行了。一起学起来吧!

4.1.1 D3 的边距约定 The margin convention

D3 的边距约定,旨在通过系统化的、可重用的方式为图表周围的坐标轴、标签以及图例保留足够的空间。该约定涉及四个方向,即图表的上方、右侧、下方和左侧,如图 4.3 所示。通过声明这些边距值,就可以知道图表核心区域的位置信息和尺寸大小,该核心区域也被称为 内部图表(inner chart

图 4.3 用 D3 的边距约定确定出的图表上、下、左、右方向上的外边距大小示意图

【图 4.3 用 D3 的边距约定确定出的图表上、下、左、右方向上的外边距大小示意图】

各边距(margin)的值都在一个边距对象中声明。该对象由上、下、左、右边距组成。下面来给我们的折线图创建边距对象。在函数 drawLineChart() 内,声明一个名为 margin 的常量,并沿顺时针方向令其顶部、右侧、底部、左侧的边距值分别为 40px170px25px40px,如以下代码所示:

const drawLineChart = (data) => {
  const margin = {top: 40, right: 170, bottom: 25, left: 40};
};

提前准确预判该为坐标轴和图表标签预留多大空间通常是不现实的。一般得从一个合理的推测开始,然后再根据需要进行调整。例如,查看前面图 4.1 中的折线图或者浏览项目的线上版本(详见 http://mng.bz/5orB),就会发现图表右侧渲染出的标签相对较宽,因此右边距暂定 170px;此外,坐标轴的标签占用空间其实并不大,因此剩余的边距可以调小一点。

一旦确定了边距对象的尺寸,下一步就可以考虑 SVG 容器的尺寸大小了。当 SVG 的容器大小和边距都确定后,就可以算出另两个新常量的大小:innerWidthinnerHeight,分别表示内部图表的宽度和高度。各尺寸的空间分布情况如图 4.4 所示:

图 4.4 SVG 容器尺寸和边距确定后,就能算出内部图表的宽高

【图 4.4 SVG 容器尺寸和边距确定后,就能算出内部图表的宽高】

内部图表的宽度值等于 SVG 容器的宽度减左右两侧的边距宽度。若 SVG 容器宽 1000px,左右边距分别为 170px40px,则内部图表可分到 790px;同理,若 SVG 容器总高度为 500px,减去上下边距的高即为内部图表的高度值,可算得 435px。这样,常量 innerWidthinnerHeight 就与边距尺寸成线性关系,后续如果边距有变动,这两个值也会同步更新:

const margin = {top: 40, right: 170, bottom: 25, left: 40};
const width = 1000;
const height = 500;
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;

接着再来添加折线图的 SVG 容器。还是在函数 drawLineChart() 内部,将一个 SVG 元素追加到 idline-chartdiv 元素内;然后使用 widthheight 常量设置 SVG 的 viewBox 属性。还可以临时给 SVG 元素绘制一个边框,以便看清工作区域的方位(关于如何将元素添加到 DOM 结构、或者元素属性与样式的设置方法,详见第 2 章相关内容)。

const svg = d3.select("#line-chart")
  .append("svg")
  .attr("viewBox", `0, 0, ${width}, ${height}`);

现在,各方向上的边距值和 SVG 的原点坐标都已经确定好了。折线图中的每个元素都必须向新划定的绘图区域平移。这时应该将内部图表封装在一个 SVG 的分组元素中,并只对该分组元素设置平移即可,无需挨个为每个图表元素指定平移量,如图 4.5 所示。这样做也为内部图表建立了一套新的坐标系。

图 4.5 包含内部图表的 SVG 分组元素的平移效果图。该平移也为内部图表各元素建立了新的坐标系

【图 4.5 包含内部图表的 SVG 分组元素的平移效果图。该平移也为内部图表各元素建立了新的坐标系】

要实现上述效果,需要在 SVG 容器中添加一个分组元素;然后利用左边距和上边距指定该分组的平移量;最后将 SVG 分组赋给常量 innerChart,以备后用:

const innerChart = svg
  .append("g")
  .attr("transform", `translate(${margin.left}, ${margin.top})`);

D3 的边距约定以及上述做法的主要优点在于,这些尺寸一旦确立,后续就无需再考虑相关问题了。这样,在充分考虑并提前预留标签、图例及其他补充信息的绘制区域后,就可以继续创建折线图的坐标轴以及核心图表了。

4.1.2 坐标轴的生成 Generating axes

边距一旦确定,就可以给图表添加坐标轴了。坐标轴既是数据可视化的重要组成部分,同时也是观众理解所绘数据与相关类别的重要参考。

对照前面图 4.1 或者线上版(详见:http://mng.bz/5orB)的折线图,可以看到两个坐标轴:横轴(也称 x 轴)显示各月份;纵轴(或 y 轴)则为华氏温度 1 的参考轴线。

译注

为方便查看效果,这里直接给出本专栏第 32 篇(第四章概述)中的最终效果图:

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

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

D3 通过 axis()组件生成器(component generator) 来创建坐标轴。该生成器接受一个比例尺函数作为参数,并返回一个组成该坐标轴的 SVG 元素。第三章介绍的比例尺相关知识还有印象吗,它们负责将定义域中的值转换为值域中对应的值,并通过这些值来绘制图表。而折线图与之类似,比例尺传入后,将算得数据集各日期的水平坐标,以及相关温度值对应的垂直坐标。

1 比例尺的声明 Declaring the scales

根据上面的介绍,创建 D3 坐标轴的第一步,其实是声明它们相应的比例尺。首先要创建一个能设置日期水平位置的比例尺,这正是 D3 时间比例尺 d3.scaleTime() 的长项(更多 D3 比例尺选型方面的介绍,详见本书 附录 B(译注:将择日翻译))。时间比例尺属于第三章介绍过的四类比例尺中的第一类:接受连续型输入,并返回连续型输出。时间比例尺的行为特征与第三章介绍的线性比例尺非常类似,唯一的区别在于这里处理的是与时间相关的数据。

接下来,先声明一个时间比例尺常量 xScale,负责 x 轴上的元素定位。该比例尺的定义域从第一个日期值开始,到最后一个日期结束。以下代码片段还用到了 d3.min()d3.max() 函数,它们是 d3-array 模块中的两个工具方法,专门用于查找对应的极值。

而时间比例尺的值域,则是在内部图表的可用水平空间上均匀分布(如图 4.5 所示)。在内部图表的坐标系中,意味着值域将从 0 延展至之前计算过的内部宽度 innerWidth(比例尺定义域及值域的相关知识点,详见第三章):

const firstDate = d3.min(data, d => d.date);
const lastDate = d3.max(data, d => d.date);
const xScale = d3.scaleTime()
  .domain([firstDate, lastDate])
  .range([0, innerWidth]);

而温度则沿 y 轴分布,也需要一个连续输入与输出的比例尺。这里自然首选线性比例尺,因为我们希望温度与折线图上的垂直坐标呈线性比例关系。

以下代码片段中,声明了一个表示温度比例尺的常量 yScale,负责 y 轴上的元素定位。假定 y 轴从 0 开始,因此 0 即为定义域的第一个传入值;虽然数据集中的最低温度大约在 26°F 左右(即 -3.3°C 上下),但将 y 轴设为从 0 开始也不错,况且在本例中也可以准确地看出气温的演变情况。这就像生活中的大多数情况,其实并没有一个硬性规定;同理,本例中的图表也不能因为华氏度中的 0 度并非真正的 0 而有对错之分。

而定义域需要的第二个参数,这里选数据集中的最大温度。具体的值通过使用 d3.max() 函数检索数据集的 max_temp_F 字段来确定。

比例尺的值域沿图表高度均匀分布,但由于 SVG 坐标系的垂直坐标是向下为正的,因此值域即从图表的内部高度 innerHeight 开始,也就是图表的左下角位置;终点则为 0,对应其左上角的纵坐标:

const maxTemp = d3.max(data, d => d.max_temp_F);
const yScale = d3.scaleLinear()
  .domain([0, maxTemp])
  .range([innerHeight, 0]);

译注
由于 4.1.2 节篇幅太长,拟再分三个子篇进行介绍(足见 D3 坐标轴这个知识点的信息密度之大)。本章同步源码已上传 CSDN 资源库。章节内容持续更新中,敬请关注本精译专栏,及时获取 D3.js 最前沿的数据可视化主流趋势及最佳实践。



  1. 华氏温度,即 Fahrenheit temperature,是由德国物理学家丹尼尔·华氏(Daniel Gabriel Fahrenheit)于 1701 年提出,其刻度是基于他所使用的水银温度计的特点,并将其划分为180个单位,并在标准大气压下测得水的冰点为华氏 32 度(32°F),沸点为华氏 212 度(212°F)。因为历史文化等原因,美国是目前世界上仅有的五个还在使用华氏度的国家之一。华氏度与摄氏度的换算关系为:1°F = 1.8 × °C + 32。 ↩︎

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

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

相关文章

京存助力北京某电力研究所数据采集

北京某电力研究所已建成了一套以光纤为主,卫星、载波、微波等多种通信方式共存,分层级的电力专用的网络通信架构体系。随着用电、配电对网络的要求提高,以及终端通信入网的迅速发展,迫切地需要高效的通信管理系统来应对大规模、复…

STM32传感器模块编程实践(七) MLX90614红外测温模块简介及驱动源码

文章目录 一.概要二.MLX90614主要技术指标三.模块参考原理图四.模块接线说明五.模块工作原理介绍六.模块通讯协议介绍七.STM32单片机与MLX90614模块实现体温测量实验1.硬件准备2.软件工程3.软件主要代码4.实验效果 八.小结 一.概要 一般来说,测温方式可分为接触式和…

大模型常见算子定义

本文将汇总大模型常用的算子定义,方便快速根据定义公式评估其计算量。 LayerNorm 这是在BERT、GPT等模型中广泛使用的LayerNorm: RMSNorm RMSNorm(root mean square)发现LayerNorm的中心偏移没什么用(减去均值等操作)。将其去掉之后,效果几乎…

51系列--人体身高体重BMI指数检测健康秤

本文主要介绍基于51单片机实现的人体身高体重BMI指数检测健康秤称设计(程序、电路图、PCB以及文档说明书见文末链接) 一、简介 本系统由STC89C52单片机、LCD1602液晶显示、按键、超声波测距、HX711称重传感器模块(0-1000KG)以及…

O(1)调度算法与CFS

目录 引言 linux内核的O(1)进程调度算法介绍 主要特点 工作原理 优点 缺点 运行队列 活动队列 过期队列 active指针和expired指针 O(1)调度器,两个队列的机制 两个队列的机制如下: 这个算法后期被CFS替代 CFS 工作原…

进阶篇-Redis集群算法详细介绍

目录 一 、集群是什么1.1 主从复制与集群的架构区别 二、Redis集群的作用三、集群算法3.1.分片-槽位slot3.2 分片是什么3.3如何找到找到给定的key值分片3.4分片的优势 四、槽位映射的三中国解决方案4.1 哈希取余分区算法4.2 哈希一致性算法4.2.1 背景以及概念4.2.2 算法的步骤4…

【Python加密与解密】深入了解Python中的数据加密技术!

Python加密与解密:深入了解Python中的数据加密技术 在现代信息时代,数据加密成为保障网络和通信安全的重要手段之一。无论是在保护个人隐私还是在保证企业数据的安全性方面,加密技术都发挥着关键作用。Python 作为一种流行的编程语言&#x…

(10) GTest c++单元测试(mac版)

文章目录 概要安装实现机制-断言(简单、独立的测试)实现机制-测试套件实现机制-Test Fixture和事件 概要 官方文档 https://google.github.io/googletest/ 安装 git clone https://github.com/google/googletestcd googletestmkdir build && c…

鸿蒙开发 四十五 鸿蒙状态管理(嵌套对象界面更新)

当运行时的状态变量变化,UI重新渲染,在ArkUI中称为状态管理机制,前提是变量必须被装饰器修饰。不是状态变量的所有更改都会引起刷新,只有可以被框架观测到的更改才会引起UI刷新。其中boolen、string、number类型,可观察…

PyQt 入门教程(3)基础知识 | 3.2、加载资源文件

文章目录 一、加载资源文件1、PyQt5加载资源文件2、PyQt6加载资源文件 一、加载资源文件 常见的资源文件有图像、图标、样式表,下面分别介绍下加载资源文件的常用方法 1、PyQt5加载资源文件 创建.qrc文件: 可以使用QtCreator或手动创建一个.qrc文件&…

注意LED亚型号区分

一. 前言 最近产品试产遇到一次批量事故:全部绿光LED的光功率不达标。最终定位到的原因就是未注意LED的细分型号,试产采用的批次与研发时的亚型号不一样,光功率范围不一致。在此记录下来,供大家做参考,避免走弯路。 …

桂林旅游一点通:SpringBoot平台应用

3系统分析 3.1可行性分析 通过对本桂林旅游景点导游平台实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本桂林旅游景点导游平台采用SSM框架,JAVA作…

uniapp结合uview-ui创建项目

准备工作: 下载HBuilderX;官网地址:HBuilderX-高效极客技巧 安装node.js;官网地址:Node.js — 在任何地方运行 JavaScript,下载所需版本,安装后配置好环境变量即可 方式一(NPM安装方式): 1、打开开发者…

OpenRTP 乱序排包和差分抖动计算

OpenRTP 开源地址 OpenRTP 开源地址 暂时使用h264 aac 的音频去测试,点开配置去选择 1 音视频同步问题 先要解决一个音视频同步问题,否则包排不排序都不对,这是因为视频时间戳不一定能够对上音频,为什么呢?因为大部…

前端考试总结

1HTML标签 h标题标签 块级标签 独占一行 p段落标签 同上 br换行标签 单标签 img图片标签 内联标签:不独占一行(src图片地址 alt图片的替代文字 title鼠标悬停提示文字) a超链接标签 同上 (href跳转路径 target属性{_blank新窗口打开 _self在当前窗口打开}) 列表标签(ul无…

诺贝尔物理学奖与机器学习、神经网络:一场跨时代的融合与展望

诺贝尔物理学奖与机器学习、神经网络:一场跨时代的融合与展望 机器学习与神经网络的崛起 机器学习与神经网络的发展前景 机器学习和神经网络的研究与传统物理学的关系 总结 2024年,诺贝尔物理学奖颁给了机器学习与神经网络,这一具有里程碑…

JAVA就业笔记5——第二阶段(2)

课程须知 A类知识:工作和面试常用,代码必须要手敲,需要掌握。 B类知识:面试会问道,工作不常用,代码不需要手敲,理解能正确表达即可。 C类知识:工作和面试不常用,代码不…

房屋租赁管理系统|基于java和小程序的房屋租赁管理系统小程序设计与实现(源码+数据库+文档)

房屋租赁管理系统小程序 目录 基于java和小程序的房屋租赁管理系统小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设…

asp.net core _ViewStart.cshtml 和 _ViewImports.cshtml

_ViewStart.cshtml asp.net mvc 就出现了 》》/Views/ViewStart.cshtml _ViewStart.cshtml 是默认模板,当页面没有指定 Layout 时,会自动调用此默认模板‌,如果要取消 在当页面设定 (如下),则表示 当前页面…

线下陪玩导游系统软件源码,家政预约服务源码(h5+小程序+app)

游戏陪玩系统源码陪玩小程序源码搭建基于PHP+MySQL陪玩系统app源码陪玩系统定制开发服务、成品陪玩系统源码 系统基于Nginx或者Apache PHP7.3 数据库mysql5.6 前端为uniapp-vue2.0 后端为thinkphp6 有域名授权加密,其他开源可二开 演示源码下载 开…