寫(xiě)在前面
第一次了解到dot已經(jīng)是很久之前的事情了,但是到今天才決定寫(xiě)下一點(diǎn)東西,可見(jiàn)懶到什么程度。最開(kāi)始對(duì)dot感興趣是因?yàn)橄旅孢@張圖:

對(duì)于這種網(wǎng)絡(luò)圖用visio很容易搞定,但是復(fù)制、粘貼、拖拽這些用起來(lái)總是感覺(jué)不怎么順手。但是用dot來(lái)做就完全不一樣了,只需寫(xiě)段文本:
digraph G {
main -> parse -> execute;
main -> init;
main -> cleanup;
execute -> make_string;
execute -> printf;
init -> make_string;
main -> printf;
execute -> compare;
}
然后在需要的時(shí)候在這段文本中增加邊、節(jié)點(diǎn)即可。保存之后只需要用貝爾實(shí)驗(yàn)室搞的graphviz來(lái)生成目標(biāo)圖片就可以了:
dot -Tpng G.dot -o g.png
這樣你的vim、emacs就馬上變成了一個(gè)可以畫(huà)圖的工具了:)。
可能你覺(jué)得這樣還不夠爽,想想看如果用代碼自動(dòng)生成dot文件,也就是說(shuō)可以通過(guò)用代碼輸出dot文件來(lái)間接到達(dá)輸出圖片的目的,是不是能做的事情多多了?
簡(jiǎn)單用法
日常中用到畫(huà)圖的地方,知道下面幾點(diǎn)基本上就夠用了:
- 有向圖(digraph)用a->b,無(wú)向圖(graph)用a--b;
- 節(jié)點(diǎn)、邊通過(guò)中括號(hào)中的key=value來(lái)設(shè)置,比如main[shape=box];將main節(jié)點(diǎn)設(shè)置為矩形;
- 連接點(diǎn)的方向可以通過(guò)b->c:se;進(jìn)行指定;
- 使用subgraph定義子流程圖;
常用屬性
對(duì)于各種結(jié)構(gòu)的通用的屬性如下:
| 屬性名稱(chēng) | 默認(rèn)值 | 含義 |
|---|---|---|
| color | black | 顏色 |
| colorscheme | X11 | 顏色描述 |
| fontcolor | black | 文字顏色 |
| fontname | Times-Roman | 字體 |
| fontsize | 14 | 文字大小 |
| label | 顯示的標(biāo)簽,對(duì)于節(jié)點(diǎn)默認(rèn)為節(jié)點(diǎn)名稱(chēng) | |
| penwidth | 1.0 | 線條寬度 |
| style | 樣式 | |
| weight | 重要性 |
常用邊屬性如下:
| 屬性名稱(chēng) | 默認(rèn)值 | 含義 |
|---|---|---|
| arrowhead | normal | 箭頭頭部形狀 |
| arrowsize | 1.0 | 箭頭大小 |
| arrowtail | normal | 箭頭尾部形狀 |
| constraint | true | 是否根據(jù)邊來(lái)影響節(jié)點(diǎn)的排序 |
| decorate | 設(shè)置之后會(huì)用一條線來(lái)連接edge和label | |
| dir | forward | 設(shè)置方向:forward,back,both,none |
| headclip | true | 是否到邊界為止 |
| tailclip | true | 與headclip類(lèi)似 |
常用節(jié)點(diǎn)屬性如下:
| 屬性名稱(chēng) | 默認(rèn)值 | 含義 |
|---|---|---|
| shape | ellipse | 形狀 |
| sides | 4 | 當(dāng)shape=polygon時(shí)的邊數(shù) |
| fillcolor | lightgrey/black | 填充顏色 |
| fixedsize | false | 標(biāo)簽是否影響節(jié)點(diǎn)的大小 |
常用圖屬性如下:
| 屬性名稱(chēng) | 默認(rèn)值 | 含義 |
|---|---|---|
| bgcolor | 背景顏色 | |
| concentrate | false | 讓多條邊有公共部分 |
| nodesep | .25 | 節(jié)點(diǎn)之間的間隔(英寸) |
| peripheries | 1 | 邊界數(shù) |
| rank | same,min,source, max,sink,設(shè)置多個(gè)節(jié)點(diǎn)順序 | |
| rankdir | TB | 排序方向 |
| ranksep | .75 | 間隔 |
| size | 圖的大?。ㄓ⒋纾?/td> |
高級(jí)用法
在dot里面label的玩法比較多,在上面看到的每個(gè)節(jié)點(diǎn)都是簡(jiǎn)單的一段文字,如果想要比較復(fù)雜的結(jié)構(gòu)怎么辦?如下圖:

對(duì)應(yīng)的代碼如下:
digraph structs {
node [shape=record];
struct1 [shape=record,label="<f0> left|<f1> mid\ dle|<f2> right"];
struct2 [shape=record,label="<f0> one|<f1> two"];
struct3 [shape=record,label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
struct1 -> struct2;
struct1 -> struct3;
}
這個(gè)還不算厲害的,label還支持HTML格式的,這樣你能想得到的大部分樣子的節(jié)點(diǎn)都可以被定義出來(lái)了:

代碼如下:
digraph html {
abc [shape=none, margin=0, label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR><TD ROWSPAN="3"><FONT COLOR="red">hello</FONT><BR/>world</TD>
<TD COLSPAN="3">b</TD>
<TD ROWSPAN="3" BGCOLOR="lightgrey">g</TD>
<TD ROWSPAN="3">h</TD>
</TR>
<TR><TD>c</TD>
<TD PORT="here">d</TD>
<TD>e</TD>
</TR>
<TR><TD COLSPAN="3">f</TD></TR>
</TABLE>>];
}
接著來(lái)看cluster的概念,在dot中以cluster開(kāi)頭的子圖會(huì)被當(dāng)做是一個(gè)新的布局來(lái)處理,而不是在原圖的基礎(chǔ)上繼續(xù)操作。比如:

對(duì)應(yīng)代碼如下:
digraph G {
subgraph cluster0 {
node [style=filled,color=white];
style=filled;
color=lightgrey;
a0 -> a1 -> a2 -> a3;
label = "process #1";
}
subgraph cluster1 {
node [style=filled];
b0 -> b1 -> b2 -> b3;
label = "process #2";
color=blue
}
start -> a0;
start -> b0;
a1 -> b3;
b2 -> a3;
a3 -> a0;
a3 -> end;
b3 -> end;
start [shape=Mdiamond];
end [shape=Msquare];
}
如果沒(méi)有cluster的話我們大概能想象的出來(lái)最后的結(jié)果是什么樣子的??赡軙?huì)想能不能將一個(gè)節(jié)點(diǎn)直接指向cluster?答案是不能!對(duì)于這種需求可以用lhead來(lái)搞定:
digraph G {
compound=true;
subgraph cluster0 {
a -> b;
a -> c;
b -> d;
c -> d;
}
subgraph cluster1 {
e -> g;
e -> f;
}
b -> f [lhead=cluster1];
d -> e;
c -> g [ltail=cluster0, lhead=cluster1];
c -> e [ltail=cluster0];
d -> h;
cluster0->cluster1;
}
生成的圖片如下:
