语法(Grammar)赋予了一门语言规则,此外在语言学上有专门的技术含义。在乔姆斯基(Chomsky)的转换理论中,语法是一个由规则组成的系统,用来生成一门语言中的合法语句。乔木斯基通过深刻而具有普遍性的结构来解释了许多特定自然语言的外在特征,其发明的上下文无关语法是现代计算机编程语言解释器的起源
语法让语言具有了表达力,假如一门语言只有单词而没有语法,则其表达的含义就仅局限于单词了。语法通过指明单词如何在句子中排列而拓展了语言的能力
本系列是关于创建可视图形的语法规则,图形化的语法规则使我们脱离了图表(类似语言中的单词)集合的束缚,达到了一个无限制的图形表达世界(类似从单词到句子)。图形的语法的规则同时具有数学和艺术双重特性,数学提供表达抽象能力的符号工具,而艺术(从源自古希腊的角度)则是提供了感官特性(如颜色、形状、声音等)抽象的原则,在现代场景下,艺术也可以看做是品味。我们这个系列要讲的不是什么好品味或图形设计的知识,我们关心的是构造图形的数学规则以及用艺术化的方式来呈现
说起图形语法(the grammar of graphics)很容易让人联想到Bertin在1967年出版的《Semiology of Graphics》,那是第一个也是最有影响力的统计制图法结构化理论,在图形化语法中遍布着Bertin的工作,记号学(Semiology)处理的是符号。尽管Bertin将符号是写在纸上的,但他的工作在虚拟空间中仍然可以发挥作用
图形与图表
我们经常会把图形称之为是图表,如饼图、柱状图、线图等,但我们这个系列会竭力避开图表的分类。因为图表通常是更通用对象的实例,例如当我们认识到饼图不过是将图块按极坐标来排列,那么我们就可以创造出更少见的极坐标图形,而且我们还会明白一些看上去类似的图形为何会有截然不同的图形语法
另一个避开图形分类的原因是,一旦我们努力去按照分类去开发图表,那么我们就要做两件事,一个是面对用户更丰富图表种类需求,其次是我们的程序将不可避免的复杂化,高雅的实现需要我们从图形的角度而非图表的角度去思考问题
图形的概念是如此的普通,以至于我开门需要组织一些创建图形实例的原则,例如我们希望提供给用户一些创建饼图的简单途径而非在对话框里提供一个饼图的实例供其选择,对此我们需要一个基于面向对象的方法论
面向对象
本系列中的很多想法都受益于面向对象设计思想,面向对象设计(Object-oriented design:OOD)包含了大量的技术和法则,这会让那些习惯过程式编程的开发人员感到困惑,下面我们花些时间来介绍下OOD
OOD是什么
OOD会用到很多策略来让软件更加灵活和可复用
- 对象是这个系统的基础构件,在现代
OOD系统中其名称有非常明显的含义,例如Factory、Decorator、Facade、Proxy、Iterator、Observer、Visitor,这些对象做的事情正如其名,一个Decorator就是添加模式,一个Observer就是查询消息 - 对象通过简单的消息相互连接,这些消息分布在整个系统里,
- 一个对象是非常“蠢笨”的,它们只干有限的事情,十分的简单和通用,这也是为了更好的复用
- 智能体现在系统上,而非具体的对象中,整体之和比单独的个体更重要
- 面向对象系统的构件是相对模块化的,如果系统的某些部分被丢弃或发生故障,系统的其余部分通常可以继续工作
- 对象可以从其他的对象继承属性和函数,这有助于节省时间提升代码的组织性
- 对象通常也是多态的,不同的对象可以用不同的方法响应相同的消息
OOD期待开发者善用抽象,不好的开发者常常会忽略细节,不好的设计者则是会迷失在细节中
OOD不是什么
OOD不是一门语言OOD不是GUIOOD不是一个交互系统
为什么选择OOD
根据我们的经验,OOD并没有带来更高的可靠性,系统的可靠性更依赖于在开发过程的早期进行简洁的设计和密集的测试;OOD也没有给我们增加程序的可移植性;OOD也没有让我们更快,汇编语言或C程序在执行时间方面是很难打败的。虽然有例外,但一般来说,OOD的吸引人的封装和多态性甚至会有副作用,OOD也没有给我们更快的开发进度,事实上OOD会阻碍开发,因为对象通常更多,开发人员很难正确地构思,修改已存在的对象则更是困难
但尽管如此,OOD仍然是思考图形的最佳方式,OOD是一种自然的思维框架因为图形就是天然的对象,我们可以看到和触摸这些物体。
一个面向对象的图形系统
图形可以视为是点的集合,从OOD的角度来看,图形就是一系列对象的集合,如果这些对象之间的消息遵循一个简单的语法,那么他们就可以一致灵活的协同,遵循这个想法,我们可以将图形创建的过程划分为三个阶段
- 制定规范
- 组装
- 展现
制定规范
规范包含将用户操作转换成形式化语言,该语言对一个需要理解图形化请求的自动化系统来说十分必要。我们的图形语法有六个基本的要素:
DATA:一组从数据集创建变量的数据操作TRANS:变量转换(如排序)SCALE:度量(如log度量)COORD:一个坐标系统(如极坐标)ELEMENT:图形及其艺审美属性(如颜色)GUIDE:一个或多个辅助物(如轴线、图例)
组装
一个场景和这个场景的描述是不同的,为了描绘一个场景,我们必须协调其形状、布局以及美学性质。一个统计学的图形程序必须可以根据规则组装出及时的图形场景
展现
如我们所知,一个图形必须以富于美感和恰当的可视化系统来渲染出来
一个示例
有了图形语法,我们不必在纠结于具体的图表类型,我们将不再以分类的思考方式来总结和归纳图表,而是从更抽象、更基础的角度将图表拆分成一般元素然后通过一定的规则来通过组合这些元素来形成图表。我们以下图为例,这张图描绘了不同国家的出生率和死亡率,密度曲线表明了国家分布的情况,按照传统的分类思维,我们很难将其归入到具体的类型中
从图形语法的角度,我们可以将其描述为:
ELEMENT: point(position(birth*death), size(0), label(country))
ELEMENT: contour(position(smooth.density.kernel.epanechnikov.joint(birth*death)),color.hue())
GUIDE: form.line(position((0,0),(30,30)), label("Zero Population Growth"))
GUIDE: axis(dim(1), label("Birth Rate"))
GUIDE: axis(dim(2), label("Death Rate"))
通过图形语法,我们可以简单的做些修改,就能得到一个完全不同的图表,例如我们将核密度曲线改成几何图形,则我们就得到了一个热力图
ELEMENT: polygon(position(smooth.density.kernel.epanechnikov.joint(birth*death)),color.hue())
如果我们改变点的描述,则会得到另外一幅图
ELEMENT: point(position(birth*death), size(military), label(country))
上述例子表明,我们可以通过基本的要素构成一个丰富多彩的图表世界,之后我们可以采用树结构将这些要素组合起来,形成一个完整的图表
总结
本文介绍了图形语法的基础知识,下一节我们将以饼图为例,介绍用图形语法构建的完整过程