学习Graphviz绘图
简介
graphviz是贝尔实验室开发的一个开源的工具包,它使用一个特定的DSL(领域特定语言):dot作为脚本语言,然后使用布局引擎来解析此脚本,并完成自动布局。graphviz提供丰富的导出格式,如常用的图片格式,SVG,PDF格式等。
相对于ms viso需要手动拖动图标,graphviz只需要通过DOT代码表达各节点的逻辑关系,然后自动布局和输出关系图。最小化复杂关系的连线交叉,增强可读性。尤其在绘制非常复杂的逻辑关系、组织架构、模块组成、数据结构等图时,可以大大减少工作量,理清思路。
但是无法绘制需要自定义或者固定布局的图,比如时序图。
布局器
Graphviz除了DOT语言用于描述图像,还有许多渲染生成工具 —— 布局器:
命令 | 说明 |
---|---|
dot | 一个用来将生成的图形转换成多种输出格式的命令行工具。其输出格式包括PostScript,PDF,SVG,PNG,含注解的文本等等。 |
neato | 用于sprint model的生成(在Mac OS版本中称为energy minimized)。 |
twopi | 用于放射状图形的生成 |
circo | 用于圆形图形的生成。 |
fdp | 另一个用于生成无向图的工具。 |
dotty | 一个用于可视化与修改图形的图形用户界面程序。 |
lefty | 一个可编程的(使用一种被EZ影响的语言[4])控件,它可以显示DOT图形,并允许用户用鼠标在图上执行操作。Lefty可以作为MVC模型的使用图形的GUI程序中的视图部分。 |
DOT语言
DOT语言是一种文本图形描述语言它提供了一种简单的描述图形的方法,并且可以为人类和计算机程序所理解。DOT语言文件通常是具有.gv或是.dot的文件扩展名。很多程序都可以处理DOT文件。
首先,在dot脚本中定义图的顶点和边,顶点和边都具有各自的属性,比如形状,颜色,填充模式,字体,样式等。然后使用合适的布局算法进行布局。布局算法除了绘制各个顶点和边之外,需要尽可能的将顶点均匀的分布在画布上,并且尽可能的减少边的交叉(如果交叉过多,就很难看清楚顶点之间的关系了)。所以使用graphviz的一般流程为:
- 定义一个图,并向图中添加需要的顶点和边
- 为顶点和边添加样式
- 使用布局引擎进行绘制
基本用法
DOT中使用图(digraph/graph/subgraph)、节点(node)和边(edge)来描述关系图/流程图,在配合一些属性的设置完成绘图。
顶点和边都接受属性的定义,形式为在顶点和边的定义之后加上一个由方括号括起来的key-value列表,每个key-value对由逗号隔开。如果图中顶点和边采用统一的风格,则可以在图定义的首部定义node, edge的属性。
说明:
- graph 用来描述无向图,关系使用 –来描述,digraph用来描述有向图,关系使用 -> 来描述。
- demo为定义的图片名称,label和bgcolor为定义的图片属性。
- father、mother、brother、sister、我、strangers为节点。可以把前面4个节点理解成变量定义,比如定义了一个变量father,名字叫爸爸,用方形来渲染,后面所有调用father都会按照方形爸爸来渲染,但这里其实和变量定义是不同的,因为这个节点即便不用也会渲染出来,比如strangers,变量思维为加强理解。比如我没有定义也是可以直接使用的。
- 描述节点与节点的关系理解为边。边有有向(->)和无向(–)两种。比如father和mother之间的关系为相互的。
- 上面有两个特殊的节点,node和edge,node用来定义节点的默认属性,edge用来定义边的默认属性。作用域从本次定义到下一次定义截住。特定节点/边设置的属性会覆盖默认值。
- []内属性,属性可以针对图、节点、边来设置。
- father 与子女的关系为一条条写的, mother 的关系则为直接通过大括号的方式来对应三个节点。
- rank 定义设置节点处在同一行,辅助渲染出来的图的效果。
- 注释和C语言类似,// 和 # 注释单行, /* */多行注释。
- DOT的写法不算严格,比如结束可以有分号,属性可以没有引号。
关键字
- node:定义全局节点属性时使用
- edge:定义全局连线属性时使用
- graph:定义全局图属性,或声明一个无向图时使用
- digraph:声明一个有向图时使用
- subgraph:声明一个子图时使用,如果父图是有向图则子图是有向图,如果父图是无向图则子图也是无向图
- strict:用于防止相同的两个节点间使用重复的连线。
ID命名规则
ID是编辑者自定义的字符串,相当于C语言中的标识符。如果ID中间包含空格一定要用双引号包裹。
- 英文字母[a-zA-Z\200-\377],下划线_,数字[0-9](但不能数字开头),如:Version_3;
- 纯数字[-]?(.[0-9]+|[0-9]+(.[0-9]*)?),如:-.1或1.414;
- 双引号包裹的字符串"…",字符串中的双引号需要转义",如:“DOT language”;
- 尖括号包裹的HTML字符串<…>,如:«b>Welcome to China.>;实际上甚至可以插入表格。
转义与实体符号
字符串中的字符,只有双引号"和反斜杠\需要转义。
字符串支持还HTML式的实体符号,如:&表示&,<表示<,β表示β。
当节点的属性shape=record时,竖杠|、花括号{ }、方括号[ ]和尖括号< >都需要转义。
分组符号
前面介绍了两种包裹字符串的符号,双引号"…“和<…>;
另外还有两种包裹分组的符号:方括号[…]和花括号{…}。
罗盘端口
罗盘也就是确定八个方位,罗盘端口就是方位端口。
方位端口是每个节点隐藏自带的,可以直接使用。
每个节点都有八个方位:北n、东北ne、东e、东南se、南s、西南sw、西w和西北nw。
利用方位可以指定连线从哪个位置连接节点,不同于默认情况下的自动连线,利用方位可以手动指定连线的位置。
图
graphviz中包含了众多的布局器:
- dot 默认布局方式,主要用于有向图
- neato 基于spring-model(又称force-based)算法
- twopi 径向布局
- circo 圆环布局
- fdp 用于无向图
无向图
在最简单的应用中,DOT语言可以用来描述一张无向图。无向图显示了对象间最简单的关系,例如人之间的友谊。使用关键字graph开始一张无向图的定义,并用大括号包含要描述的节点,双连字号(–)被用来描述节点间的关系。另外,一行的末尾需要加上分号(;)。
有向图
类似于无向图,DOT语言也可以用来描述一张有向图,类似于流程图和树状图。其语法与无向图相似,但要在图的最开始使用关键字’digraph’,并用箭头(->)表示节点直接的关系。
常用图属性
属性名 | 默认值 | 说明 |
---|---|---|
label | 图片标签,如上面示例 | |
bgcolor | 背景颜色 | |
fontcolor | black | 字体颜色,定义上面示例的颜色 |
fontname | Times-Roman | 字体 |
fontsize | 14 | 字体大小 |
rank | 子图等级限制, same,min,max,source,sink | |
rankdir | TB | 排序方向,LR(left to right) or TB(top to bottom) |
compound | false | If true, allow edges between clusters. 配合 lhead 和 ltail 使用 |
Graphviz颜色表
节点
常用节点属性
属性名 | 默认值 | 说明 |
---|---|---|
label | node name | 节点显示内容 |
color | black | node边框颜色 |
fontcolor | black | 字体颜色 |
fillcolor | 背景色 | |
fontname | Times-Roman | 字体 |
fontsize | 14 | 字体大小 |
shape | ellipse | 形状,box、ellipse、circle、diamond、plaintext、point、triangle、invtriangle |
style | 图形样式,eg. bold、dashed、dotted、filled | |
image | 背景图片地址 |
Graphviz节点样式
在顶点的形状为record的时候,label属性的语法比较奇怪,但是使用起来非常灵活。比如,用竖线”|”隔开的串会在绘制出来的节点中展现为一条分隔符。用<>括起来的串称为锚点,当一个节点具有多个锚点的时候,这个特性会非常有用,比如节点st_table的type属性指向st_hash_type,第4个属性指向st_table_entry等,都是通过锚点来实现的。
边
常用边属性
属性名 | 默认值 | 说明 |
---|---|---|
label | 描述关系 | |
color | black | 箭头颜色 |
fontcolor | black | 关系文字颜色 |
dir | forward | 设置方向:forward,back,both,none |
arrowhead | normal | 箭头头部形状。box、crow、diamond、dot、none、normal、vee |
arrowtail | 箭头尾部形状 | |
arrowsize | 1.0 | 箭头大小 |
style | 图形样式,eg. bold、dashed、dotted、filled | |
lhead | 当 compound 为true时,lhead用于指定边指向的cluster | |
ltail | 与ltail类似 |
Graphviz箭头样式
Graphviz边样式
子图
graphviz支持子图,即图中的部分节点和边相对对立(软件的模块划分经常如此)。
一个图可以包含多个子图,以及子图也可以嵌套子图。子图的名字须为cluster*,否则就直接当节点渲染了。