常会在一些技术书籍、文章里面看到描述数据结构的图形,很大一部分应该是用DOT语言生成的图片,还有一部分可能是metapost生成的。
对于DOT语言 ,是一种文本图形描述语言,文件通常是具有.gv或是.dot的文件扩展名,比较常用的用Graphviz软件包 渲染为多种文件格式。
DOT语言适合快速、高效的画出流程图、结构图等,但图中元素是自动布局的,无法精确控制每个元素的具体位置;当有大量元素的时候,自动布局的优势就显现出来了。如果需要精确布局,可以生成图片然后调整图片内容。
语言定义:
graph:[ strict ] (graph | digraph) [ ID ] '{' stmt_list '}' stmt_list:[ stmt [ ';' ] [ stmt_list ] ] stmt: node_stmt | edge_stmt | attr_stmt | ID '=' ID | subgraph attr_stmt:(graph | node | edge) attr_list attr_list:'[' [ a_list ] ']' [ attr_list ] a_list:ID '=' ID [ ',' ] [ a_list ] edge_stmt:(node_id | subgraph) edgeRHS [ attr_list ] edgeRHS:edgeop (node_id | subgraph) [ edgeRHS ] node_stmt:node_id [ attr_list ] node_id:ID [ port ] port:':' ID [ ':' compass_pt ] |':' compass_pt ubgraph:[ subgraph [ ID ] ] '{' stmt_list '}'compass_pt:(n | ne | e | se | s | sw | w | nw | c | _)
用关键字graph定义一个无向图,用“ – – ”表示节点之间的关系,如:
graph test1{ a[label="旧金山",shape=house]; b[label="KDS",shape=box,fillcolor=yellow]; c[label="北京",shape=egg,style=filled,fillcolor=yellow]; d[label="沈阳",shape=ellipse]; a--b[label="总部"]; b--c[label="MOA",color=red]; b--d[label="神秘部队",color=blue]; label="test1.png";}
生成一张PNG图片: dot -Tpng test1.dot > test1.png
用关键字digraph定义一个有向图,用“ -> ”表示节点之间的关系,如:
digraph test2{ rank=TD; a[label="Buiness Analysis"]; b[label="Requirement Analysis"]; c[label="Design"]; d[label="Module Design"]; e1[label="Code A"]; e2[label="Code B"]; f[label="Test"]; f1[label="Test A"]; f2[label="Test B"]; g[label="N+1 Product"]; h[label="N Product"]; a -> b; b -> c[label="Review",color=red]; c -> d; d -> e1; d -> e2; e1 -> f1; e2 -> f2; f1 -> f; f2 -> f; f -> g; g -> h[label="Review",color=red]; label="\n\nSDM WorkFlow\n\n";}
生成图片: dot -Tpng test2.dot > test2.png
对于图片中的节点、线条和边框,都可以定义自己的属性,比如颜色等,多个属性用”, ” 分割:
graph graphname { a [label="Foo"]; // label属性可以改变节点的显示名称 b [shape=box]; // 节点形状被改变了 a -- b -- c [color=blue]; // a-b边和b-c边有相同的属性 b -- d [style=dotted];}
这个例子可以看到(命令 info dot 能查看更多细节):
label属性定义节点的显示名称shape属性定义节点的形状,其中box是盒子外框,更多查阅:http://www.graphviz.org/content/node-shapes“//”是注释符,“#”也是注释,“/*..*/”也是注释,类似C风格和Shell风格color属性定义边框线条颜色style属性定义线条的样式风格,风格列表:solid、dashed 、dotted、 bold、 invis
digraph g { size="30,40"; bgcolor="#BBCAF2"; // graph属性,用来定义图片的一些属性 // rankdir=LR , 表示从Left到Right排列图形,LR,TD // center=ture, 图片居中显示 // margin=0.2, 边缘间距,0表示不需要边缘间距 // nodesep=2.1, 表示节点之间的距离 // ranksep=0.3, 表示列与列之间的距离 // 关于属性attr: http://www.graphviz.org/content/attrs graph[rankdir=LR, center=true, margin=0.2, nodesep=10, ranksep=1] // edge用来定义线条的属性 // arrowsize=1.0, 设置箭头大小 // arrowhead=vee, 设置箭头形状是v字型 // 关于线条edge:http://www.graphviz.org/content/arrow-shapes edge[arrowsize=1.0, arrowhead=vee] // node用来定义节点的属性 // shape=record, 定义节点形状是类似档案记录 // height=10,定义节点的高度 // width=10,定义节点宽度 // fontname="Courier-Bold", 定义字体 // fontsize=10, 定义字体大小 // fixedsize=true, 固定大小,false是自动变更大小 // 关于节点node: http://www.graphviz.org/content/node-shapes node [shape = record,fontname="sans-serif", fontsize=20, width=1, height=1, fixedsize=false]; node0[label = "<prev> prev|<value> A|<next> next"]; // <xx>,这里xx是一个属性元素,可以调用 node1[label = "<prev> prev|<value> B|<next> next"]; // B, 这是节点的显示名称 node2[label = "<prev> prev|<value> C|<next> next"]; // | 用来分割,label有很多魔法,要查看文档 head [label = "HEAD", url="http://lesliezhu.github.com"]; head -> node0:value[dir=both, arrowtail=dot]; //箭尾是点,只有both的才有效 node0:next -> node1:value[color=red, tailport=s headport=s, dir=both,arrowtail=vee]; //这里的dir=both是双向箭头 node1:next -> node2:value[color=blue, tailport=s headport=s,arrowhead=normal]; //箭头是普通造型 //{rank=same; node0 node1 node2;} // 3个节点在同一列 label="\n简单的数据结构关系图\n";}
效果: dot -Tpng test5.dot -o test5.png
比如:
digraph Agency { size="30,40"; bgcolor="#BBCAF2"; // graph属性,用来定义图片的一些属性 // rankdir=LR , 表示从Left到Right排列图形,LR,TD // center=ture, 图片居中显示 // margin=0.2, 边缘间距,0表示不需要边缘间距 // nodesep=2.1, 表示节点之间的距离 // ranksep=0.3, 表示列与列之间的距离 graph[center=true, margin=0.2, nodesep=1, ranksep=1] // edge用来定义线条的属性 // arrowsize=1.0, 设置箭头大小 // arrowhead=vee, 设置箭头形状是v字型 edge[arrowsize=1.0, arrowhead=vee] // node用来定义节点的属性 // shape=record, 定义节点形状是类似档案记录 // height=10,定义节点的高度 // width=10,定义节点宽度 // fontname="Courier-Bold", 定义字体 // fontsize=10, 定义字体大小 // fixedsize=true, 固定大小,false是自动变更大小 node [shape = record,fontname="sans-serif", fontsize=20, width=1, height=1, fixedsize=false]; subgraph cluster_agency{ agency[label="Agency Data"]; subgraph cluster_info{ label = "Factor Day"; the4th1[label = "4th",shape = record,fontname="sans-serif", fontsize=20, width=1, height=0.5, fixedsize=false,color=red,style=filled]; the6th[label = "6th",shape = record,fontname="sans-serif", fontsize=20, width=1, height=0.5, fixedsize=false,color=blue,style=filled]; the8th[label = "8th",shape = record,fontname="sans-serif", fontsize=20, width=1, height=0.5, fixedsize=false,color=green,style=filled];} subgraph cluster_fnma{ label="FNMA"; fn[label = "{<fix> FIX|<arm>ARM|<breakout> Breakout|<ll> Loan Level}"]; } subgraph cluster_fhlmc{ label="FHLMC"; fh[label = "{<fix> FIX|<arm>ARM|<breakout> Breakout|<ll> Loan Level}"]; } gnma[label="{GNMA I|FIX|Breakout|Loan Level||GNMA II|FIX|ARM|Breakout|Loan Level}"]; /* subgraph cluster_gnma{ label="GNMA"; subgraph cluster_gnma1{ label="GNMA I"; gnma1[label = "{<fix> FIX|<breakout> Breakout|<ll> Loan Level}"]; } subgraph cluster_gnma2{ label="GNMA II"; gnma2[label = "{<fix> FIX|<arm>ARM|<breakout> Breakout|<ll> Loan Level}"]; } }*/ agency->gnma; agency->fn; agency->fh; agency->the8th; agency->the6th; agency->the4th1; } label="\nMBS Agency关系图\n";}
更多文档查阅:http://www.graphviz.org/Documentation.php
作者简介:
朱春来(Leslie Zhu),金融工程师,毕业于西安电子科技大学, 喜欢历史,喜欢编程. 日常在GNU/Linux环境下进行C/C++、Python开发,对Common Lisp、Node.js、金融等感兴趣。可以通过邮箱(pythonisland@gmail.com)联系他,或者直接在他的个人主页上留言.
访问朱春来(Leslie Zhu)的个人主页(http://lesliezhu.github.com)