0x00 资源

0x01 基本语法

1. 图 (Graph)

DOT语言支持 有向图(digraph)无向图(graph) 两种图类型的定义,定义的基本语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 这是dot无向图的定义方法, 使用 -- 进行边的连接
graph G {
O -- H1; // 水分子简陋版本,后面有高级的(笑)
O -- H2;
}

// 这是dot有向图的定义方法, 使用 -> 进行有向边的连接
digraph DG {
first -> second;
second -> third;
third -> last;
last -> first;
}

可以看到,主要的区别在于定义词和连接词不同。

note

字符串特注:对于不含空格的字符串,可以不加单引号和双引号简化。

2. 图的节点(Node)

分为隐式定义显式定义

  • A -> B; 定义边的同时会隐式定义未定义的 A 和 B 两个节点

  • A [label = 'name of A'] 会定义一个标签为 name of A 的节点

3. 图的边 (Edge)

如图的类型中所讲,分为无向边有向边两种

  • 无向边定义:A -- B

  • 有向边定义:A -> B

  • 连续定义:A -> B -> C

4. 图、节点、边的属性 (Attributes)

针对三种不同的对象,属性的设置有些许区别,具体见如下实例。

1
2
3
4
5
6
7
8
9
10
11
digraph G {
// 图属性:设置布局为从左到右
rankdir=LR;

// 节点属性:定义节点的形状和标签
A [label="数据库", shape=cylinder];
B [label="应用服务器", shape=box];

// 边属性:定义边的颜色和标签
A -> B [label="数据流", color=blue];
}
简单范例

info

图的全局属性直接写在{}内;而节点和边的属性则写在它们各自定义后的[]

5. 图的子图(Subgraph)

子图也是一种图,继承于父类,通过在父图中嵌套定义来实现。具体语法见下实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
digraph G {
// 定义一个名为 "后端服务" 的集群
subgraph cluster_backend {
label = "后端服务"; // 集群的标签
style = "filled";
fillcolor = "lightgrey";

db [label="数据库"];
cache [label="缓存"];
db -> cache;
}

// 定义另一个集群
subgraph cluster_frontend {
label = "客户端";
app [label="移动App"];
}

// 集群间的连接
app -> db;
}

info

如果子图的名称以 cluster 开头,Graphviz 会在这些节点周围绘制一个矩形边框,将它们视觉上“聚集”起来。这时候的子图也被称为集群 (Cluster)

6. 注释 (Comment)

DOT语言支持C风格注释

  • 单行注释: // 这是一行无需多言的注释

  • 多行注释: /* 这是多行废话(实际只写了一行,笑) */

0x02 常见样式

这一部分的内容主要是介绍熟悉中可用的样式(键值对中的键),通过样式的选择可以达到美观的效果。

1. 图样式
属性 描述 常用值
size 生成的图的大小(英寸) “4,4”
rankdir 图的布局方式 TB(Top to Bottom, 默认)
LR(Left to Right)
bgcolor 画布背景色 #RRGGBB
label 图标题 “随便画的图”
fontsize 字体大小,全局 14
splines 边的绘制 true(曲线),false或者line(直线)
ortho(正交线)
2. 边样式
属性 描述 常用值
style 边的线条样式 solid(默认),dasheddottedbold
color 边的颜色 red(常见颜色基本都有),#RRGGBB
arrowhead 箭头样式 normaldotveediamondemptycrow
arrowtail 箭尾样式 同上
dir 边的方向 forwordbackbothnone
label 边的标签文本 “任何的我”
fontsize 标签字体大小 10,12
fontcolor 字体颜色 gray

note

关于边的特别说明:下面这两个都表示A和B两个节点有双向关系,但是其对应的图和边数是不一样的。

  • A -> B -> A 有2条边
  • A -> B [dir = "both"] 仅有1条边
3. 节点样式
属性 描述 常用值
shape 节点形状 boxellipsecirclediamondrecordcylindercomponent
style 节点基本样式 filled, dashed, dotted, bold, rounded
color 节点边框颜色 red#RRGGBB
fillcolor 节点填充颜色(需要style = filled yellow#RRGGBB
fontname 节点字体风格 Arial, Comic Sans MS宋体
fontsize 节点字号 12, 14
fontcolor 节点字体颜色 black, white

更多节点形状

0x03 常见用例

下面让Gemini老师给点用例,我先偷会懒哈,前两个是很简单且典型的工程图,最后一个是我闲的没事干了(笑)。

1. E-R 图 (实体关系图)

E-R 图用于表示数据库中的实体、属性和它们之间的关系。

  • 实体 (Entity): 通常使用 record 形状的节点来表示,可以将实体名和属性分栏显示。

  • 关系 (Relationship): 通常使用 diamond 形状的节点。

  • 基数 (Cardinality): 使用不同的箭头样式来表示,如 crow (多), tee (一)。

示例:一个简单的“用户-订单”E-R图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
digraph ER_Diagram {
graph [rankdir=LR];

// 定义节点形状
node [shape=record];
// 定义实体
user [label="{User | + UserID (PK)\l+ UserName\l+ Email\l}"];
order [label="{Order | + OrderID (PK)\l+ OrderDate\l+ Amount\l# UserID (FK)\l}"];

// 定义关系
node [shape=diamond, style=filled, fillcolor=lightyellow];
places [label="Places"];

// 连接实体和关系,并用标签表示基数
// |< 表示 “一”, >| 表示 “多” (crow's foot)
user -> places [arrowhead=none, label="1"];
places -> order [arrowhead=crow, label="N"];
}


E-R图

note

字符串转义:三种换行,,/code>代表换行居中,换行靠左,换行靠右

2. UML 类图 (Class Diagram)

类图是面向对象建模的核心,用于展示系统中的类、接口以及它们之间的静态关系。

  • 类 (Class): 使用 record 形状,分为三部分:类名、属性(字段)、操作(方法)。

  • 关系:

    • 继承 (Generalization): 带空心三角箭头的实线 (arrowhead=empty)。
    • 实现 (Realization): 带空心三角箭头的虚线 (style=dashed, arrowhead=empty)。
    • 关联 (Association): 普通实线 (arrowhead=veenone)。
    • 聚合 (Aggregation): 带空心菱形箭头的实线 (arrowhead=odiamond)。
    • 组合 (Composition): 带实心菱形箭头的实线 (arrowhead=diamond)。

示例:一个简单的“动物”类图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
digraph UML_Class_Diagram {
graph [rankdir=TB];
node [shape=record, style=filled, fillcolor=lightyellow];

// 定义抽象类 Animal
Animal [label="{Animal (abstract)\l|+ name: string\l|+ age: int\l|+ makeSound(): void\l}"];

// 定义接口 Flyable
Flyable [shape=record, style="dashed", label="{\<interface\>\lFlyable | + fly(): void\l}"];

// 定义具体类 Dog 和 Bird
Dog [label="{Dog | - breed: string\l|+ bark(): void\l}"];
Bird [label="{Bird | + wingSpan: float\l}"];

// 定义关系
// 继承:Dog 和 Bird 继承自 Animal
edge [arrowhead=empty, style=solid, dir=back];
Dog -> Animal;
Bird -> Animal;

// 实现:Bird 实现 Flyable 接口
edge [arrowhead=empty, style=dashed, dir=back];
Bird -> Flyable;
}
UML图
3. 就决定是你了,水分子 (H2O)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 画一个角度可控的水分子 (H₂O)
graph H2O {
// 必须使用 neato 或 fdp 引擎来支持 pos 属性
layout=neato;

// 为了防止引擎画出不必要的曲线,可以加上这句
splines=false;

// 定义节点样式
node [shape=circle, style=filled, fontcolor=white, fontsize=20];

// 使用 pos="x,y!" 属性手动指定节点位置
// "!" 是必须的,它强制引擎使用这个位置
O [label="O", fillcolor="grey", width=1, pos="0,0!"];
H1 [label="H", fillcolor="dodgerblue", width=0.6, pos="-1.2,0.8!"];
H2 [label="H", fillcolor="dodgerblue", width=0.6, pos="1.2,0.8!"];

// 定义化学键
O -- H1;
O -- H2;
}
可爱的水分子

note

通过neato引擎可以实现无向图的弹簧模型布局,而超模的pos属性可以通过值的最后加上!进行强制指定,具体可以看官方文档

0x04 工具链和应用

1. 工具链的安装和使用
1.1 安装

参考 Graphviz 官网下载页面 中的说明。

Windows可以直接到这个网站上进行下载.msi或者.exe进行安装。Linux和MacOS的包管理工具一般可以直接安装graphviz

1.2 使用

命令可以通过dot -?进行查询,下面介绍最有用的两种:

info

dot -T<format> [-K<engine>] <input_file> -o <output_file>
<format> : 文件格式,如 png, svg, jepg, …
<engine>: 指定布局引擎(可选), 如 neato,fdp, circo
<input_file> : 输入的 dot 文件
<output_file> : 输出的图片文件
用例:dot -Tpng -Kneato my_file.dot -o my_image.png

dot -T<format> -O <input_file>
<format> : 文件格式,如 png, svg, jepg, …
<input_file> : 输入的 dot 文件
此时生成的文件为<input_file>.<format>
用例:dot -Tsvg -O my_file.dot

2. DOT语言的应用

dot语言相当于提供了一个精确的代码→图的途径,因此在自动化生成图片的方面,dot都可以发挥作用。下面给出我观察到的:

  • 逆向工程中控制流图(CFG)的生成
  • AI生成DOT文本,然后有客户端进行识别和渲染生成图片
  • 数据结构的可视化展示
  • 决策树软件自动生成

0x05 更多主题

下面罗列了本博客没有涉及到的但是可能有用的内容,可以自行搜索学习

todo

  1. DOT语言完整的文法,比如通过端口(port)来指定连接点的位置
  2. DOT语言的属性,这部分非常丰富,建议参考官网和需要按需搜索学习
  3. DOT工具链的使用,主要是命令行选项,例如-G,-E,-N
  4. VS Code的graphviz插件安装及使用
  5. Python中,graphviz 库(通过生成DOT源码)和 pygraphviz库(通过API直接调用)是两种主流的自动化绘图方式,各有优劣,可按需选择