前言
什么是数据可视化
将结果数据的每一个数据项,作为单个图元元素展示,大量的数据集构成数据图像,同时将数据的各个属性以多维度的方式展现,从而提高数据的可读性。
数据可视化的优点
- 图形化展示比文字的描述能力更强。
- 降低大数据据阅读门槛。
- 清晰有效地传达与沟通信息。
具体做法:是指将大型数据集中的数据以图形图像形式表示。基于几何的技术、面向像素技术、基于图标的技术、基于层次的技术、基于图像的技术和分布式技术等等。
数据处理流程
- 数据收集:将已经存在的数据管理起来( 收集、采集 );
- 数据清洗 ETL (extract transform load 数据仓库技术):将脏数据,指那些没有意义、没有用的数据清洗掉;
- 数据计算:进行多维度计算,统计分析(分组、极值、多维度展示), 结果预测(spark)、python机器学习(分类/聚类算法);
- 数据可视化:通过一些插件库,将数据以图表的形式进行展示,目前常用的插件库有以下:
- echarts:(百度开源项目,国内应用领域十分广泛,apache孵化器,各大领域,入门比较容易、主要是修改配置)
- highCharts: (学习可以,商用需要授权,09年发布,使用纯js编写的图表库)
- d3:D3 的全称是(Data-Driven Documents),一个被数据驱动的文档。听名字有点抽象,说简单一点,其实就是一个 JavaScript 的函数库,主要是用来做数据可视化,将强大的可视化组件应用于需求中。
接下来我们来认识一下D3.js
1. D3.js 简介
D3.js是一个JavaScript库,用于根据数据处理文档。D3可通过使用HTML,SVG和CSS使数据栩栩如生。D3遵循 Web标准,它可以提供了现代浏览器的全部功能,而又不会使自己陷入专有框架,而是结合了强大的可视化组件和数据驱动的DOM操作方法。
使用D3可以将任意数据绑定到文档对象模型(DOM)上,然后将数据驱动的转换应用于文档。例如,可以使用D3从数字数组生成HTML表。或者,使用相同的数据创建具有平滑过渡和交互作用的交互式SVG条形图。
2. 安装
如果使用npm,可以通过npm install d3
来安装,此外还可以下载最新版,最新版支持 AMD、CommonJS 以及基础标签引入形式。 你也可以直接从 d3js.org, CDNJS, 或者 unpkg 加载. 比如:
<script src="https://d3js.org/d3.v5.js"></script>
压缩版:
<script src="https://d3js.org/d3.v5.min.js"></script>
你也可以单独使用 d3 中的某个模块, 比如单独使用 d3-selection:
<script src="https://d3js.org/d3-selection.v1.js"></script>
D3基于 ES2015 modules 开发。 可以使用 Rollup, webpack 或者其他你偏爱的打包工具进行构建。 在一个符合 ES2015 的应用中导入 d3 或者 d3 的某些模块:
import { scaleLinear } from "d3-scale";
或者导入 d3 的全部功能并且设置命名空间 (这里是 d3):
import * as d3 from "d3";
在 Nodejs 环境中:
var d3 = require("d3");
你也可以导入多个模块然后将这些模块集合到 d3 对象中, 此时使用 Object.assign:
var d3 = Object.assign({}, require("d3-format"), require("d3-geo"), require("d3-geo-projection"));
在 Node 环境中使用 DOM 的时候,必须要提供自己的 DOM 实现。推荐使用 JSDOM,为了避免定义全局 document,建议将 DOM 传递给 d3.select 或者将 NodeList 传递给 d3.selectAll,如下:
var d3 = require("d3"),
jsdom = require("jsdom");
var document = jsdom.jsdom(),
svg = d3.select(document.body).append("svg");
3. D3-选择集
在 D3 中,用于选择元素的函数有两个,这两个函数返回的结果称为选择集。
- d3.select():选择所有指定元素的第一个;
- d3.selectAll():选择指定的全部元素;
一般情况下,返回当前选择集的选择方法使用四个缩进空间,而返回新选择集的方法仅使用两个缩进空间。通过使上下文脱离链,这有助于揭示上下文的变化:
d3.select("body")
.append("svg")
.attr("width", 960)
.attr("height", 500)
.append("g")
.attr("transform", "translate(20,20)")
.append("rect")
.attr("width", 920)
.attr("height", 460);
选择集的常见用法如下:
var body = d3.select("body"); //选择文档中的body元素
var p1 = body.select("p"); //选择body中的第一个p元素
var p = body.selectAll("p"); //选择body中的所有p元素
var svg = body.select("svg"); //选择body中的svg元素
var rects = svg.selectAll("rect"); //选择svg中所有的rect元素
var id = body.select("#id"); //选择body中id元素
var class = body.select(".class");//选择body中class类元素
链式操作:
d3.select("#container").text("这是一段文字").attr("name","cont");
3.1 datum() 与 data()
绑定数据:选择集和绑定数据通常是一起使用的,D3 中是通过以下两个函数来绑定数据的:
- datum():用来绑定一个数据到选择集上;
- data():用来绑定一个数组到选择集上,数组的各项值分别与选择集的各元素绑定;
使用 datum(),可以将一个数据分别绑定到多个DOM元素上。
<div id="app">
<p></p>
<p></p>
<p></p>
</div>
<script>
var data = '这是一段文字';
var container = d3.select("#app");
container.selectAll('p')
.datum(data)
.text(function (d, i) {
return "第 " + i + " 个元素绑定的数据是: " + d;
})
</script>
页面效果如下:
使用data(),分别将数组的各元素绑定到多个DOM元素上。
<div id="app">
<p></p>
<p></p>
<p></p>
</div>
<script>
var datalist = [10, 20, 30];
var container = d3.select("#app");
container.selectAll('p')
.data(datalist)
.text(function (d, i) {
return d;
})
</script>
页面效果如下:
回调函数中,
- 第一个参数表示 data,即 datum() 或者 data() 中的各项数据;
- 第二个参数表示 index,表示索引;
动态属性,在回调函数中,可以通过对data判断,给元素动态设置属性:
var datalist = [10, 20, 30]
d3.selectAll('p').data(datalist).text((d, i) => {
return d;
}).style('color', (d, i) => {
if (d > 10) {
return 'red'
} else {
return 'blue'
}
}).style('font-size',(d,i)=>{
return d+'px';
})
页面效果如下:
3.2 update()、enter()、exit()
数据绑定的时候可能出现 DOM 元素与数据元素个数不匹配的问题,那么 enter 和 exit 就是用来处理这个问题的。enter 操作用来添加新的 DOM 元素,exit 操作用来移除多余的 DOM 元素。
Update、Enter、Exit 是 D3 中三个非常重要的概念,它处理的是当选择集和数据的数量关系不确定的情况。
- update(), 当对应的元素正好满足时 ( 绑定数据数量 = 对应元素 ),实际上并不存在这样一个函数,只是为了要与之后的 enter 和 exit 一起说明才想象有这样一个函数。但对应元素正好满足时,直接操作即可,后面直接跟 text ,style 等操作即可。
enter()
, 当对应的元素不足时 (绑定数据数量 > 对应元素
),当对应的元素不足
时,通常要添加元素
,使之与绑定数据的数量相等。后面通常先跟append
操作。exit()
, 当对应的元素过多时 (绑定数据数量 < 对应元素
),当对应的元素过多时,通常要删除元素
,使之与绑定数据的数量相等。后面通常要跟remove
操作。
如果数组为 [3, 6, 9, 12, 15],将此数组绑定到三个 p 元素的选择集上。可以想象,会有两个数据没有元素与之对应,这时候 D3 会建立两个空的元素与数据对应,这一部分就称为 Enter。而有元素与数据对应的部分称为 Update。如果数组为 [3],则会有两个元素没有数据绑定,那么没有数据绑定的部分被称为 Exit。示意图如下所示。
update() 、enter()、exit():
var dataset = [3, 6, 9, 12, 15]
var p = d3.select('body').selectAll('p'); //选择body中的P元素
var update = p.data(dataset); //获取update部分
update.text(function (d) { //获取update部分,更新属性值
return "update " + d;
})
var enter = update.enter() //获取enter部分
enter.append('p').text(function (d) {
return "enter " + d;
})
var exit = update.exit() //获取exit部分
// exit.text(function (d) {
// return "exit"
// })
exit.remove();
3.3 transition()
过渡动画。
- duration() 动画的持续时间
- delay() 动画的延迟时间
var width = 600;
var height = 400;
var svg = d3.select('body') //添加svg元素
.append('svg')
.attr('width',width)
.attr('height',height);
svg.append('rect') //在svg中添加宽100高30,填充色为绿色,左上角位置在30,40的rect
.attr("fill","green")
.attr("x",30)
.attr("y",40)
.attr("width",100)
.attr("height",30)
.transition() //添加动画效果
.duration(2000) //动画持续时间2000ms
.delay(3000) //延时3000ms后 开始执行动画
.attr("width",300) //过渡成宽300高300,移动到200,100的位置
.attr("height",300)
.attr("x",200)
.attr("y",100)
页面的效果如下:
3.4 svg的简单使用
D3.js 主要是通过绘制 svg 来展示数据,这里简单介绍svg的使用方式,详细教程可以查看:https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element
SVG 意为可缩放矢量图形(Scalable Vector Graphics)。SVG 使用 XML 格式定义图像。
使用svg绘制矩形、椭圆、正圆:
<svg width="500" height="200" style="background: #efefef;">
<!-- 矩形 -->
<rect x="50" y="100" width="100" height="50" class="rect" stroke="blue" stroke-width="5" ></rect>
<!-- 椭圆 -->
<ellipse cx="230" cy="100" rx="100" ry="50" style="fill: orange; stroke: orangered; stroke-width: 5px;"></ellipse>
<!-- 正圆 -->
<circle cx="380" cy="100" r="90" style="fill: orange; stroke: orangered; stroke-width: 5px;"></circle>
</svg>
页面效果如下,可以看到最先绘制的矩形在最底层,最后绘制的正圆在最上面。
使用svg绘制直线、多边形、折线、路径、文本:
<svg width="500" height="200" style="background: #efefef;">
<!-- 直线 -->
<line x1="50" y1="50" x2="450" y2="150" stroke="red" stroke-width="3"></line>
<!-- 多边形 -->
<polygon points="50,20 150,60 120,180 100,180 " fill="none" stroke="blue" stroke-width="5"></polygon>
<!-- 折线 -->
<polyline points="150,20 250,60 220,180 200,180" fill="none" stroke="blue" stroke-width="5"></polyline>
<!-- 路径 -->
<path d="M330,30 L330,150 L470,170 " fill="none" stroke-width="4" stroke="green"></path>
<!-- 文本 -->
<text x="180" y="180" style="font-size: 50;fill:none; stroke-width: 1; stroke:red;"> hello world </text>
</svg>
使用 polygon 绘制多边形,或者使用 polyline 绘制折线时,语法为第一点的x坐标,y坐标 第二个点的x坐 y坐标 ...
,两者的不同之处在于,绘制多边形时会自动连接起始点和结束点,形成闭合图形;而绘制折线时,不会自动闭合图形。
path 绘制路径时,语法为M第一个点的x坐标,y坐标 L第二个点的x坐标,y坐标....
,可以理解为moveTo...lineTo....
。
页面效果如下:
元素g
是用来组合对象的容器。添加到g
元素上的变换会应用到其所有的子元素
上。添加到g
元素的属性
会被其所有的子元素继承
。此外,g元素也可以用来定义复杂的对象,之后可以通过<use>
元素来引用它们。
把所有需要多次使用的引用元素定义在defs
元素里面。这样做可以增加SVG内容的易读性和可访问性。 在defs
元素中定义的图形元素不会
直接呈现。 你可以在你的视口的任意地方利用 <use>
元素呈现这些元素。
<svg width="500" height="200" style="background: #efefef;">
<defs>
<g id="mycircle" stroke="green" fill="none" stroke-width="5">
<circle cx="25" cy="30" r="15" />
<circle cx="55" cy="80" r="15" />
<circle cx="85" cy="50" r="15" />
</g>
</defs>
<use xlink:href="#mycircle" x="30" y="30" />
<use xlink:href="#mycircle" x="260" y="80" />
</svg>
页面效果如下:
svg 中的动画,使用 animate
元素,它需要放在形状元素
的内部
,用来定义一个元素的某个属性如何踩着时点改变。在指定持续时间里,属性从开始值变成结束值。
- attributeName 要改变的属性名称;
- from to 开始状态跟结束状态;
- dur 动画的持续时间;
- repeatCount 动画的重复次数;
<svg width="500" height="200" style="background: #efefef;">
<circle cx="85" cy="50" r="15">
<animate attributeName="cx" from="85" to="180" dur="5s" repeatCount="5" />
<animate attributeName="cy" from="50" to="100" dur="5s" repeatCount="5" />
</circle>
</svg>
页面效果如下:
4. d3-selection API
d3中的常用的选择集有:
- d3.select - 从当前文档中选择一系列元素。
- d3.selectAll - 从当前文档中选择多项元素。
- selection.attr - 设置或获取指定属性。
- selection.classed - 添加或删除选定元素的 CSS 类(CSS class)。
- selection.style - 设置或删除 CSS 属性。style优先级高于attr。
- selection.text - 设置或获取选定元素的标签体文本内容。
- selection.html - 设置或获取选定元素的 HTML 内容(类似 innerHTML )。
- selection.datum - 设置或获取单独元素的数据,不进行关联。
- selection.data - 设置或获取一组元素的绑定数据。
- selection.append - 创建并添加新元素到选定元素后。
- selection.insert - 创建并添加新元素到选定元素前。
- selection.remove - 从当前文档对象中删除选定的元素。
- selection.enter - 返回缺失元素的占位对象(placeholder),指向绑定的数据中比选定元素集多出的一部分元素。
- selection.exit - 返回多余元素的元素集,即选择元素中比绑定数据多出的一部分。(关于data, enter, exit原理的示例1, 示例2, 示例3)
- selection.filter - 根据绑定的数据过滤选择集。
- selection.sort - 根据绑定的数据对选择的元素进行排序。
- selection.order - 对文档中的元素重排序以匹配选择集。
- selection.on - 添加或删除事件监听器。
- selection.transition - 启动一个过渡效果(返回 Transition 对象),可以理解为动画。
- selection.each - 为每个选择的元素集调用指定的函数。
- selection.call - 为当前选择的元素集调用指定的函数。
- selection.empty - 测试选择集是否为空。
- selection.node - 返回选择集中的第一个元素。
- selection.size - 返回选择集中的元素个数。
- selection.select - 选择所选的元素中的第一个子元素组成新的选择集。
- selection.selectAll - 选择所选的元素中的多个子元素组成新的选择集。
- d3.selection - 选择集对象原型(可通过 d3.selection.prototype 为选择集增强功能)。
- d3.event - 获取当前交互的用户事件。
- d3.mouse - 获取鼠标的相对某元素的坐标。
- d3.touches - 获取相对某元素的触控点坐标。