使用Graphviz繪製流程圖和關係圖
Graphviz概述
Graphviz
是一個由AT&T實驗室啟動的使用DOT語言來繪製關係圖/流程圖的開源工具包。
DOT
語言是一種文字圖形描述語言,它提供了一種簡單的描述圖形的方法。
使用Graphviz,我們只需要將精力集中在邏輯設計上,而不需要花費大量時間在圖形佈局的調整上,圖形繪製佈局都由工具引擎來搞定。也因此,需要精確定位的圖形就不適合用Graphviz來繪製了。另外,文字程式碼繪製圖形的方式也便於版本管理。
另外,
plantuml
也包含了dot語法,並且還具有更多的功能,或許你可以嘗試一下。
Graphviz工具
工具善其事,必先利其器。原諒我是一個工具痴 :-)
要想使用graphviz,首先需要上官網下載graphviz並安裝。安裝之後就可以使用graphviz自帶的編輯器gvedit
來編寫dot程式碼來繪製圖形了。快捷鍵F5
來預覽生成的圖片,Shift+F5
開啟對話方塊並點選ok就可以生成指定型別的圖片檔案。
但是graphviz自帶的gvedit編輯器那是非常非常的難用。怎麼辦呢?經過四處尋找和妥協,最終找到了windows平臺下的還挺好用的工具,此工具不僅具有dot程式碼高亮、程式碼提示,還闊以預覽生成的圖片,只是暫時還不能匯出圖片。該工具就是github出品的程式碼編輯器Atom,另外需要安裝兩個外掛:language-dot和graphviz-preview
使用Atom來編寫和預覽圖片,最後使用gvedit來匯出圖片。看起來還不錯的樣子。
- windows中安裝好graphviz之後,最好配置一下
PATH
環境變數。
- Atom的language-dot外掛中的程式碼提示模板(snippet)可能不能滿足你的需求,不過你可以自己新增和修改。這裡有我自己修改的程式碼模板。
中文亂碼解決
若渲染出的圖片中出現亂碼,檢查兩項:
-
檔案編碼需要使用utf-8。
-
windows平臺下需要在dot原始碼中指定字型名稱。具體如下:
// 影響圖片級別的字型 graph [fontname="宋體"]; // 影響節點中的文字字型 node [fontname="宋體"]; // 影響箭頭或線條上的文字字型 edge [fontname="宋體"];
DOT基本語法
DOT語法相對簡單和鬆散,沒有特別的格式要求,也沒有複雜的運算子和結構。你可以檢視官方文件以瞭解更多,其實安裝完graphviz後,其安裝目錄中就有文件了,位置如下:
GRAPHVIZ_HOME/share/graphviz/doc/html/index.html
|
概述
- DOT中使用圖(
digraph
/graph
)、節點(node
)和邊(edge
)來描述關係圖/流程圖。
- DOT的註釋風格和C類似(
//
用於單行註釋,/* */
用於多行註釋)。
圖
DOT可以描述有向圖(使用digraph
宣告)和無向圖(使用graph
宣告)兩種圖。圖由{}
中包含的節點和邊構成。
在圖的開頭使用graph []
對圖進行設定,如:graph
[bgcolor="gray"]
將圖背景色設定為灰色。屬性設定語句也可以不包含在graph []
中而直接使用。
子圖(使用subgraph
宣告)可以進行和“父圖”類似的設定,唯一注意的是子圖必須以cluster
做為名稱的字首。
節點
DOT中,節點可以不用宣告直接使用,但如果需要設定節點的屬性,則需宣告節點並在宣告處設定屬性然後再使用。每個節點首次出現的名稱做為該節點的唯一標識。
node []
用於設定節點預設屬性(對設定位置之後的點有效),在節點後面用[]
設定單獨一個點的屬性。
邊
DOT中有有向邊(使用->
表示)和無向邊(使用--
表示)兩種,有向邊用於有向圖,無向邊用於無向圖,不可混用。
和節點類似的,用edge []
設定邊預設屬性,在邊之後用[]
設定單獨一條邊的屬性。對於有向邊,還可以設定邊的起點/終點的位置(用n、e、s、w或它們的組合表示位置)。
常用屬性
對於各種結構的通用屬性如下:
屬性名稱 | 預設值 | 含義 |
---|---|---|
color | black |
顏色,顏色設定支援形如red 和#FF0000 兩種形式 |
fontcolor | black | 文字顏色 |
fontname | Times-Roman | 字型 |
fontsize | 14 | 文字大小 |
label | 顯示的標籤,支援’\n’換行,對於節點預設為節點名稱 | |
penwidth | 1.0 | 線條寬度 |
style | 樣式 |
常用圖屬性如下:
屬性名稱 | 預設值 | 含義 |
---|---|---|
bgcolor | 背景顏色 | |
concentrate | false | 讓多條邊有公共部分 |
nodesep | .25 | 節點之間的間隔(英寸) |
peripheries | 1 | 邊界數 |
rank | same,min,source, max,sink,設定多個節點順序 | |
rankdir | TB | 排序方向 |
ranksep | .75 | 間隔 |
size | 圖的大小(英寸) | |
labelloc | 調整圖或子圖的標籤的上下位置 | |
labeljust | 調整圖或子圖的標籤的左右位置 | |
compound | false |
If true, allow edges between clusters. 配合lhead 和ltail 使用 |
常用節點屬性如下:
屬性名稱 | 預設值 | 含義 |
---|---|---|
shape | ellipse | 形狀 |
sides | 4 | 當shape=polygon時的邊數 |
fillcolor | lightgrey/black | 填充顏色 |
fixedsize | false | 標籤是否影響節點的大小 |
常用邊屬性如下:
屬性名稱 | 預設值 | 含義 |
---|---|---|
arrowhead | normal | 箭頭頭部形狀 |
arrowsize | 1.0 | 箭頭大小 |
arrowtail | normal | 箭頭尾部形狀 |
constraint | true | 是否根據邊來影響節點的排序 |
decorate | 設定之後會用一條線來連線edge和label | |
dir | forward | 設定方向:forward,back,both,none |
headclip | true | 是否到邊界為止 |
tailclip | true | 與headclip類似 |
headlabel | 邊的頭部顯示的標籤 | |
taillabel | 邊的尾部顯示的標籤 | |
lhead |
當compound 為true時,lhead用於指定邊指向的cluster |
|
ltail | 與ltail類似 |
簡單示例
dot程式碼:
digraph simple_demo {
// 設定圖、節點和邊的預設屬性
graph [label="simple demo", bgcolor="#EEEEEE"];
node [style="filled", fillcolor="#AAAAAA"];
edge [style="dashed", arrowsize=0.6];
// 節點和邊
{a, b} -> {c, d};
}
|
圖片效果:
高階用法
繪製二叉樹
繪製二叉樹使用到了記錄形式的節點,程式碼如下:
digraph g {
node [shape="record", height=.1];
node0[label="<f0> |<f1> G|<f2>"];
node1[label="<f0> |<f1> E|<f2>"];
node2[label="<f0> |<f1> B|<f2>"];
node0:f0 -> node1:f1;
node0:f2 -> node2:f1;
}
|
其中,用|
隔開的串會在繪製出來的節點中展現為一條分隔符,用<>
括起來的串稱為錨點。
豎排記錄
記錄形式的節點也可以是豎形排列的。與橫向排列的記錄的不同只是label的形式不同,label中內容使用{}
包圍則是豎形排列的。程式碼如下:
digraph g {
node [shape="record"];
a [label="{a | b | c}"];
}
|
效果如下:
自定義複雜節點
label還支援HTML格式的,這樣你能想得到的大部分樣子的節點都可以被自定義出來。程式碼如下:
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>>];
}
|
效果如下:
直接指向cluster
邊直接指向cluster,需要設定compound
為true,並配合lhead
或ltail
來實現。程式碼如下:
digraph G {
compound=true;
subgraph cluster0 {
a;
}
subgraph cluster1 {
b;
}
a -> b [lhead=cluster1];
}
|
效果如下:
簡單的時序圖
簡單的時序圖程式碼如下:
digraph g {
rankdir="LR";
{
rank="same";
a0 -> a1 -> a2;
}
{
rank="same";
b0 -> b1 -> b2;
}
a1 -> b1;
}
|
其中,rankdir="LR"
表示,佈局從左L
到右R
,每一個rank="same"
的block中的所有節點都會在同一條線(橫線或豎線)上。
效果如下:
以圖片為節點
節點還可以使用圖片,通過在節點中使用image="image_path"
來設定圖片。不過需要注意的是,在使用圖片作為節點的時候,需要將本來的形狀設定為none
,並且將label
置為空字串,避免出現文字對圖片的干擾。