为什么需要 D3
硬件产品和交互设备的多样化使得可视化设计工具面临新的技术难题。理想情况下,可视化工具需要支持从桌面应用到 web 应用以及多触点移动设备,同时还需要紧随硬件发展的趋势,如多核计算以及特殊的图形硬件。Protovis 提供了 JavaScript 和 Java 的实现版本支持异构平台,D3 是 Protovis 的后续产品同样具备跨平台的特性。D3 与 Protovis 最大的差异在于用户能够更直接地使用 SVG,比 Protovis 更灵活。同时 D3 的性能要胜于 Protovis,特别是在动画方面,主要原因在于 D3 只有变化的属性才被更新而不是重新绘制整个场景。目前 Protovis 已停止开发,全面转向 D3。
D3 是什么
Web 上的交互式可视化通常需要同时使用多项技术,HTML 用于显示页面内容,CSS 用于设计样式,JavaScript 用于交互,SVG 用于绘制。值得高兴的是,DOM 以层次结构展现页面内容,使得这些技术能够相互协作。然而目前的可视化工具对 DOM 进行了过多自主形式的封装,导致这些工具在可访问性(accessibility, 学习)及表现多样性(expressiveness, 可视化呈现的多样性)都存在不足。D3 在综合考虑表现多样性、效率和可访问性的基础上提出的。
D3 并没有引入新的图形化语法,而只是解决了另一个不同的更小得问题:有效地操作基于数据的文档。D3 核心的共献在与设计了一个可视化的“内核”,类似于 jQuery、CSS 及 XSLT 这样的文档转换器(Document Transformer)。低层次上,D3 的文档模型直接操作图形原语,这一点类似于 Processing 和 Raphäel。而在高层抽象上,D3 包含了一系列内核之上的辅助模块,这些模块受之前的可视化系统影响而产生。
D3 使用了 selection 这一概念:用谓词标识一个元素的集合,然后赋予一系列的操作来改变被选的元素的值。这一概念起源于 CSS,而 jQuery 提供了更灵活的控制接口。然而,在数据可视化时,通常需要添加或删除一些元素(Element),然而 jQuery 缺乏这种动态改变的机制。基于 XML 的 XSLT 虽然能够允许用户按照定义好的模板填充数据并生成 HTML,但是没有高级的可视化抽象,无法灵活地处理繁杂的数学可视化任务。
Protovis 和 D3 都是基于宿主语言(JavaScript),采用声明式语言(DSL)描述式可视化设计。开发者告诉 DSL 需要什么样的计算结果,而不需要知道结果是如何计算的。HTML/CSS 以及 SQL 都是 DSL 的典型代表。用于可视化的声明式语言也有很多,如 Grammar of Graphics, ggplot2, HiVE, ViaQL 以及 Ploaris。这些语言都提供了高级抽象以及快速分析,但是并不提供细粒度的图形及交互式控制。
D3 的设计
D3 的原子操作是 selection:从当前文档中提取元素(Element)集合。操作符(Operator)作用于 selection 之上,用于修改元素内容。数据联合(Data Joins)将输入数据绑定到元素,使得操作符能够操纵相关的数据。这一过程产生了进入(enter)及退出(exit)两个子选择,分别用于创建和销毁元素与数据之间的对应关系。动画式的转换(transitions)可以对属性及样式进行插值处理,让它们变化更平滑。事件处理器(Event handlers)则用于对用户的输入产生响应并可以交互。大量的辅助模块(Modules),如布局、缩放简化了一些常用的可视化操作。
D3 与 Processing 的比较
源于 Mike Bostock 对两者作出评述。
- Pixel vs. Vector
Processing 像 HTML5 Canvas 一样,是基于像素的图形库;D3 使用 SVG,是基于矢量的。一些的图形化的效果如 motion bur and glow,如果用基于像素的库实现起来比较容易(可以组合多帧或者做卷积)。SVG 用 filter 也可以实现,但是不如 pixel-based 库那么灵活。而基于矢量的库则在缩放上有自身的优势。
- Immediate vs. Retained
Processing 由于是在 pixel buffer 中绘制,最终所有绘制的内容都变成 pixel buffer 中的元素。而 retained-mode 系统则维护一个可见元素的场景图(scenegraph)。它的好处在于你可以控制场景,改变了场景中的元素,场景跟着改变,而无须像 pixel buffer 那样管理 dirty region 然后再 redraw。基于这一点,后者能获得比较好的性能。但是对于很复杂的场景,维护场景自身也会带来一定的开销。
另外,对于动画,往场景中添加交互操作更容易。用 HTML5 Canvas,需要用 pointInPath 手工做 hit testing,用 SVG 只需要向 HTML 语句添加 event listener 即可。甚至可以用 CSS(hover, anchor tags, etc)做简单的交互。
- Proprietary vs. Standard
Processing 虽然具有一个非常好用的 API,但是远不如 HTML 流行。D3 建立在标准 HTML 之上,因此可以与其他技术进行整合,例如使用外部的 stylesheets 做样式,甚至可以使用 CSS3 作动画。也可以在服务器上生成 HTML,然后使用 D3 做数据变换在客户端上显示。或者与其他的 JavaScript 工具一起使用,如 jQuery。而 Processing 则是一个相对封闭的系统。
- Imperative vs. Declarative
Processing 本质上是一种 C/C++风格的编程语言,使用函数和 for 循环等等,通常被称为“Imperative”编程。D3 是声明式的,虽然不像 CSS 那样纯粹的声明式语法,但已经去除了大部分的控制语句。
总结
D3 在 web 可视化上确实下了很多功夫,尤其是动画上编程简单效果非常棒,而且 D3 的例子中实现了常见的可视化方法,很多可以直接拿来使用。但是受浏览器本身的限制,D3 仍然存在一些不足,特别是处理数据的规模还很小,尽管 Jeff Heer 还开发了与之相配合的 JS 数据库来支持 D3 处理更大的数据,但是效果并不佳。在交互上,D3 也还仍有很多工作需要继续。希望 D3 的发展越来越好,成为 web 可视化的标准库。
✉️ zjuvis@cad.zju.edu.cn