使用Graphviz下的dot工具绘制图像

lixlsj 8年前

来自: http://my.oschina.net/Tsybius2014/blog/617963


一、关于Graphviz下的dot工具

Graphviz是一个画图软件,其中的dot工具可以用于绘制流程图。dot工具可以根据dot语言代码生成GIF、PNG、SVG、PDF、PostScript格式的图片文件。

通过dot工具,可以绘制出如下面这样复杂的流程图(摘自dot工具官方帮助手册):

dot工具画图通过以下四个步骤来完成:

第一步:通过翻转一些循环边的内部方向,打破在输入图中出现的环路。

第二步:将节点分配给不同的等级(rank)和层次(level),自顶向下绘图,等级决定了纵轴的位置。跨越了多个等级的边,会被拆分成有多个虚拟节点相连接的链条。

第三步:根据节点等级(rank)为节点排序以避免节点的交叉。

第四步:在保持边长尽量短的情况下,设置节点的横坐标,同时绘出边的样条曲线。

dot工具的绘图方法,其官网 www.graphviz.org 上面有着详细地介绍,这里不再做详尽说明。

二、使用dot工具生成图片

安装Graphviz后,新建一个文件夹,建立一个bat文件取名【GenerateJpgsBatch.bat】,代码如下:

:: 在这里设置调用文件路径  set dotPath=D:\Graphviz2.38  set sourcePath=C:\Users\Tsybius\Desktop\graphviz_study    rem 测试文件XXX  %dotPath%\bin\dot.exe -Tjpg %sourcePath%\XXX.dot -o %sourcePath%\XXX.jpg    pause

其中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=<          <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">              <TR><TD>张<BR/>飞</TD><TD COLSPAN="2">曹操</TD><TD>马<BR/>超</TD></TR>              <TR>                  <TD ROWSPAN="2">赵<BR/>云</TD>                  <TD COLSPAN="2">关羽</TD>                  <TD ROWSPAN="2">黄<BR/>忠</TD>              </TR>              <TR><TD>卒</TD><TD>卒</TD></TR>              <TR><TD>卒</TD><TD COLSPAN="2"></TD><TD>卒</TD></TR>          </TABLE>      >];  }

生成图片如下:

五、实例三:为图片添加层次关系-世系树

世系树要求将同一个辈分的人放在同一个层次,下面这个例子描绘了汉宣帝从高祖到其自身的世系树,它设置了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