2016-4-25 Sublime Text + Graphviz + Dot = 有向圖.md

Graphviz介紹

介紹一個(gè)高效而簡(jiǎn)潔的繪圖工具graphviz。graphviz是貝爾實(shí)驗(yàn)室開發(fā)的一個(gè)開源的工具包戚丸,它使用一個(gè)特定的DSL(領(lǐng)域特定語言): dot作為腳本語言累澡,然后使用布局引擎來解析此腳本程帕,并完成自動(dòng)布局。graphviz提供豐富的導(dǎo)出格式绊诲,如常用的圖片格式,SVG褪贵,PDF格式等掂之。

graphviz中包含了眾多的布局器:

  • dot 默認(rèn)布局方式,主要用于有向圖
  • neato 基于spring-model(又稱force-based)算法
  • twopi 徑向布局
  • circo 圓環(huán)布局
  • fdp 用于無向圖

本文主要介紹dot有向圖脆丁。

首先世舰,在dot腳本中定義圖的頂點(diǎn)和邊,頂點(diǎn)和邊都具有各自的屬性槽卫,比如形狀跟压,顏色,填充模式晒夹,字體裆馒,樣式等。然后使用合適的布局算法進(jìn)行布局丐怯。布局算法除了繪制各個(gè)頂點(diǎn)和邊之外喷好,需要盡可能的將頂點(diǎn)均勻的分布在畫布上,并且盡可能的減少邊的交叉(如果交叉過多读跷,就很難看清楚頂點(diǎn)之間的關(guān)系了)梗搅。所以使用graphviz的一般流程為:

  1. 定義一個(gè)圖,并向圖中添加需要的頂點(diǎn)和邊
  2. 為頂點(diǎn)和邊添加樣式
  3. 使用布局引擎進(jìn)行繪制

在我的機(jī)器上效览,使用Sublime Text 編輯dot腳本无切,然后將F7/Cmd-B映射為調(diào)用dot引擎去繪制當(dāng)前腳本,并打開一個(gè)新的窗口來顯示運(yùn)行結(jié)果:

Sublime Text 3 集成Graphviz方法

如下:
第一步:下載https://github.com/munro/SublimeGraphvizPreview/archive/master.zip
第二步:打開Preferences -> Packages Settings-> Packages Control -> Settings User丐枉,來確認(rèn)一下installed_packages沒有GraphVizPreview哆键。并且增加"remove_orphaned": false防止Sublime Text 把手動(dòng)安裝的插件包給刪除了。

{
  "bootstrapped": true,
  "in_process_packages":
  [
  ],
  "installed_packages":
  [
  "EncodingHelper",
  "Package Control",
  "Theme - Spacegray"
  ],
  "remove_orphaned": false
}

第三步:打開Preferences -> Browse Packages...進(jìn)入到Sublime Text的插件包下Packagas瘦锹。
第四步:解壓zip文件到Packagas下籍嘹,并且更改文件夾SublimeGraphvizPreview-master為GraphVizPreview。
第五步:重啟Sublime Text弯院。

注:快捷鍵為Win+Shift+G辱士,調(diào)用Graphviz 調(diào)用dot引擎去繪制當(dāng)前腳本。

使用graphviz繪制流程圖

Paste_Image.png

注:引用image圖片的時(shí)候听绳,需要使用命令颂碘,
使用 dot 命令編譯,如

dot hello.dot -T png -o hello.png

完整的命令為:

<cmd> <inputfile> -T <format> -o <o(jì)utputfile>

示例如下:

D:\\>dot -Tjpg tes.dot -o test.jpg
<cmd> 介紹
dot 渲染的圖具有明確方向性椅挣。
neato 渲染的圖缺乏方向性头岔。
twopi 渲染的圖采用放射性布局塔拳。
circo 渲染的圖采用環(huán)型布局。
fdp 渲染的圖缺乏方向性峡竣。
sfdp 渲染大型的圖蝙斜,圖片缺乏方向性。

基礎(chǔ)知識(shí)

graphviz包含3中元素澎胡,圖孕荠,頂點(diǎn)和邊。每個(gè)元素都可以具有各自的屬性攻谁,用來定義字體稚伍,樣式,顏色戚宦,形狀等个曙。

第一個(gè)graphviz圖

digraph abc{
  a;
  b;
  c;
  d;
 
  a -> b;
  b -> d;
  c -> d;
}
Paste_Image.png

定義頂點(diǎn)和邊的樣式

digraph abc{
  node [shape="record"];
  edge [style="dashed"];
  a;
  b;
  c;
  d;
 
  a -> b;
  b -> d;
  c -> d;
}
Paste_Image.png

進(jìn)一步修改頂點(diǎn)和邊樣式

將頂點(diǎn)a的顏色改為淡綠色,并將c到d的邊改為紅色受楼。

digraph abc{
  node [shape="record"];
  edge [style="dashed"];
 
  a [style="filled", color="black", fillcolor="chartreuse"];
  b;
  c;
  d;
 
  a -> b;
  b -> d;
  c -> d [color="red"];
}
Paste_Image.png

子圖的繪制

digraph abc{
 
  node [shape="record"];
  edge [style="dashed"];
 
  a [style="filled", color="black", fillcolor="chartreuse"];
  b;
 
    subgraph cluster_cd{
      label="c and d";
      bgcolor="blue";
      c;
      d;
    }
 
  a -> b;
  b -> d;
  c -> d [color="red"];
}
Paste_Image.png

注:子圖的名稱必須以cluster開頭垦搬,否則graphviz無法設(shè)別。

數(shù)據(jù)結(jié)構(gòu)的可視化

一個(gè)hash表的數(shù)據(jù)結(jié)構(gòu)

hash表內(nèi)容

struct st_hash_type {
    int (*compare) ();
    int (*hash) ();
};
 
struct st_table_entry {
    unsigned int hash;
    char *key;
    char *record;
    st_table_entry *next;
};
 
struct st_table {
    struct st_hash_type *type;
    int num_bins;
/* slot count */
    int num_entries;
/* total number of entries */
    struct st_table_entry **bins;
/* slot */
};

腳本如下:

digraph st2{
  fontname = "Verdana";
  fontsize = 10;
  rankdir=TB;
 
  node [fontname = "Verdana", fontsize = 10, color="skyblue", shape="record"];
 
  edge [fontname = "Verdana", fontsize = 10, color="crimson", style="solid"];
 
  st_hash_type [label="{<head>st_hash_type|(*compare)|(*hash)}"];
  st_table_entry [label="{<head>st_table_entry|hash|key|record|<next>next}"];
  st_table [label="{st_table|<type>type|num_bins|num_entries|<bins>bins}"];
 
  st_table:bins -> st_table_entry:head;
  st_table:type -> st_hash_type:head;
  st_table_entry:next -> st_table_entry:head [style="dashed", color="forestgreen"];
}
Paste_Image.png

注:在頂點(diǎn)的形狀為record的時(shí)候艳汽,label屬性的語法比較奇怪猴贰,但是使用起來非常靈活。比如河狐,用豎線”|”隔開的串會(huì)在繪制出來的節(jié)點(diǎn)中展現(xiàn)為一條分隔符米绕。用<>括起來的串稱為錨點(diǎn),當(dāng)一個(gè)節(jié)點(diǎn)具有多個(gè)錨點(diǎn)的時(shí)候馋艺,這個(gè)特性會(huì)非常有用栅干,比如節(jié)點(diǎn)st_table的type屬性指向st_hash_type,第4個(gè)屬性指向st_table_entry等捐祠,都是通過錨點(diǎn)來實(shí)現(xiàn)的碱鳞。

使用默認(rèn)的dot布局后,綠色的這條邊覆蓋了數(shù)據(jù)結(jié)構(gòu)st_table_entry踱蛀,并不美觀窿给,因此可以使用別的布局方式來重新布局,如使用circo算法可以得到更加合理的布局結(jié)果星岗。

D:\\>circo -Tjpg tes.dot -o test.jpg
Paste_Image.png

hash表的實(shí)例

digraph st{
  fontname = "Verdana";
  fontsize = 10;
  rankdir = LR;
  rotate = 90;
 
  node [ shape="record", width=.1, height=.1];
  node [fontname = "Verdana", fontsize = 10, color="skyblue", shape="record"];
 
  edge [fontname = "Verdana", fontsize = 10, color="crimson", style="solid"];
  node [shape="plaintext"];
 
  st_table [label=<
      <table border="0" cellborder="1" cellspacing="0" align="left">
      <tr>
      <td>st_table</td>
      </tr>
      <tr>
      <td>num_bins=5</td>
      </tr>
      <tr>
      <td>num_entries=3</td>
      </tr>
      <tr>
      <td port="bins">bins</td>
      </tr>
      </table>
  >];
 
  node [shape="record"];
  num_bins [label=" <b1> | <b2> | <b3> | <b4> | <b5> ", height=2];
  node[ width=2 ];
 
  entry_1 [label="{<e>st_table_entry|<next>next}"];
  entry_2 [label="{<e>st_table_entry|<next>null}"];
  entry_3 [label="{<e>st_table_entry|<next>null}"];
 
  st_table:bins -> num_bins:b1;
  num_bins:b1 -> entry_1:e;
  entry_1:next -> entry_2:e;
  num_bins:b3 -> entry_3:e;
}
Paste_Image.png

注:LR指定了左右排序方式填大。
可以看到戒洼,節(jié)點(diǎn)的label屬性支持類似于HTML語言中的TABLE形式的定義俏橘,通過行列的數(shù)目來定義節(jié)點(diǎn)的形狀,從而使得節(jié)點(diǎn)的組成更加靈活圈浇。

軟件模塊組成圖

digraph idp_modules{
 
  rankdir = TB;
  fontname = "Microsoft YaHei";
  fontsize = 12;
 
  node [ fontname = "Microsoft YaHei", fontsize = 12, shape = "record" ];
  edge [ fontname = "Microsoft YaHei", fontsize = 12 ];
 
      subgraph cluster_sl{
          label="IDP支持層";
          bgcolor="mintcream";
          node [shape="Mrecord", color="skyblue", style="filled"];
          network_mgr [label="網(wǎng)絡(luò)管理器"];
          log_mgr [label="日志管理器"];
          module_mgr [label="模塊管理器"];
          conf_mgr [label="配置管理器"];
          db_mgr [label="數(shù)據(jù)庫管理器"];
      };
 
      subgraph cluster_md{
          label="可插拔模塊集";
          bgcolor="lightcyan";
          node [color="chartreuse2", style="filled"];
          mod_dev [label="開發(fā)支持模塊"];
          mod_dm [label="數(shù)據(jù)建模模塊"];
          mod_dp [label="部署發(fā)布模塊"];
      };
 
  mod_dp -> mod_dev [label="依賴..."];
  mod_dp -> mod_dm [label="依賴..."];
  mod_dp -> module_mgr [label="安裝...", color="yellowgreen", arrowhead="none"];
  mod_dev -> mod_dm [label="依賴..."];
  mod_dev -> module_mgr [label="安裝...", color="yellowgreen", arrowhead="none"];
  mod_dm -> module_mgr [label="安裝...", color="yellowgreen", arrowhead="none"];
}
Paste_Image.png

狀態(tài)圖

digraph automata_0 {
  size = "8.5, 11";
  fontname = "Microsoft YaHei";
  fontsize = 10;
 
  node [shape = circle, fontname = "Microsoft YaHei", fontsize = 10];
  edge [fontname = "Microsoft YaHei", fontsize = 10];
 
  0 [ style = filled, color=lightgrey ];
  2 [ shape = doublecircle ];
 
  0 -> 2 [ label = "a " ];
  0 -> 1 [ label = "other " ];
  1 -> 2 [ label = "a " ];
  1 -> 1 [ label = "other " ];
  2 -> 2 [ label = "a " ];
  2 -> 1 [ label = "other " ];
 
  "Machine: a" [ shape = plaintext ];
}
Paste_Image.png
digraph finite_state_machine {
  rankdir = LR;
  size = "8,5"
 
  node [shape = doublecircle];
 
  LR_0 LR_3 LR_4 LR_8;
 
  node [shape = circle];
 
  LR_0 -> LR_2 [ label = "SS(B)" ];
  LR_0 -> LR_1 [ label = "SS(S)" ];
  LR_1 -> LR_3 [ label = "S($end)" ];
  LR_2 -> LR_6 [ label = "SS(b)" ];
  LR_2 -> LR_5 [ label = "SS(a)" ];
  LR_2 -> LR_4 [ label = "S(A)" ];
  LR_5 -> LR_7 [ label = "S(b)" ];
  LR_5 -> LR_5 [ label = "S(a)" ];
  LR_6 -> LR_6 [ label = "S(b)" ];
  LR_6 -> LR_5 [ label = "S(a)" ];
  LR_7 -> LR_8 [ label = "S(b)" ];
  LR_7 -> LR_5 [ label = "S(a)" ];
  LR_8 -> LR_6 [ label = "S(b)" ];
  LR_8 -> LR_5 [ label = "S(a)" ];
}
Paste_Image.png

模塊的生命周期圖

digraph module_lc{
  rankdir=TB;
  fontname = "Microsoft YaHei";
  fontsize = 12;
 
  node [fontname = "Microsoft YaHei", fontsize = 12, shape = "Mrecord", color="skyblue", style="filled"];
  edge [fontname = "Microsoft YaHei", fontsize = 12, color="darkgreen" ];
 
  installed [label="已安裝狀態(tài)"];
  resolved [label="已就緒狀態(tài)"];
  uninstalled [label="已卸載狀態(tài)"];
  starting [label="正在啟動(dòng)"];
  active [label="已激活(運(yùn)行)狀態(tài)"];
  stopping [label="正在停止"];
  start [label="", shape="circle", width=0.5, fixedsize=true, style="filled", color="black"];
 
  start -> installed [label="安裝"];
  installed -> uninstalled [label="卸載"];
  installed -> resolved [label="準(zhǔn)備"];
  installed -> installed [label="更新"];
  resolved -> installed [label="更新"];
  resolved -> uninstalled [label="卸載"];
  resolved -> starting [label="啟動(dòng)"];
  starting -> active [label=""];
  active -> stopping [label="停止"];
  stopping -> resolved [label=""];
}
Paste_Image.png

簡(jiǎn)單的抽象語法樹

digraph ast{
  fontname = "Microsoft YaHei";
  fontsize = 10;
 
  node [shape = circle, fontname = "Microsoft YaHei", fontsize = 10];
  edge [fontname = "Microsoft YaHei", fontsize = 10];
  node [shape="plaintext"];
 
  mul [label="mul(*)"];
  add [label="add(+)"];
 
  add -> 3
  add -> 4;
  mul -> add;
  mul -> 5;
}
Paste_Image.png

簡(jiǎn)單的UML類圖

digraph G{
 
  fontname = "Courier New"
  fontsize = 10
 
  node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
  edge [ fontname = "Courier New", fontsize = 10 ];
 
  Animal [ label = "{Animal |+ name : String\\l+ age : int\\l|+ die() : void\\l}" ];
 
      subgraph clusterAnimalImpl{
          bgcolor="yellow"
          Dog [ label = "{Dog||+ bark() : void\\l}" ];
          Cat [ label = "{Cat||+ meow() : void\\l}" ];
      };
 
  edge [ arrowhead = "empty" ];
 
  Dog->Animal;
  Cat->Animal;
  Dog->Cat [arrowhead="none", label="0..*"];
}
Paste_Image.png

時(shí)序圖

digraph G {
    rankdir="LR";
    node[shape="point", width=0, height=0];
    edge[arrowhead="none", style="dashed"]
 
    {
        rank="same";
        edge[style="solided"];
        LC[shape="plaintext"];
        LC -> step00 -> step01 -> step02 -> step03 -> step04 -> step05;
    }
 
    {
        rank="same";
        edge[style="solided"];
        Agency[shape="plaintext"];
        Agency -> step10 -> step11 -> step12 -> step13 -> step14 -> step15;
    }
 
    {
        rank="same";
        edge[style="solided"];
        Agent[shape="plaintext"];
        Agent -> step20 -> step21 -> step22 -> step23 -> step24 -> step25;
    }
 
    step00 -> step10 [label="sends email new custumer", arrowhead="normal"];
    step11 -> step01 [label="declines", arrowhead="normal"];
    step12 -> step02 [label="accepts", arrowhead="normal"];
    step13 -> step23 [label="forward to", arrowhead="normal"];
    step24 -> step14;
    step14 -> step04 [arrowhead="normal"];
}

rankdir=”LR”表示寥掐,布局從左L到右R靴寂。可以看到召耘,在代碼中有{}括起來的部分百炬。

{
    rank="same";
    edge[style="solided"];
    Agency[shape="plaintext"];
    Agency -> step10 -> step11 -> step12 -> step13 -> step14 -> step15;
}

每一個(gè)rank=”same”的block中的所有節(jié)點(diǎn)都會(huì)在同一條線上。我們?cè)O(shè)置了所有的線為虛線污它,但是在該block中剖踊,將線改為solided。

Paste_Image.png

如果你追求高效的開發(fā)速度衫贬,并希望快速的將自己的想法畫出來德澈,那么graphviz是一個(gè)很不錯(cuò)的選擇。
graphviz的強(qiáng)項(xiàng)在于自動(dòng)布局固惯,當(dāng)圖中的頂點(diǎn)和邊的數(shù)目變得很多的時(shí)候梆造,才能很好的體會(huì)這一特性的好處。

最后葬毫,提供Graphviz下載地址镇辉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市贴捡,隨后出現(xiàn)的幾起案子忽肛,更是在濱河造成了極大的恐慌,老刑警劉巖烂斋,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麻裁,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡源祈,警方通過查閱死者的電腦和手機(jī)煎源,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來香缺,“玉大人手销,你說我怎么就攤上這事⊥颊牛” “怎么了锋拖?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)祸轮。 經(jīng)常有香客問我兽埃,道長(zhǎng),這世上最難降的妖魔是什么适袜? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任柄错,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘售貌。我一直安慰自己给猾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布颂跨。 她就那樣靜靜地躺著敢伸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恒削。 梳的紋絲不亂的頭發(fā)上池颈,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音钓丰,去河邊找鬼饶辙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛斑粱,可吹牛的內(nèi)容都是我干的弃揽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼则北,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼矿微!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起尚揣,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤涌矢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后快骗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娜庇,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年方篮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了名秀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡藕溅,死狀恐怖匕得,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情巾表,我是刑警寧澤汁掠,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站集币,受9級(jí)特大地震影響考阱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鞠苟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一乞榨、第九天 我趴在偏房一處隱蔽的房頂上張望秽之。 院中可真熱鬧,春花似錦姜凄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扼鞋,卻和暖如春申鱼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背云头。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工捐友, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溃槐。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓匣砖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親昏滴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子猴鲫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容