如何使用graphviz绘制流程图
今天给大家安利一款小清新的思维导图开源软件 graphviz
我也是刚发现,兴奋之余来跟大家分享一下,好了废话不多讲,
===========================================分割线========================
第一步:下载安装:http://www.graphviz.org/(官网)
这里只说一下window,因为本人用的就是Windows哈哈哈!
选者一个下载之后就是傻瓜式安装,不过要记得安装路径,因为之后要配置环境变量path
第二步:配置环境变量
将目录bin的路径复制出来,例如:E:\graphviz\bin
右键我的电脑-属性-高级系统设置-高级-环境变量(N),点击进去之后再系统变量里面找到path,选中点击编辑,新增一个路径例如我的:E:\graphviz\bin
配置好之后,调出命令行,即运行cmd,输入dot -version ,如果弹出版本号等信息说明安装成功!
===============================以下开始上手使用==============================
下面一部分转载自:http://www.th7.cn/Program/Python/201610/982762.shtml
http://www.tuicool.com/articles/vy2Ajyu
一、Graphviz脚本语言接口之小试牛刀
新建myfirst.gv文件,输入以下代码:
digraph G {
a[label="node a",shape=record];
b[label="node b",shape=ellipse];
a->b[label="edge a-> b"];
}
在本目录的Shell中输入命令;
dot myfirst.gv -T png -o myfirst.png
输出一个图片文件myfirst.png,如下:
解释:
首先解释一下源代码文件,文件名后缀没有强制要求,但一般使用gv、dot等后缀。
再源文件内部,代码布局是这样的:
digraph/graph graph_name {
command_line1;
command_line2;
......
}
graph代表此图是无向图(就是连线没有箭头),digraph就是有向图,后面时图的名字(可有可无),再后面就是用花括号括起来的图的元素——子图、节点和连线——以命令的形式表示,并且用分号隔开。
在本例中,此图是一个有向图,名字为G,有三个元素:节点a,标题为“node a”,形状是矩形;节点b,标题为“node b”,形状是椭圆(默认);有向连线a->b,标题为“edge a -> b ”。
在命令行中,最开始的dot是一个解释程序,对源文件进行解释并采用dot布局算法,计算图的形状,类似的算法还有neato、fdp、sfdp、twopi、circo等等,对应的命令跟它们的名称一样,例如,我想使用neato,而不是dot算法计算布局,输入以下命令:
neato myfirst.gv -T png -o myfirst.png
输出如下:
可以看出,使用的布局算法不同,得到的结果也是不同的,以后我们可以看到,布局算法是Graphviz中的精华部分,非常值得一学。
跟GCC一样,命令的第二个参数是输入文件,-o 后面是输出文件,-T后面是输出文件的格式,可以是各种图形格式例如:PNG、JPG、GIF、SVG、PDF、PS甚至是非图形的DOT语言自己,在这里你可能会说,DOT格式不是变回自己吗,这也有意义?答案是,有,但不是这里。再以后的章节我会详细说明。
(三)、Graphviz的C语言接口之小试牛刀
新建myfirst.cpp文件,加上以下内容:
#include
#include
int main(){
GVC_t * gv;
Agraph_t * g;
Agnode_t * a,* b;
Agedge_t * e;
gv=gvContext();
g=agopen("G",Agdirected,0);
a=agnode(g,"node a",1);
b=agnode(g,"node b",1);
agsafeset(a,"shape","record","ellipse");
agsafeset(a,"shape","ellipse","ellipse");
e=agedge(g,a,b,"edge e",1);
agsafeset(e,"label","edge a -> b","");
gvLayout(gv,g);
gvRenderFilename(gv,g,"png","myfirst.png");
gvRender(gv,g,"dot",stdout);
gvFreeLyout(gv,g);
agclose(g);
gvFreeContext(gv);
}
同目录终端输入以下命令,编译运行,编译时有可能会有很多警告,这是由于gvc接口的字符串参数类型为char *,而源代码中字符串类型为const char *,可以忽略:
g++ myfirst.cpp -o myfirst `pkg-config --libs --cflags libgvc`
./myfirst
可以得到图片(myfirst.png),以及以DOT语言为格式的,再标准输出上显示的代码:
代码:
digraph G {
graph [bb="0,0,97.447,123"];
node [label="/N",
shape=ellipse
];
"node a" [height=0.5,
pos="34.447,105",
width=0.95686];
"node b" [height=0.5,
pos="34.447,18",
width=0.95686];
"node a" -> "node b" [key="edge e",
label="edge a -> b",
lp="65.947,61.5",
pos="e,34.447,36.175 34.447,86.799 34.447,75.163 34.447,59.548 34.447,46.237"];
}
图片:
可以看到,图片输出的效果跟使用dot命令解释脚本一模一样,DOT格式输出也差不多(多了精确坐标信息)。
二、基本例子
1、 简单图例
graph graphname {
a -- b;
b -- c;
b -- d;
d -- a;
}
![](http://img0.tuicool.com/6NbEN3.png!web)
2、 一样的图,不一样的布局
graph graphname {
rankdir=LR; //Rank Direction Left to Right
a -- b;
b -- c;
b -- d;
d -- a;
}
![](http://img0.tuicool.com/bYNjqeV.png!web)
3 、简单有向图
digraph graphname{
a -> b;
b -> c;
a -> c;
}
![](http://img0.tuicool.com/EVBrayi.png!web)
4 、带标签的简单有向图
digraph graphname{
T [label="Teacher"] // node T
P [label="Pupil"] // node P
T->P [label="Instructions", fontcolor=darkgreen] // edge T->P
}
![](http://img2.tuicool.com/v6Jjaq.png!web)
5 、同样的图,不同的形状和颜色
digraph graphname {
T [label="Teacher" color=Blue, fontcolor=Red, fontsize=24, shape=box] // node T
P [label="Pupil" color=Blue, fontcolor=Red, fontsize=24, shape=box] // node P
T->P [label="Instructions", fontcolor=darkgreen] // edge T->P
}
![](http://img0.tuicool.com/FraEB3r.png!web)
这儿你可以选择的形状有: box
, polygon
, ellipse
, oval
, circle
, point
, egg
, triangle
, plaintext
, diamond
, trapezium
, parallelogram
, house
, pentagon
, hexagon
, septagon
, octagon
, doublecircle
, doubleoctagon
, tripleoctagon
更多的形状看 这里
6、 总结
digraph summary{
start [label="Start with a Node"]
next [label="Choose your shape", shape=box]
warning [label="Don't go overboard", color=Blue, fontcolor=Red,fontsize=24,style=filled, fillcolor=green,shape=octagon]
end [label="Draw your graph!", shape=box, style=filled, fillcolor=yellow]
start->next
start->warning
next->end [label="Getting Better...", fontcolor=darkblue]
}
![](http://img1.tuicool.com/R7b2uyr.png!web)
三、 高级
1、 节省时间的技巧
单独地去定义每一个节点其实很浪费时间的,下面这个技巧能够让你快点儿。
digraph hierarchy {
nodesep=1.0 // increases the separation between nodes
node [color=Red,fontname=Courier,shape=box] //All nodes will this shape and colour
edge [color=Blue, style=dashed] //All the lines look like this
Headteacher->{Deputy1 Deputy2 BusinessManager}
Deputy1->{Teacher1 Teacher2}
BusinessManager->ITManager
{rank=same;ITManager Teacher1 Teacher2} // Put them on the same level
}
![](http://img0.tuicool.com/yUBFvm.png!web)
2、 记录
你现在可以用HTML来定义这一类节点了, 这里 有更多相关信息。
digraph structs {
node[shape=record]
struct1 [label="<f0> left|<f1> mid\ dle|<f2> right"];
struct2 [label="{<f0> one|<f1> two\n\n\n}" shape=Mrecord];
struct3 [label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
struct1:f1 -> struct2:f0;
struct1:f0 -> struct3:f1;
}
![](http://img0.tuicool.com/mYRRv23.png!web)
四. 例子
1、 有限状态机
digraph finite_state_machine {
rankdir=LR;
size="8,5"
node [shape = circle];
S0 -> S1 [ label = "Lift Nozzle" ]
S1 -> S0 [ label = "Replace Nozzle" ]
S1 -> S2 [ label = "Authorize Pump" ]
S2 -> S0 [ label = "Replace Nozzle" ]
S2 -> S3 [ label = "Pull Trigger" ]
S3 -> S2 [ label = "Release Trigger" ]
}
![](http://img1.tuicool.com/yEze6z.png!web)
2、 数据流示意图
digraph dfd{
node[shape=record]
store1 [label="<f0> left|<f1> Some data store"];
proc1 [label="{<f0> 1.0|<f1> Some process here\n\n\n}" shape=Mrecord];
enti1 [label="Customer" shape=box];
store1:f1 -> proc1:f0;
enti1-> proc1:f0;
}
![](http://img0.tuicool.com/nIVVVf.png!web)
3、 数据流示意图2
digraph dfd2{
node[shape=record]
subgraph level0{
enti1 [label="Customer" shape=box];
enti2 [label="Manager" shape=box];
}
subgraph cluster_level1{
label ="Level 1";
proc1 [label="{<f0> 1.0|<f1> One process here\n\n\n}" shape=Mrecord];
proc2 [label="{<f0> 2.0|<f1> Other process here\n\n\n}" shape=Mrecord];
store1 [label="<f0> |<f1> Data store one"];
store2 [label="<f0> |<f1> Data store two"];
{rank=same; store1, store2}
}
enti1 -> proc1
enti2 -> proc2
store1 -> proc1
store2 -> proc2
proc1 -> store2
store2 -> proc1
}
![](http://img2.tuicool.com/jyQ3Ev.png!web)
4、 对象继承
digraph obj{
node[shape=record];
rankdir="BT";
teacher [label = "{<f0> Teacher|<f1> \n |<f2> \n }"];
course [label = "{<f0> Course|<f1> \n |<f2> \n }"];
student [label = "{<f0> Student|<f1> \n |<f2> \n }"];
lesson [label = "{<f0> Lesson |<f1> \n |<f2> \n }"];
tutorial [label = "{<f0> Tutorial|<f1> \n |<f2> \n }"];
assessment[label = "{<f0> Assessment|<f1> \n |<f2> \n }"];
coursework [label = "{<f0> Coursework|<f1> \n |<f2> \n }"];
exam [label = "{<f0> Exam|<f1> \n |<f2> \n }"];
{rank=same; teacher course student}
teacher->course [dir="forward",arrowhead="none",arrowtail="normal",headlabel="1",taillabel="1.."];
student->course [dir="forward",arrowhead="none",arrowtail="normal",headlabel="1",taillabel="1.."];
lesson->course [dir="forward",arrowhead="diamond",arrowtail="normal"];
tutorial->course [dir="forward",arrowhead="diamond",arrowtail="normal"];
assessment->course [dir="forward",arrowhead="diamond",arrowtail="normal"];
coursework->assessment;
exam->assessment;
}
![](http://img0.tuicool.com/NriQf2Z.png!web)
5、 关系型实体
digraph ER{
node[shape=box];
Book;
Customer;
Loan;
{rank=same;Book,Customer,Loan}
Book->Loan[dir="forward",arrowhead="crow",arrowtail="normal"];
Customer->Loan[dir="forward",arrowhead="crow",arrowtail="normal"];
}
![](http://img2.tuicool.com/E3Yziy.png!web)
五. 参考
以下可能是你在画图时候最有用的一些属性,完整的列表可以在 这里 看。
1 、图像属性
label="My Graph"; # 给图像设置标签
rankdir=LR; # 将图片由原来的从上到下布局变成从左到右布局
{rank=same; a, b, c } # 将一组元素放到同一个level
splines="line"; # 让边框变为直线,没有曲线和锐角
K=0.6; # 用来在布局中影响spring属性,spring属性可以用于将节点往外推,这个在twopi和sfdp布局中很有用。
译注:暂时还没明白这个spring属性应该怎么翻,初步猜测是弹性。胡克定律里面的常量名也叫K。
2、 交点属性
[label="Some Label"] # 给交点打标签
[color="red"] # 给交点上色
[fillcolor="blue"] # 设置交点的填充色
3、 边的属性
[label="Some Label"] # 给边设置标签 (设置路径权重的时候很有用)
[color="red"] # 给交点上色 (标示路径的时候很有用)
[penwidth=2.0] # 给边适配厚度,标示路径的时候很有用。
4、 尺寸, 背景颜色
fixedsize=true; size="1,1"; resolution=72; bgcolor="#C6CFD532";
=================================================结束========================
Graphviz的奇妙之处不仅于此,以后我会用更多的时间来介绍Graphviz,也欢迎读者和大神们和我一起学习Graphviz,共同提高。