Graphviz工具

来源:互联网 发布:骑马动作数据 编辑:程序博客网 时间:2024/05/16 15:58

工欲善其事,必先利其器。Graphviz是图形可视化工具,doxygen等工具的重要基石,如果想摆脱visio工具的束缚,想更高效的画出各种时序图,流程图、状态图等等,可以尝试使用Graphviz,特别是doxygen工具,可以帮助你通过代码注释输出可视化的文档。本章主要介绍Graphviz工具。


Graphviz入门

简介

        Graphviz (Graph visualization)缩写,即图形可视化的工具,是贝尔实验室开源的一款工具。主要用途可以将特定语言(DSL)编写的脚本进行可视化输出,支持JPEG,PDF等多种输出样式。并且其是跨平台非常好,已经支持Linux, MAC, Window多平台,二进制安装方式提供fedora, ubuntu,rhel, solaris, macos, windows等系统。

        Graphviz拥有多种布局方式,默认才用Dot布局方式。
1)dot -  默认布局方式,主要用于向图。
2)neato - "spring model'' layouts。
3)  fdp,sfdp - 用于无向图。
3)twopi -  径向布局。
4)circo  - 环行布局。

      Graphviz的官网,里面有更为详细的介绍和文档。

安装

     安装方式可以选择源码方式安装或者直接使用安装包方式进行,我这里使用的二进制方式安装,MAC系统下载地址,通过可以地址可以找到其他平台安装方式。MAC下直接下载pkg文件进行安装。

傻瓜式下一步即可。
     Graphviz安装

安装完成打开Graphviz
Graphviz使用
Graphviz使用



测试

编写一个脚本如下,命名为test.dot
digraph test1{a;b;c;d;a -> b;b -> d;c -> d;}

使用Graphviz->File->Open,(或花o-快捷键)打开test.dot文件
Graphviz使用

可以使用Graphviz->File->Export进行输出,可以保存你想要的格式。


应用

     上面使用Graphviz一个简单的演示让我们了解到Graphviz工具的主要用途,可以使用脚本化的方式来输出可视化的图形界面,能够快速的进行思维的图形化,我们想把我们所思考的东西进行图形化表达,可以借助Graphviz。比如我们想画出一个函数的调用关系,或者类的继承、组合图等等。
     
      现在有很大强大的工具都在使用Graphviz作为图形化基础来实现其界面展示。后续有机会对下面的几款工具进行介绍。

Doxygen - 一款可以将注释文档化的工具,能够输出CHM, HTML等多种格式的文档。

Valgrind -  一款内存泄露,内存越界等检查工具,能够输出图形化的内存异常报表。


Graphviz使用 

有向图

上一节测试部分已经演示最简单的有向图的使用,Dot语法还提供修改图形的各种属性,下面一一进行介绍。
属性也分为作用域,如果是全局作用于,则对所有节点生效,也可以是只对某个节点生效。我们来演示一个使用矩形、虚线的例子。
digraph test2{node [shape="box"];edge [style="dashed"];a [shape="ellipse"];b  [style="filled", color="green"];c;d;a -> b [color="red"];b -> d [style=bold,label="b to d"];c -> d;}

Graphviz_有向图1
node,edge 作用域是全局的,全局的基调是“形状是矩形,连线是虚线”
a节点的形状是椭圆形
b节点风格是使用绿色填充
a到b的连线颜色使用红色
b到d的连线使用实心连线,并且携带注释"b to d"


下面演示一个子图绘制,我们将c和d节点定义为一个子图。
digraph test3{a;b;subgraph cluster_cd{    label="c and d";    bgcolor="mintcream";    c [shape = "polygon",sides=5];    d;    }a -> b;b -> d [color = "red"];c -> d [style="dashed" color = "green"];}
Graphviz有向图2

使用subgraph关键字定义子图,并且子图保证使用cluster前缀作为子图名。


数据结构图

我们举例来描述一个hash表的数据结构,数据结构C代码如下:

struct hash_entry {int hashcode;char *key;char *value;hash_entry *next;};struct hash_oper {int (*compare)(int op1, int op2);   //hash比较方法int (*hash)();      //hash值计算方法};struct  hash_table {int  slots;    //槽总数int   count; //数据总数struct      hash_oper  *oper;  //hash操作封装struct hash_entry **entries; //槽数组,每个槽是一个链表};


使用Graphviz展示的效果如下图:

Grapviz数据结构

使用如下脚本可以输出该图:

digraph test4 {rankdir = TB;node [fontname = "Verdana", fontsize = 10, color="skyblue", shape="record"];edge [fontname = "Verdana", fontsize = 10, color="crimson", style="solid"]; hash_oper  [label="{<head>hash_oper|int (*compare)|int (*hash)}"];hash_entry [label="{<head>hash_entry|hashcode|key|value|<next>next}"];hash_table [label="{hash_table|slots|count|<oper>oper|<entries>entries}"];hash_table:entries -> hash_entry:head;hash_entry:next -> hash_entry:head [style="dashed" color="green"];hash_table:oper -> hash_oper:head;}
数据结构图的连线主要使用尖括号<xx>实现,使用<>可以定义一个leble,然后使用lable实现表格之间的连线。


上面是使用dot布局方式,我们可以使用circo布局方式实现哈希表数据机构,代码如下:

digraph test5 {rankdir = LR;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"];hash_table [label=<<table border="0" cellborder="1" cellspacing="0" align="left"><tr><td>hash_table</td></tr><tr><td>slots=4</td></tr><tr><td>count</td></tr><tr><td>oper</td></tr><tr><td>entries</td></tr></table>>];node [shape="record"];num_entry [label="<b1> | <b2> | <b3> | <b4>", height=2];entry_1 [label="{<e>hash_entry|<next>next}"];entry_2 [label="<e>hash_entry|<next>null"];entry_3 [label="<e>hash_entry|<next>null"];hash_table:entries ->num_entry:b1;num_entry:b1->entry_1:e;entry_1:next->entry_2:e;num_entry:b3->entry_3:3;}

和dot布局方式一样,<>也是可以用来做标签的,可以使用<table>类似HTML的方式进行格式调整。可视化后得到下图:

Graphviz表格


我们再画一个二叉树的数据结构图,代码如下:

digraph test6 {node [shape = record,height=.1];node0[label = "<f0> |<f1> G|<f2> "];node1[label = "<f0> |<f1> E|<f2> "];node2[label = "<f0> |<f1> B|<f2> "];node3[label = "<f0> |<f1> F|<f2> "];node4[label = "<f0> |<f1> R|<f2> "];node5[label = "<f0> |<f1> H|<f2> "];node6[label = "<f0> |<f1> Y|<f2> "];node7[label = "<f0> |<f1> A|<f2> "];node8[label = "<f0> |<f1> C|<f2> "];"node0":f2 -> "node4":f1;"node0":f0 -> "node1":f1;"node1":f0 -> "node2":f1;"node1":f2 -> "node3":f1;"node2":f2 -> "node8":f1;"node2":f0 -> "node7":f1;"node4":f2 -> "node6":f1;"node4":f0 -> "node5":f1;}

二叉树


UML图

状态图

我用一个Bug系统的状态图为例,演示下状态图。
digraph test7 {rankdir = LR;node [fontsize = 12, shape = "Mrecord", color="skyblue", style="filled"]; edge [fontsize = 12, color="darkgreen" ];created [label="created"];review [label="review"];assign  [label="assign"];assigned [label="assigned"];verify  [label="verify"];closed [label="closed"];start [label="", shape="circle", width=0.5, fixedsize=true, style="filled", color="black"];start -> created[label="创建"];created -> review [label="提交"];review -> assign [label="通过"];review -> created [label ="拒绝"];assign -> assigned [label="分配"];assigned-> verify [label="解决"];assigned-> closed [label="直接关闭"];verify -> closed [label="验证通过"];verify -> assigned [label="未解决"];}

状态图


类图

我用一个形状的类图来进行演示,代码如下:
digraph test8{ fontname = "Courier New"fontsize = 10 node [ fontname = "Courier New", fontsize = 10, shape = "record" ];edge [ fontname = "Courier New", fontsize = 10 ]; Animal [ label = "{Shape |+ getArea|+ draw}" ];     subgraph clusterShapeImpl{        bgcolor="yellow"        Triangle [ label = "{Triangle|+ getArea | + draw}" ];        Rectangular [ label = "{Rectangular|+ getArea | + draw}" ];    }; edge [ arrowhead = "empty" ]; Triangle->Animal;Rectangular->Animal;Triangle->Rectangular [arrowhead="none", label="0..*"];}

类图




小结

     本章对Graphviz进行入门级的介绍,演示了几种类型的示例,可以更加直接的了解Graphviz使用方法。当时为了快速画出函数的调用的关系,我使用doxygen对代码进行文档化输出,然后截图,想想也够浪费时间的,如果直接使用脚本进行格式化,想必回事半功倍。后续我会介绍doxygen工具的使用,希望对大家有所帮助。


参考

Graphviz官网         官网

Dot语法                 官方文档


修订

初稿                                       2014-11-16               Simon

1 0
原创粉丝点击