1. 程式人生 > >使用Graphviz繪製流程圖和關係圖

使用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-dotgraphviz-preview

使用Atom來編寫和預覽圖片,最後使用gvedit來匯出圖片。看起來還不錯的樣子。

  • windows中安裝好graphviz之後,最好配置一下PATH環境變數。
  • Atom的language-dot外掛中的程式碼提示模板(snippet)可能不能滿足你的需求,不過你可以自己新增和修改。這裡有我自己修改的程式碼模板。

中文亂碼解決

若渲染出的圖片中出現亂碼,檢查兩項:

  1. 檔案編碼需要使用utf-8。

  2. 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. 配合lheadltail使用

常用節點屬性如下:

屬性名稱 預設值 含義
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};
}

圖片效果:

simple_demo

高階用法

繪製二叉樹

繪製二叉樹使用到了記錄形式的節點,程式碼如下:

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;
}

其中,用|隔開的串會在繪製出來的節點中展現為一條分隔符,用<>括起來的串稱為錨點。

效果如下:
binary_tree

豎排記錄

記錄形式的節點也可以是豎形排列的。與橫向排列的記錄的不同只是label的形式不同,label中內容使用{}包圍則是豎形排列的。程式碼如下:

digraph g {
    node [shape="record"];
    a [label="{a | b | c}"];
}

效果如下:

col_record

自定義複雜節點

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>>];
}

效果如下:

custom_node

直接指向cluster

邊直接指向cluster,需要設定compound為true,並配合lheadltail來實現。程式碼如下:

digraph G {
    compound=true;
    subgraph cluster0 {
        a;
    }
    subgraph cluster1 {
        b;
    }
    a -> b [lhead=cluster1];
}

效果如下:

point_to_cluster

簡單的時序圖

簡單的時序圖程式碼如下:

digraph g {
    rankdir="LR";
    {
        rank="same";
        a0 -> a1 -> a2;
    }
    {
        rank="same";
        b0 -> b1 -> b2;
    }
    a1 -> b1;
}

其中,rankdir="LR"表示,佈局從左L到右R,每一個rank="same"的block中的所有節點都會在同一條線(橫線或豎線)上。

效果如下:

sequence

以圖片為節點

節點還可以使用圖片,通過在節點中使用image="image_path"來設定圖片。不過需要注意的是,在使用圖片作為節點的時候,需要將本來的形狀設定為none,並且將label置為空字串,避免出現文字對圖片的干擾。

Graphviz程式設計庫