1. Graphviz 简介
本文大部分内容摘录自: 开源项目:【自动】绘图工具 Graphviz
1.1 Graphviz 是啥?
Graphviz
是洋文 Graph Visualization
的缩略词,是一个开源的,跨平台的自动绘图工具,其官网在 “这里”,维基百科的介绍在 “这里”。
这玩意儿诞生于上个世纪末,来自 AT&T
的实验室,属于名门正派出身。十多年来,它已经被广泛使用于各个领域。
Graphviz
不但是开源软件,而且是自由软件。使用它完全【无需】付费,也【没有】任何注册码之类的恶心东西。
1.2 Graphviz 能干啥?
“绘图工具” 有很多种,Graphviz
主要是用来绘制【关系图】。所以它更类似于微软的 Visio
。
但是它与 Visio
有一个【本质上】的差异:
- 用
Visio
画图是【手动】的——你需要动用你的肉眼和手指头。 - 用
Graphviz
画图是【自动】的——你只需要告诉Graphviz
这张图包含哪些元素,元素之间有啥关系,然后Graphviz
可以【自动】帮你画出来。
那么,你如何告诉 Graphviz
你要画的图形包含哪些元素捏?这就需要用到一个名叫 DOT
的描述语言。
1.3 为啥用 Graphviz 而不用 Visio 或类似的工具?
客观地讲,Graphviz
和 Visio
之类的工具,各有各的特长。
因为本文介绍的是 Graphviz
,所以下面聊一下:哪些场景是 Graphviz
胜过 Visio
类工具的。
简而言之,
Graphviz
胜过Visio
这类工具的关键在于【自动布局】。
如果你要绘制的关系图非常复杂,这时候【手动】布局就变得极其繁琐。而 Graphviz
的自动布局功能,再复杂的关系图,也可以自动搞定。
提示:
Graphviz
的自动布局功能,【无需】人为干预就可以做到 “最小化连线交叉”。
可以从官网的图库查看通过 Graphviz
生成图片的例子。
1.4 安装
1.4.1 桌面端应用
(1)从 Graphviz 官网 下载安装包,并进行安装操作。
添加 Grahpviz 路径到系统 `PATH` 环境变量中(2)从 DotEditor - Graphviz 桌面 GUI 下载 DotEditor
,可以直接打开使用。
DotEditor
依赖 Grahpviz
的 PATH
环境变量,如果没有配置,打开 DotEditor
软件会出现如下图所示错误。
1.4.2 Web 端服务
2. DOT 语言入门
前面提到,你需要通过 DOT 语言
来描述一个关系图,然后 Graphviz
根据这个 DOT 语言
的描述来自动生成图形。
很多读者一听到 “语言” 就先望而生畏,其实这个 DOT
并不复杂。
从原则上讲,它只描述三种东西,分别是:图(
graph
)、节点(node
)、边(edge
)。
你可以通过 DOT
语言定义这三种东西的属性(比如:颜色、形状)。
2.1 图(graph
)
DOT 语言
支持两种图形,分别是 “有向图(digraph
) 和 无向图(graph
)”。
通俗地说,“有向图” 里面的连线是有箭头;反之,“无向图” 里面的连线是没有箭头的。
定义一个无向图很简单,先看下面这段代码。
graph simple
{
a -- b -- c;
b -- d;
}
// 这是个无向图
上述代码的效果图如下:
无向图 graph
要定义一个有向图,也很简单,代码如下:
digraph simple
{
a -> b -> c;
b -> d;
}
/* 这是个有向图 */
上述代码的效果图如下:
有向图 digraph
这 2 段代码的简单释义:
-
graph
用来表示一个无向图;digraph
用来表示一个有向图。 - 示例中的
simple
表示图的名称。- 图的名称可以是【英文字母、下划线、数字、中文】。
- 最好【不要包含】其它英文的标点符号(也就是【半角符号】),可能会导致一些语法错误。
- 但是中文标点符号(也就【全角符号】)没有关系。
-
花括号/大括号 里面的语句表示【图的定义】——这张图包含哪些内容。
- 每一条语句以【分号】结尾(类似于 C、C++、Java 的语法)。
顺便提一下 DOT 语言的注释
(其注释的语法与 C、C++、Java 类似),包括如下两种:
-
单行注释:以
//
表示——【该行】后续的内容为注释 -
多行注释:以
/*
和*/
包含起来的内容为注释
2.2 节点(node
)
通过上面两个例子,你应该已经获得了感性的认识。OK,下面来讨论“ 节点”(node
)的概念。
在上面两个例子中, a b c d
都是【节点名】,分别代表节点。
在图的定义中,相同名称就代表同一个节点。
当DOT
编译器碰到一个新的名称,就认为这是一个新的节点。
节点的命名规范类似于图的命名规范,此次不再罗嗦。
如果某个节点没有设置 label
属性(关于【属性】,下面会聊到),那么图形中就用节点名作为该节点的标题——就好比前面两幅简单的示意图。
2.2.1 节点(node
)的属性
在节点名之后可以使用 方括号/中括号 来定义该节点的属性,属性之间用【半角】逗号分隔。
属性的定义采用如下形式:
属性名 = 属性值
(如果属性值包含空格,需用【半角】引号把属性值引用起来)
常用的【属性名】包括如下:
-
label
:标题 -
color
:颜色 -
style
:样式 -
shape
:形状
(还有更多属性,可以参见官网 “这个链接”)
给一个示例代码及效果图,你一看就明白了:
digraph node_attr
{
shape1 [shape=box, label="编程随想注:\n矩形节点"];
shape2 [shape=circle, label="编程随想注:\n圆形节点"];
shape3 [shape=ellipse, label="编程随想注:\n椭圆形节点"];
shape4 [shape=polygon, sides=4, skew=0.4, label="编程随想注:\n平行四边形节点"];
shape5 [shape=none, label="编程随想注:\n无边框节点"];
shape1 -> shape2 -> shape3 -> shape4 -> shape5
color1 [color="blue", label="编程随想注:\n蓝色边框"]
color2 [color="green", style=filled, label="编程随想注:\n绿色填充"]
color3 [color="#ff0000", style=filled, fillcolor="yellow", label="编程随想注:\n红色边框+黄色填充"]
color4 [color="#0000FF" style=filled, fillcolor="green:red", label="编程随想注:\n蓝色边框+从绿色到红色渐变填充"]
/* 上面两个节点采用 HTML 的颜色语法,dot 支持 这种语法 */
color1 -> color2 -> color3 -> color4
text1 [shape=box, fontsize=12, label="编程随想注:\n小字体"]
text2 [shape=box, fontsize=24, label="编程随想注:\n大字体"]
text3 [shape=box, fontcolor="blue", label="编程随想注:\n蓝色文字"]
text4 [shape=box, label=<编程随想注:<br/><b>粗体</b> <i>斜体</i><u>下划线</u>>]
// 注意:text4 使用 HTML 风格的 label,无需引号,但必须用尖括号
text1 -> text2 -> text3 -> text4
}
补充说明:
- 在上述示例,俺刻意用到了 HTML 的颜色语法。关于这种语法的说明可以参见维基百科的这个链接。
- 上面的图形用 Graphviz 在线绘图工具 进行渲染。
2.3 边(edge
)
如前面所示,无向图的边用 --
表示,有向图的边用 ->
表示,非常形象。
提示:定义边的语句也是以分号结尾。
边与节点的关键差异之处在于——节点有名称而【边没有名称】。
2.3.1 边(edge
)的属性
边也可以设置属性,其属性写在定义连线的语句末尾,语法类似节点属性。
常用的【属性名】包括如下:
-
label
:标题
-color
:颜色 -
style
:线条的样式 -
dir
:边的方向(仅用于有向图,可设置:正向箭头、反向箭头、双向箭头) -
arrowhead
:前端的样式 -
arrowtail
:末端的样式
(还有更多属性,可以参见官网“这个链接”)
下面给几个示例,你自己去揣摩(以【有向图】作示范)
digraph edge_attr
{
style0[label="编程随想注:\n以下是样式的示例"];
style1[label=""] style2[label=""] style3[label=""] style4[label=""];
style0 -> style1 [style=solid, label="实线"];
style1 -> style2 [style=bold, label="粗线"];
style2 -> style3 [style=dashed, label="短划线"];
style3 -> style4 [style=dotted, label="虚线"];
arrow0[label="编程随想注:\n以下是箭头的示例"];
arrow1[label=""] arrow2[label=""] arrow3[label=""] arrow4[label=""] arrow5[label=""] arrow6[label=""];
arrow0 -> arrow1 [dir=both, label="双向箭头"];
arrow1 -> arrow2 [arrowsize=2.0, label="大箭头"];
arrow2 -> arrow3 [arrowhead="open", label="带倒钩的箭头"];
arrow3 -> arrow4 [arrowhead="halfopen", label="单边倒钩"];
arrow4 -> arrow5 [arrowhead="ediamond", label="菱形箭头"];
arrow5 -> arrow6 [arrowhead="dot", label="圆形箭头"];
color0[label="编程随想注:\n以下是颜色的示例"];
color1[label=""] color2[label=""] color3[label=""];
color0 -> color1 [color="blue", label="蓝色"];
color1 -> color2 [color="red:blue", label="双色"];
color2 -> color3 [color="green:red;0.4:blue", label="颜色分段"];
}
通过 Dot Editor 生成的图形
字体属性设置为 serif【提示】
如果会出现中文乱码。
可以需要设置node
和edge
以及graph
的fontname
属性
2.4 图的属性
说完了 “节点” 和 “边”,最后稍微聊一下 “图” 本身的属性。
常用的【属性名】包括如下:
-
label
:标题 -
bgcolor
:颜色 -
fontname
:字体名称(【不】影响节点和边) -
fontsize
:字体大小(【不】影响节点和边) -
fontcolor
:字体颜色(【不】影响节点和边) -
center
:是否居中绘制
(还有更多属性,可以参见官网 “这个链接”)
digraph graph_attr
{
graph[bgcolor="cadetblue" label="图的标题" fontsize=24 fontcolor="green"];
node0 -> node1;
node0 -> node2;
}
网友评论