数据可视化技术实现的关键点

原文地址:https://geekplux.com/2019/10/06/how-to-implement-data-visualization (opens in a new tab)

题目想了半天,最后定了这个,也不知道有没有准确表达我的意思。其实本文主要想分享我做数据可视化这么久之后积累的一些经验,重点在技术实现这个层面。

在已经确定要实现一个可视化视图之前,你一定已经经历了思考和设计,拿到了一张确定的设计图或者原型图,所以这里就不赘述可视化在实现前的那些步骤 (opens in a new tab)了,直奔如何编程实现的主题。

实现前的规划

拿到一张设计图之后,和做前端切图差不多,你基本上要先做规划:

举个例子

以下图为例:

visualization design demo

为了简单,例子中其他视图的部分我剪裁掉了,只保留了一副 Sankey 图,文字部分也打码,但应该还是可以看出结构的。基本上元素有矩形、小圆、曲线、文字。矩形在最上层,有 hover 和 click 交互。线段和矩形都是半透明,线段在矩形下层。矩形之间的连接靠的是和它相邻的小圆点。文字分两部分,年份和矩形下面的字段。那么经过分析可以做出如下判断:

计算、计算、还是计算

经过刚才的分析和举例,你应该也看得出其实算坐标就是可视化中最重要的事。各种点各种 x,y 算来算去,算出坐标之后的渲染、样式都是水到渠成。一般计算也分几个步骤。这些步骤不一定是按顺序的,而且实现的时候你还可以不断根据需求优化调整。

1 数据结构设计

这个我上文也略微提到,只有你数据结构设计得好,才能降低实现的难度并有效提升性能。

通常是数组就搞定一切了,但复杂的可视化中像 tree 和 graph 这种经典的数据结构也经常会被用到。无需掌握太复杂的,基本操作就够用了。当遇到性能瓶颈时,因为这些数据结构比较经典,你也有很多资料可参考去优化它。

2 比例尺 (scale)与映射

数据可视化中坐标、大小、形状、颜色、饱和度等都有可能映射不同的数据维度,所以这些都是可计算的部分,而且它们之间有时候还会互相影响。

比例尺有很多种,类别型(离散型)、有序型、数值型数据 (opens in a new tab)通常用到的比例尺也不一样。线性比例尺(linear scale)应该是最常用的,其他的比例尺可以参考 GitHub - d3/d3-scale: Encodings that map abstract data to visual representation. (opens in a new tab) ,每种比例尺用处不同,具体是用在哪种数据类型或哪种图元类型,感兴趣的你可以进一步学习一下。

3 坐标计算

坐标计算刚说过是可视化中最必不可少的环节,通常是一些简单的数学计算,就是加减乘除啦 :) 算线性坐标(斜线)时可能会用到二元一次方程,算曲线可能会用到二次或高次方程,能回忆起并用上初中高中的知识有时候是很有趣的事。

4 交互计算

交互计算一般就是事件驱动了,在回调函数中进行数据的再处理,进行二次计算后渲染出来就完成了一段交互。数据量少的时候可以一次次遍历,完全不用担心性能。如果数据量巨大,你可以采取空间换时间的方法,在相关交互的元素中互相存储引用,这样只要 O(1) 就可以完成交互。

5 动画计算

一般可视化都有动画成分。用 Chrome Developer Tool 录屏观察这些动画,就发现它们一般都是沿着一个轨迹去运动,所以动画的计算就是去算出这些轨迹,然后再插值(interpolate)

这里稍微解释一下插值: 插值你可以理解成在两个数字之间按一定规律插入一系列数字。比如起点坐标是 (0, 0),终点坐标是 (10, 10),那可以在其中插值 (1, 1), (2, 2), (3, 3)… 等,也可以插入 (1, 1), (2, 2), (4, 4), (8, 8)…等,计算机去按这些插入的值不停的计算再渲染,就变成了动画。显然这个点按后一种插值方式运动的速度更快,这样我们肉眼会看到它是以一个加速度去运动到终点的。不同的插值方式造成了不同的动画效果。

计算举例

这些一系列计算的例子可以参考我之前的博客 数据可视化之 Sankey 桑基图的实现 - GeekPlux (opens in a new tab) 。其实不管什么图都大同小异啦。

渲染

计算出所有需要的坐标之后就可以去渲染了,让其画到画布上。在 Web 上一般可以靠 HTML + CSS、SVG、Canvas、WebGL 去画,它们的能力互有交叉,你可以根据需求选择。

选择时除了要考虑性能问题,还要想想数据表达和实现成本。最简单的例子:如果你是用 HTML 和 CSS 去渲染元素,那么上下层关系你可以简单地通过 z-index 去控制,而如果用 SVG 去渲染,那只能通过元素在 DOM 树中的前后顺序去控制了,用 WebGL 去表达这种就复杂了,深度缓存、Blending 啥的,3D 可视化还要算 z 轴坐标。

渲染好像没多少说的,更底层的渲染机制我们没必要了解,除非涉及到更难的可视化吧,至少我现在还没碰到。

这是一篇经验贴。如果按参加工作时间开始算,我也是个六年经验的 code monkey 了。现在愈发觉得实际编码前的思考和规划更为重要,编码只是实现中最简单的环节,帮你把思考的结果表达出来而已。