Appearance
基础-可视化工具概览
上面一节和大家一起从 0 到 1 实现了一个条形图去回答了我们8个问题中第一个问题:“哲学家、哲学问题和流派的数量关系是怎样的?”。
在绘制条形图的过程中,因为没有借助任何工具,所以虽然代码行数不是很多,但是也能感觉到不太方便,比如自己实现数据处理过程,调用浏览器原生的绘制 API 等。
有没有办法可以简化这个流程,让我们能快更好的完成我们的可视分析任务?答案是肯定的。俗话说的好:“工欲善其事,必先利其器”,解决办法就是使用现有的工具。但是几乎所有做可视化的人会面对一个绕不开的问题:
“我应该使用哪一个可视化工具?”
要回答这个问题,那么我们就该先了解选择标准是什么?前端领域有哪些有名的可视化工具?它们又有什么特点?使用它们有什么常见的挑战?
接下来我们就来一一看看。
选择标准
选择可视化工具的时候,我们的标准不是哪个更好,而是哪个跟适合我们当前想要完成的任务。那么又该如何判断这个工具是否当前的任务呢?那我们首先得看看这些可视化工具解决的核心问题。
可视化工具要想解决的核心问题是:在易用和灵活之间找到一个平衡。易用是指用户在实现一个可视化图表的时候只用付出很少的努力,灵活是指用户能用该工具实现更多自定义的效果。
很容易想象得到,易用性越强的工具越不灵活,越灵活的工具越不易用。因为当你付出努力少的时候,说明很多事情工具已经自己帮你做了,而这些你是没有办法或者只有部分参与的,这无疑降低了灵活性。
所以我们选择工具的时候就是看这个工具能否在易用和灵活两方面都尽量满足我们的需求。那目前前端领域的可视化工具的易用性和灵活性有如何呢?我们马上来看看。
可视化框架概览
参考 Navigating the Wide World of Data Visualization Libraries 这篇文章,我们把一些有名的可视化工具用下面这张图整理了一下:
垂直方向是按照抽象程度来分类的,越底层的工具抽象程度越低,灵活性越强,易用性越差;越高层的工具抽象程度越高,易用性越强。水平方向是按照归属来分类的,左边的工具是来自于 AntV 技术栈的工具,右边的工具是来自于社区优秀的开源工具。
大概了解了社区上一些优秀的可视化工具之后,我们接下来就从渲染引擎这一层抽像开始,一层层向上看,看看它们是怎么帮助我们可视化的。
渲染引擎
首先是渲染引擎,渲染引擎会对浏览器的原生 API 进行封装,主要目的是为了简化我们绘制图形的流程。
比如我们用 Canvas2D 绘制一个矩形的方式如下,需要一行行的设置属性。
javascript
// 绘制一个矩形
context.fillStyle = "red"; // 设置填充颜色
context.strokeStyle = "yellow"; // 设置边框的颜色
context.lineWidth = 10; // 设置边框的宽度
context.strokeRect(0, 0, 100, 100); // 绘制边框
context.fillRect(5, 5, 95, 95); // 绘制填充颜色
但是在 @antv/g 的帮助下,直接把属性通过一个 options 的形式指定就好。
javascript
const rect = new G.Rect({
style: {
x: 5,
y: 5,
width: 100,
height: 100,
fill: 'red',
stroke: 'yellow'
},
});
但是在这一抽象层次的工具只是简化了最后的数据绘制流程,没有简化我们的数据处理流程,或者一些通用功能(坐标轴,图例这些),所以我们需要更强大的工具。
低级可视化模块
低级可视化模块就是上面提到的更强大的工具。它们是一些和可视化相关的工具,各自都是相互独立并且负责数据处理或者数据绘制的某部分。
比如在上一章我们通过以下的方式去计算每个条的 x 坐标,这样不仅需要我们自己实现计算逻辑,还看上去不直观。
javascript
const step = chartWidth / names.length;
const barWidth = step * 0.8;
const xs = Array.from(indices, (i) => i * step);
如果我们使用 d3-scale 就可以简化这个流程如下。
javascript
const map = d3.scaleBand().domain(indices).range([0, chartWidth]);
const xs = Array.from(indices, map);
这一抽象层次的工具简化了图表绘制各个流程,但是难道每一个流程都必须人来参与吗?工具可以自己完成一部分吗?
可视化语法
可视化语法就能大幅度减少人的参与,同时保持相对可观的灵活性。
可视化语法的开山鼻祖可以说是:图形语法,目前前端有名的在可视化语法这一层级的工具 G2,Vega-Lite 等都或多或少借鉴它的思想。
图形语法这个概念是在 Leland Wilkinson 的《The Grammar of Graphics》被提出的。它的核心就是用一些不同同图表都通用的概念(比例尺,坐标系等)去描述一个可视化图表。下面是书中给出的一个案例,目前大家不用深入了解,只用大概感受一下,我们在后面会深入了解。
要实现上一章的条形图就可以很简单了,下面用 G2 举例子:
javascript
import { Chart } from '@antv/g2';
const data = [
{ name: "questions", value: 17 },
{ name: "schools", value: 25 },
{ name: "philosophers", value: 35 },
];
const chart = new Chart({
width: 480,
heihgt: 300,
container: 'container-canvas'
});
chart.data(data);
chart
.interval()
.position('name*value')
.color('name');
chart.render();
如果我们希望再简单一点使用呢?那么就需要看看下一层级了。
高级可视化绘制模块
高级可视化绘制模块和可视化语层级一样,都不会显式指明可视化图表的类型,但是这些模块不一定是所有图表都通用的,同时在不同的可视化工具中功能也不一样。
在 ECharts 中就会通过 series 去组合形成不同的可视化图表类型。下面用是 ECharts 去绘制上一节需要的条形图的代码。
javascript
const chart = echarts.init(document.getElementById('container-canvas'));
const option = {
xAxis: {
type: 'category',
data: ['questions', 'schools', 'philosophers']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar',
}
]
};
chart.setOptions(options);
图表模板
图表模版这一抽象层级一个最大的改变就是需要指定我们选择的图表的类型,不用去考虑如何去组合高级可视化绘制模块。这在意味着非常的方便的同时,丧失了很多灵活性,适合对自定义要求不高的任务。
下面用 G2Plot 来实现我们上一章对条形图,发现代码确实少了很多。
javascript
import { Column } from '@antv/g2plot';
const data = [
{ name: "questions", value: 17 },
{ name: "schools", value: 25 },
{ name: "philosophers", value: 35 },
];
const column = new Column('container-canvas', {
data,
xField: 'name',
yField: 'value',
seriesField: 'name',
});
column.render();
智能可视化
如果你在可视化的过程什么也不愿意参与或者想参与程度很低的话,那么智能化可视化便是你最好的选择。一般来说你只需要把你想要可视化的数据和可视化意图告诉它,它就可以自动可视化出来。
比如 @antv/AVA 就可以非常简单的完成我们上一章提到的分析任务,我们都不需要去告诉它我们需要条形图,如下的代码就可以帮助我们把条形图做出来。
javascript
import { AutoChart } from '@antv/auto-chart';
const data = [
{ name: "questions", value: 17 },
{ name: "schools", value: 25 },
{ name: "philosophers", value: 35 },
];
autoChart('container-canvas', data);
就这样我们在很短时间内直观感受了前端领域的不同抽象层级的可视化框架。想必大家肯定感觉好像学到了很多东西,却又好像什么都没有学到。
这是因为我们只是简单了解了其中的一些基本概念,而没有深入理解。如何才能深入理解?那就是自己亲自体验一下:自己从零开一个可视化工具,看完成一个完整的可视化图表到底有哪些需要考虑的。
Sparrow
我们接下来要开发的框架的名字叫做:Sparrow,是一个基于图形语法的可视化框架。选择开发一个在可视化语法抽象层级工具的考虑有两点:
- 可视化语法是很关键的一层,有承上启下的感觉:它不仅仅将一些低层级可视化绘制模块串联起来了,也给上层的高级可视化模块提高了足够灵活和易用的基础。
- 我们团队在迭代 G2 的过程中,发现很多 issues 提到的问题都是因为对图形语法不了解导致的的,希望能通过这个过程加深大家对图形语法的理解,可以更好的使用相关的可视化工具,也能对可视化有更加深刻的理解。
Sparrow 翻译过来就是麻雀。俗话说的好:“麻雀虽小,五脏俱全”,这意味着我们最后完成工具代码量会很少,但是却覆盖了如下图图形语法最核心的东西。
开发完成之后,我们可以通过一个如下的 JavaScript 对象去描述我们的图表。
javascript
import { plot } from "@sparrow-vis/sparrow";
const data = [
{ name: "questions", value: 17 },
{ name: "schools", value: 25 },
{ name: "philosophers", value: 35 },
];
const chart = plot({
data,
type: "interval",
encodings: {
x: "name",
y: "value",
fill: "name"
}
});
document.getElementById("container").appendChild(chart);
开发完成之后可以大大的提高我们解决后面问题的速度。
小结
这一章我们简单给大家展示了目前前端领域流行的可视化工具,并且大概了解了它们的使用方式。为了对它们有更深入的认识,并且能加速我们后面解决问题的速度,我们接下来准备从零开发一个基于图形语法的可视化库 Sparrow。
基础篇就这样结束了,接下来让我们一起扬帆起航进入实战篇。
参考资料
- Navigating the Wide World of Data Visualization Libraries, Krist Wongsuphasawat
- The Grammar of Graphics, 2nd Edition, Leland Wilkinson