日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Graphviz-Gdot语言学习

發布時間:2024/9/5 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Graphviz-Gdot语言学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

GVEdit這個繪圖軟件呢我也是剛接觸的,感覺畫起圖來還是很爽的。。。尤其很熟悉c++后很容易上手這門dot語言。

先看一下十分清新的編程界面:

沒有天下最邪惡的語法加亮,沒有縮進行。。。這又算什么!我們可是有編譯環境的,像這樣。。。

所以呢如果不是很習慣它的編程環境自己開一個c++就挺好的。。。(在線的很支持coding.net)

注意,這個編譯環境語法不是準確性語法,也就是說你輸入的無效字符會自動忽略而不是報一大堆錯。。。其實感覺上還是很爽呢!

當然了,一些關鍵性語法還是會報錯的啦。。。(比如像主函數不寫這樣的。。)

編譯命令是F5,生成命令是加上shift

好啦,熟悉了編譯環境后,讓我們開始Gdot之旅吧(好吧我管這門語言叫做Gdot)

?

基本語句

前面也提到了Gdot這門語言實在是一種非常簡單的描述性語言。如果有其他語言的一定基礎再看一兩個例子就能很輕松的上手。

我覺得似乎還是跟c比較像?(霧

首先,Gdot非強制面向對象(這不廢話嗎?怎么可能?),它有一個主函數像這樣:

digraph G{}

G是自己命名的,比如我還可以:

digraph HelloWolrd{}

我們在里面寫圖即可了。

?

首先讓我們畫一個a->b

digraph G{a->b; }

可以看到,只是a->b;這一條語句我們就畫出了一個a到b的流程圖。。。(這在畫圖里需要很久啊。。。。)

哦順便提一句:Gdot句尾是不需要分號的,作為一名c_er我很手賤。。。

事實上,如果一切按照默認設置,我們將畫出一個內容為a的橢圓形用黑色實線箭頭指向另一個內容為b的橢圓形,就是這樣。

似乎很簡單的樣子,我們畫一個自動機好了:

digraph G{s->s;s->a;s->b;s->c;a->a;b->c;c->d;d->d;a->e;e->d; }

恩恩還是很不錯的。順便提一句,Graphviz強大之處就在于它的隨機布局上面,面對大量的結構它可以做得很好看(而對于畫圖似乎只能靠人手?)

但是這樣看起來很單調對不對?不急,我們給它裝飾一下,比如顏色,請注意這個語法:

digraph G{s->s;s[color=blue];s->a;a[color=red];s->b;s->c;a->a;b->c;c->d;d->d;a->e;e->d; }

在對應變量的后面注上中括號[]可以叫做修飾語句,中括號內的語句起到修飾的作用。

對于上面那個例子,我們在s和a的修飾框內注上了顏色,它們的外框顏色就如愿以償了。

那我想要填充顏色呢?也好說:

digraph G{s->s;s[style="filled",fillcolor=green];s->a;a[style="filled"];s->b;s->c;a->a;b->c;c->d;d->d;a->e;e->d; }

語句似乎有了一些不同,注意到我們修飾了它的狀態:fill,意味著是填充狀態,也就是我們選中了它的填充面積。那么對于a,可以看到它的填充面積變成了灰色標出。而對于s,由于我們聲明了它的填充顏色fillcolor=green它就變成綠色的了。

對于框線的顏色修飾,我們可以這么寫:

digraph G{s->s;s[style="filled",fillcolor=green,color=blue];s->a;a[style="filled"];s->b;b[color=blue]s->c;a->a;b->c;c->d;d->d;a->e;e->d; }

在修飾框里只要寫上color=...就好了,注意到b的顏色變化,也就是說color是不需要狀態filled的,而fillcolor是需要狀態filled的,看下面的例子。

digraph G{a;b;a[style="filled",color=blue,fillcolor=purple];b[color=blue,fillcolor=purple]; }

狀態為filled的a獲得了fillcolor的命令,而b則沒有。

當然了,如果我們有好多個對象想要都賦成紅色我們還每個都加上修飾框嗎?當然不是了,我們有一個叫做全局修飾的神奇的東東:

digraph G{node[style="filled",fillcolor="red"];a;b;c; }

可以看到,當我們設置了一個全局修飾node后所有的點都設置成了同一個顏色。

當然了,如果要對其中的一個進行修改直接加修飾框覆蓋掉全局修飾即可:

digraph G{node[style="filled",fillcolor="red"];a;b;c;d[style="null",color=blue]; }

注意,一個style如果僅僅是想要覆蓋我想怎么編就怎么編,真的不一定是null。。。

當然了,沒有覆蓋到的則會保留原有的全局修飾:

digraph G{node[style="filled",fillcolor="red"];a;b;c;d[color=blue]; }

那么顏色大概就是這樣了,我們可以看一下它的形狀,都是橢圓形其實很丑的。。。。

?比如說呢,矩形?

digraph G{a[shape="box",style="filled",fillcolor="red"]; }

只要在修飾框中修飾shape=box就好了,似乎好簡單。。。(其實應該寫record的我懶。。。shape的默認值應該就是矩形)

當然了,我們還可以讓它變得奇怪一點:

digraph G{a[shape="record",style="dashed"]; }

style=dashed就修飾了它的框框變成虛的,但是貌似就不能再filled了。。。(當然了,虛框你怎么fill啊。。。)

不過呢我們還是可以修飾它的線的顏色的,像這樣:

digraph G{a[shape="record",style="dashed",color="purple"]; }

然后我突然發現我后面寫的東西都丟了媽呀,瞬間就不想再寫了= =(博客園的編輯器實在需要改進= =)

之后就是一些數據結構之類的東西了,感興趣可以看看這些大神的,寫的都比我好= =:

http://www.cnblogs.com/sld666666/archive/2010/06/25/1765510.html

http://www.cnblogs.com/CoolJie/archive/2012/07/17/graphviz.html

事實上graphviz的子圖以及結構師最重要的組成部分了,那我轉一點來彌補這個遺漏吧,以下【轉】:

子圖的繪制

graphviz支持子圖,即圖中的部分節點和邊相對對立(軟件的模塊劃分經常如此)。比如,我們可以將頂點c和d歸為一個子圖:

1: digraph abc{

?

2:?

?

3: node [shape="record"];

?

4: edge [style="dashed"];

?

5:?

?

6: a [style="filled", color="black", fillcolor="chartreuse"];

?

7: b;

?

8:?

?

9: subgraph cluster_cd{

?

10: label="c and d";

?

11: bgcolor="mintcream";

?

12: c;

?

13: d;

?

14: }

?

15:?

?

16: a -> b;

?

17: b -> d;

?

18: c -> d [color="red"];

?

19: }

?

將c和d劃分到cluster_cd這個子圖中,標簽為”c and d”,并添加背景色,以方便與主圖區分開,繪制結果如下:

應該注意的是,子圖的名稱必須以cluster開頭,否則graphviz無法設別。

數據結構的可視化

實際開發中,經常要用到的是對復雜數據結構的描述,graphviz提供完善的機制來繪制此類圖形。

一個hash表的數據結構

比如一個hash表的內容,可能具有下列結構:

1: struct st_hash_type {

?

2: int (*compare) ();

?

3: int (*hash) ();

?

4: };

?

5:?

?

6: struct st_table_entry {

?

7: unsigned int hash;

?

8: char *key;

?

9: char *record;

?

10: st_table_entry *next;

?

11: };

?

12:?

?

13: struct st_table {

?

14: struct st_hash_type *type;

?

15: int num_bins; /* slot count */

?

16: int num_entries; /* total number of entries */

?

17: struct st_table_entry **bins; /* slot */

?

18: };

?

繪制hash表的數據結構

從代碼上看,由于結構體存在引用關系,不夠清晰,如果層次較多,則很難以記住各個結構之間的關系,我們可以通過下圖來更清楚的展示:

腳本如下:

1: digraph st2{

?

2: fontname = "Verdana";

?

3: fontsize = 10;

?

4: rankdir=TB;

?

5:?

?

6: node [fontname = "Verdana", fontsize = 10, color="skyblue", shape="record"];

?

7:?

?

8: edge [fontname = "Verdana", fontsize = 10, color="crimson", style="solid"];

?

9:?

?

10: st_hash_type [label="{<head>st_hash_type|(*compare)|(*hash)}"];

?

11: st_table_entry [label="{<head>st_table_entry|hash|key|record|<next>next}"];

?

12: st_table [label="{st_table|<type>type|num_bins|num_entries|<bins>bins}"];

?

13:?

?

14: st_table:bins -> st_table_entry:head;

?

15: st_table:type -> st_hash_type:head;

?

16: st_table_entry:next -> st_table_entry:head [style="dashed", color="forestgreen"];

?

17: }

?

應該注意到,在頂點的形狀為”record”的時候,label屬性的語法比較奇怪,但是使用起來非常靈活。比如,用豎線”|”隔開的串會在繪制出來的節點中展現為一條分隔符。用”<>”括起來的串稱為錨點,當一個節點具有多個錨點的時候,這個特性會非常有用,比如節點st_table的type屬性指向st_hash_type,第4個屬性指向st_table_entry等,都是通過錨點來實現的。

我們發現,使用默認的dot布局后,綠色的這條邊覆蓋了數據結構st_table_entry,并不美觀,因此可以使用別的布局方式來重新布局,如使用circo算法:

則可以得到更加合理的布局結果。

hash表的實例

另外,這個hash表的一個實例如下:

腳本如下:

1: digraph st{

?

2:?

?

3: fontname = "Verdana";

?

4: fontsize = 10;

?

5: rankdir = LR;

?

6: rotate = 90;

?

7:?

?

8: node [ shape="record", width=.1, height=.1];

?

9: node [fontname = "Verdana", fontsize = 10, color="skyblue", shape="record"];

?

10:?

?

11: edge [fontname = "Verdana", fontsize = 10, color="crimson", style="solid"];

?

12: node [shape="plaintext"];

?

13:?

?

14: st_table [label=<

?

15: <table border="0" cellborder="1" cellspacing="0" align="left">

?

16: <tr>

?

17: <td>st_table</td>

?

18: </tr>

?

19: <tr>

?

20: <td>num_bins=5</td>

?

21: </tr>

?

22: <tr>

?

23: <td>num_entries=3</td>

?

24: </tr>

?

25: <tr>

?

26: <td port="bins">bins</td>

?

27: </tr>

?

28: </table>

?

29: >];

?

30:?

?

31: node [shape="record"];

?

32: num_bins [label=" <b1> | <b2> | <b3> | <b4> | <b5> ", height=2];

?

33: node[ width=2 ];

?

34:?

?

35: entry_1 [label="{<e>st_table_entry|<next>next}"];

?

36: entry_2 [label="{<e>st_table_entry|<next>null}"];

?

37: entry_3 [label="{<e>st_table_entry|<next>null}"];

?

38:?

?

39: st_table:bins -> num_bins:b1;

?

40: num_bins:b1 -> entry_1:e;

?

41: entry_1:next -> entry_2:e;

?

42: num_bins:b3 -> entry_3:e;

?

43:?

?

44: }

?

上例中可以看到,節點的label屬性支持類似于HTML語言中的TABLE形式的定義,通過行列的數目來定義節點的形狀,從而使得節點的組成更加靈活。

軟件模塊組成圖

Apache httpd模塊關系

IDPV2后臺的模塊組成關系

在實際的開發中,隨著系統功能的完善,軟件整體的結構會越來越復雜,通常開發人員會將軟件劃分為可理解的多個子模塊,各個子模塊通過協作,完成各種各樣的需求。

下面有個例子,是在IDPV2設計時的一個草稿:

IDP支持層為一個相對獨立的子系統,其中包括如數據庫管理器,配置信息管理器等模塊,另外為了提供更大的靈活性,將很多其他的模塊抽取出來作為外部模塊,而支持層提供一個模塊管理器,來負責加載/卸載這些外部的模塊集合。

這些模塊間的關系較為復雜,并且有部分模塊關系密切,應歸類為一個子系統中,上圖對應的dot腳本為:

1: digraph idp_modules{

?

2:?

?

3: rankdir = TB;

?

4: fontname = "Microsoft YaHei";

?

5: fontsize = 12;

?

6:?

?

7: node [ fontname = "Microsoft YaHei", fontsize = 12, shape = "record" ];

?

8: edge [ fontname = "Microsoft YaHei", fontsize = 12 ];

?

9:?

?

10: subgraph cluster_sl{

?

11: label="IDP支持層";

?

12: bgcolor="mintcream";

?

13: node [shape="Mrecord", color="skyblue", style="filled"];

?

14: network_mgr [label="網絡管理器"];

?

15: log_mgr [label="日志管理器"];

?

16: module_mgr [label="模塊管理器"];

?

17: conf_mgr [label="配置管理器"];

?

18: db_mgr [label="數據庫管理器"];

?

19: };

?

20:?

?

21: subgraph cluster_md{

?

22: label="可插拔模塊集";

?

23: bgcolor="lightcyan";

?

24: node [color="chartreuse2", style="filled"];

?

25: mod_dev [label="開發支持模塊"];

?

26: mod_dm [label="數據建模模塊"];

?

27: mod_dp [label="部署發布模塊"];

?

28: };

?

29:?

?

30: mod_dp -> mod_dev [label="依賴..."];

?

31: mod_dp -> mod_dm [label="依賴..."];

?

32: mod_dp -> module_mgr [label="安裝...", color="yellowgreen", arrowhead="none"];

?

33: mod_dev -> mod_dm [label="依賴..."];

?

34: mod_dev -> module_mgr [label="安裝...", color="yellowgreen", arrowhead="none"];

?

35: mod_dm -> module_mgr [label="安裝...", color="yellowgreen", arrowhead="none"];

?

36:?

?

37: }

?

38:?

?

狀態圖

有限自動機示意圖

上圖是一個簡易有限自動機,接受a及a結尾的任意長度的串。其腳本定義如下:

1: digraph automata_0 {

?

2:?

?

3: size = "8.5, 11";

?

4: fontname = "Microsoft YaHei";

?

5: fontsize = 10;

?

6:?

?

7: node [shape = circle, fontname = "Microsoft YaHei", fontsize = 10];

?

8: edge [fontname = "Microsoft YaHei", fontsize = 10];

?

9:?

?

10: 0 [ style = filled, color=lightgrey ];

?

11: 2 [ shape = doublecircle ];

?

12:?

?

13: 0 -> 2 [ label = "a " ];

?

14: 0 -> 1 [ label = "other " ];

?

15: 1 -> 2 [ label = "a " ];

?

16: 1 -> 1 [ label = "other " ];

?

17: 2 -> 2 [ label = "a " ];

?

18: 2 -> 1 [ label = "other " ];

?

19:?

?

20: "Machine: a" [ shape = plaintext ];

?

21: }

?

形狀值為plaintext的表示不用繪制邊框,僅展示純文本內容,這個在繪圖中,繪制指示性的文本時很有用,如上圖中的”Machine: a”。

OSGi中模塊的生命周期圖

OSGi中,模塊具有生命周期,從安裝到卸載,可能的狀態具有已安裝,已就緒,正在啟動,已啟動,正在停止,已卸載等。如下圖所示:

對應的腳本如下:

1: digraph module_lc{

?

2:?

?

3: rankdir=TB;

?

4: fontname = "Microsoft YaHei";

?

5: fontsize = 12;

?

6:?

?

7: node [fontname = "Microsoft YaHei", fontsize = 12, shape = "Mrecord", color="skyblue", style="filled"];

?

8: edge [fontname = "Microsoft YaHei", fontsize = 12, color="darkgreen" ];

?

9:?

?

10: installed [label="已安裝狀態"];

?

11: resolved [label="已就緒狀態"];

?

12: uninstalled [label="已卸載狀態"];

?

13: starting [label="正在啟動"];

?

14: active [label="已激活(運行)狀態"];

?

15: stopping [label="正在停止"];

?

16: start [label="", shape="circle", width=0.5, fixedsize=true, style="filled", color="black"];

?

17:?

?

18: start -> installed [label="安裝"];

?

19: installed -> uninstalled [label="卸載"];

?

20: installed -> resolved [label="準備"];

?

21: installed -> installed [label="更新"];

?

22: resolved -> installed [label="更新"];

?

23: resolved -> uninstalled [label="卸載"];

?

24: resolved -> starting [label="啟動"];

?

25: starting -> active [label=""];

?

26: active -> stopping [label="停止"];

?

27: stopping -> resolved [label=""];

?

28:?

?

29: }

?

其他實例

一棵簡單的抽象語法樹(AST)

表達式 (3+4)*5 在編譯時期,會形成一棵語法樹,一邊在計算時,先計算3+4的值,最后與5相乘。

對應的腳本如下:

1: digraph ast{

?

2: fontname = "Microsoft YaHei";

?

3: fontsize = 10;

?

4:?

?

5: node [shape = circle, fontname = "Microsoft YaHei", fontsize = 10];

?

6: edge [fontname = "Microsoft YaHei", fontsize = 10];

?

7: node [shape="plaintext"];

?

8:?

?

9: mul [label="mul(*)"];

?

10: add [label="add(+)"];

?

11:?

?

12: add -> 3

?

13: add -> 4;

?

14: mul -> add;

?

15: mul -> 5;

?

16: }

?

17:?

?

簡單的UML類圖

下面是一簡單的UML類圖,Dog和Cat都是Animal的子類,Dog和Cat同屬一個包,且有可能有聯系(0..n)。

腳本:

1: digraph G{

?

2:?

?

3: fontname = "Courier New"

?

4: fontsize = 10

?

5:?

?

6: node [ fontname = "Courier New", fontsize = 10, shape = "record" ];

?

7: edge [ fontname = "Courier New", fontsize = 10 ];

?

8:?

?

9: Animal [ label = "{Animal |+ name : Stringl+ age : intl|+ die() : voidl}" ];

?

10:?

?

11: subgraph clusterAnimalImpl{

?

12: bgcolor="yellow"

?

13: Dog [ label = "{Dog||+ bark() : voidl}" ];

?

14: Cat [ label = "{Cat||+ meow() : voidl}" ];

?

15: };

?

16:?

?

17: edge [ arrowhead = "empty" ];

?

18:?

?

19: Dog->Animal;

?

20: Cat->Animal;

?

21: Dog->Cat [arrowhead="none", label="0..*"];

?

22: }

?

狀態圖

腳本:

1: digraph finite_state_machine {

?

2:?

?

3: rankdir = LR;

?

4: size = "8,5"

?

5:?

?

6: node [shape = doublecircle];

?

7:?

?

8: LR_0 LR_3 LR_4 LR_8;

?

9:?

?

10: node [shape = circle];

?

11:?

?

12: LR_0 -> LR_2 [ label = "SS(B)" ];

?

13: LR_0 -> LR_1 [ label = "SS(S)" ];

?

14: LR_1 -> LR_3 [ label = "S($end)" ];

?

15: LR_2 -> LR_6 [ label = "SS(b)" ];

?

16: LR_2 -> LR_5 [ label = "SS(a)" ];

?

17: LR_2 -> LR_4 [ label = "S(A)" ];

?

18: LR_5 -> LR_7 [ label = "S(b)" ];

?

19: LR_5 -> LR_5 [ label = "S(a)" ];

?

20: LR_6 -> LR_6 [ label = "S(b)" ];

?

21: LR_6 -> LR_5 [ label = "S(a)" ];

?

22: LR_7 -> LR_8 [ label = "S(b)" ];

?

23: LR_7 -> LR_5 [ label = "S(a)" ];

?

24: LR_8 -> LR_6 [ label = "S(b)" ];

?

25: LR_8 -> LR_5 [ label = "S(a)" ];

?

26:?

?

27: }

?

附錄

事實上,從dot的語法及上述的示例中,很容易看出,dot腳本很容易被其他語言生成。比如,使用一些簡單的數據庫查詢就可以生成數據庫中的ER圖的dot腳本。

如果你追求高效的開發速度,并希望快速的將自己的想法出來,那么graphviz是一個很不錯的選擇。

當然,graphviz也有一定的局限,比如繪制時序圖(序列圖)就很難實現。graphviz的節點出現在畫布上的位置事實上是不確定的,依賴于所使用的布局算法,而不是在腳本中出現的位置,這可能使剛開始接觸graphviz的開發人員有點不適應。graphviz的強項在于自動布局,當圖中的頂點和邊的數目變得很多的時候,才能很好的體會這一特性的好處:

比如上圖,或者較上圖更復雜的圖,如果采用手工繪制顯然是不可能的,只能通過graphviz提供的自動布局引擎來完成。如果僅用于展示模塊間的關系,子模塊與子模塊間通信的方式,模塊的邏輯位置等,graphviz完全可以勝任,但是如果圖中對象的物理位置必須是準確的,如節點A必須位于左上角,節點B必須與A相鄰等特性,使用graphviz則很難做到。畢竟,它的強項是自動布局,事實上,所有的節點對與布局引擎而言,權重在初始時都是相同的,只是在渲染之后,節點的大小,形狀等特性才會影響權重。

本文只是初步介紹了graphviz的簡單應用,如圖的定義,頂點/邊的屬性定義,如果運行等,事實上還有很多的屬性,如畫布的大小,字體的選擇,顏色列表等,大家可以通過graphviz的官網來找到更詳細的資料。

?

graphviz真的是一個很好用的東西,希望大家喜歡。

轉載于:https://www.cnblogs.com/chxer/p/4561629.html

總結

以上是生活随笔為你收集整理的Graphviz-Gdot语言学习的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。