一、关于Graphviz下的dot工具
Graphviz是一个画图软件,其中的dot工具可以用于绘制流程图。dot工具可以根据dot语言代码生成GIF、PNG、SVG、PDF、PostScript格式的图片文件。
通过dot工具,可以绘制出如下面这样复杂的流程图(摘自dot工具官方帮助手册):
dot工具画图通过以下四个步骤来完成:
第一步:通过翻转一些循环边的内部方向,打破在输入图中出现的环路。
第二步:将节点分配给不同的等级(rank)和层次(level),自顶向下绘图,等级决定了纵轴的位置。跨越了多个等级的边,会被拆分成有多个虚拟节点相连接的链条。
第三步:根据节点等级(rank)为节点排序以避免节点的交叉。
第四步:在保持边长尽量短的情况下,设置节点的横坐标,同时绘出边的样条曲线。
dot工具的绘图方法,其官网 上面有着详细的介绍,这里不再做更深层次的说明。本文中我使用的Graphviz版本为2.38
二、使用dot工具生成图片
安装Graphviz后,新建一个文件夹,建立一个bat文件取名【GenerateJpgsBatch.bat】,代码如下:
:: 在这里设置调用文件路径set dotPath=D:\Graphviz2.38set sourcePath=C:\Users\Tsybius\Desktop\graphviz_studyrem 测试文件XXX%dotPath%\bin\dot.exe -Tjpg %sourcePath%\XXX.dot -o %sourcePath%\XXX.jpgpause
其中dotPath为dot代码文件地址,sourcePath为生成后文件的地址。
上面的代码就是用dot.exe,将一个名为XXX.dot的文件,生成为图片XXX.jpg。
使用dot程序生成带有汉字信息的图片,需要注意两点,否则生成的图片中汉字会被显示为乱码:
1、文件应使用UTF-8编码保存,而不是Windows默认的ANSI编码
2、字体应指定为支持汉字的字体,如宋体为SimSun
三、实例一:最简单的dot图-高速公路节点图
下图是一张高速公路重要节点图。这张图是一张较为简单dot图,只有节点之间的简单指向关系。
文件【expressway.dot】内代码如下:
digraph { edge[fontname="SimSun",fontcolor=red]; node[fontname="SimSun",size="20,20"]; 北京[shape=doublecircle]; 湘潭[shape=plaintext] //高速公路节点关系 北京->石家庄->郑州->武汉->长沙->广州[label=京港澳高速,color=red]; 北京->天津->沈阳->长春->哈尔滨[label=京哈高速,color=lawngreen]; 北京->呼和浩特->银川->兰州->西宁->拉萨[label=京藏高速,color=purple]; 郑州->西安->兰州->乌鲁木齐[label=连霍高速,color=blue] 上海->杭州->南昌->湘潭->贵阳->昆明[label=沪昆高速,color=orange]; 福州->南昌->武汉->西安->银川[label=福银高速,color=brown]; 湘潭->长沙[style=dotted];}
生成图片如下:
四、实例二:类HTML语言编写复杂的节点-华容道
dot也支持解释一些类HTML的代码绘制近似于复杂表格的数据。
下图是由一个单一节点组成的,这个节点被划分成很多区域,被绘制成华容道最经典的图形-横刀立马
文件【huarongpass.dot】内代码如下:
digraph { huarongpass [shape=none, margin=0, fontname="SimSun" label=<
张飞 | 曹操 | 马超 | |
赵云 | 关羽 | 黄忠 | |
卒 | 卒 | ||
卒 | 卒 |
生成图片如下:
五、实例三:为图片添加层次关系-世系树
世系树要求将同一个辈分的人放在同一个层次,下面这个例子描绘了汉宣帝从高祖到其自身的世系树,它设置了5个rank。
文件【familytree.dot】内代码如下:
digraph { ranksep=2.75; size="15,15"; { edge [fontname="SimSun", fontcolor=red]; //时间线 node [shape=plaintext, fontname="SimSun", fontsize=60]; "高祖辈"->"曾祖辈"->"祖父辈"->"父辈"->"本人"; } { rank = same; }; node [shape=box, fontname="SimSun", fontsize=60]; { rank = same; "高祖辈"; "孝景皇帝刘启"; "孝景皇后王氏"; "外高祖父卫父"; "外高祖母卫媪"; } { rank = same; "曾祖辈"; "曾祖父世宗武皇帝刘彻"; "曾祖母思皇后卫子夫"; "外曾祖母贞君"; } { rank = same; "祖父辈"; "祖父戾太子刘据"; "祖母戾后史氏"; "外祖父思成侯王乃始"; "外祖母博平君思成夫人王媪"; } { rank = same; "父辈"; "父悼皇考刘进"; "母悼后王翁须" } { rank = same; "本人"; "中宗孝宣皇帝刘询" } {"孝景皇帝刘启", "孝景皇后王氏"}->"曾祖父世宗武皇帝刘彻"; {"外高祖父卫父", "外高祖母卫媪"}->"曾祖母思皇后卫子夫"; {"曾祖父世宗武皇帝刘彻", "曾祖母思皇后卫子夫"}->"祖父戾太子刘据"; "外曾祖母贞君"->"祖母戾后史氏" {"祖父戾太子刘据", "祖母戾后史氏"}->"父悼皇考刘进"; {"外祖父思成侯王乃始", "外祖母博平君思成夫人王媪"}->"母悼后王翁须"; {"父悼皇考刘进", "母悼后王翁须"}->"中宗孝宣皇帝刘询";}
生成图片如下:
六、实例四:通过创建子图对大图中的节点进行分组-三国君主传承顺序
dot支持可以通过创建子图(subgraph)对节点进行分区,如下图总结三国时代魏蜀吴三国君主传承顺序,将魏、蜀、吴三国的君主分到了各自的区域内。
文件【threekingdoms.dot】内代码如下:
digraph { edge[fontname="SimSun",fontcolor=red]; node[fontname="SimSun",size="20,20"]; subgraph cluster0 { color=red; "曹操(0)","曹丕(1)","曹叡(2)","曹髦(3)","曹芳(4)","曹奂(5)"[shape=box]; fontname="SimSun" label="#1 魏国"; "曹操(0)"->{"曹丕(1)", "曹彰", "曹宇"}; "曹丕(1)"->{"曹叡(2)", "曹霖"}; "曹霖"->"曹髦(3)" "曹彰"->"曹楷"->"曹芳(4)" "曹宇"->"曹奂(5)" } subgraph cluster1 { color=blue; "刘备(0)","刘禅(1)"[shape=box]; fontname="SimSun" label="#2 蜀国"; "刘备(0)"->"刘禅(1)" } subgraph cluster2 { color=purple; "孙坚(0)","孙策(1)","孙权(2)","孙亮(3)","孙休(4)","孙和(5)","孙皓(6)"[shape=box]; fontname="SimSun" label="#3 吴国"; "孙坚(0)"->{"孙策(1)","孙权(2)"}; "孙权(2)"->{"孙和(5)","孙休(4)","孙亮(3)"}; "孙和(5)"->"孙皓(6)"; } "初代君主"->{"曹操(0)","刘备(0)","孙坚(0)"}[style=dotted]; {"曹奂(5)","刘禅(1)","孙皓(6)"}->"末代君主"[style=dotted];}
生成图片如下:
END