Graphviz工具

工欲善其事,必先利其器。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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

心静以致远

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值