可视化工具Graphviz

自由绘图软件中有两大神器:gnuplotgraphviz。前者一般用来可视化你的数据,比如,描绘函数曲线、数据分布之类的,对我来说其实用的不多。后者在软件领域使用得可能相对频繁,比如,显示一些结构化信息、流程图、网络拓扑图、函数调用序列等等,很是实用。本文介绍一下graphviz。

我之所以说他俩是神器,因为他们提供非常方便的命令行接口,可以完成自动化绘图功能,并且你不必仔细考虑节点尺寸、连线、布局等细节,只需要把握处理流程或者拓扑结构就可以了。这是一种“所思即所得”的绘图工具。

直接举官方的一个示例,这应该是一段代码的流程图:

Graphviz example

如下代码就可以胜任:

digraph G {
    subgraph cluster_0 {
        style=filled;
        color=lightgrey;
        node [style=filled,color=white];
        a0 -> a1 -> a2 -> a3;
        label = "process #1";
    }

    subgraph cluster_1 {
        node [style=filled];
        b0 -> b1 -> b2;
        label = "process #2";
        color=blue
    }
    start -> a0;
    start -> b0;
    a1 -> b2 [color=red,label="call it",fontcolor=red];
    b2 -> b0 [style=dotted];
    a3 -> end;
    b2 -> end;

    start [shape=Mdiamond];
    end [shape=Msquare];
}

然后,你可以用make来管理它:

DOT=d:/program/Graphviz/bin/dot.exe

all: graphviz_cluster.png

%.png: %.dot
    $(DOT) -Tpng $< -o $@

实际使用中,Graphviz的具体绘图是由一系列的小工具完成的:

  • dot 适用于有向无环图(DAG)和各种层次结构绘图。
  • neato 常用于无向图,基于一种弹性模型,可以自动优化各节点之间的距离。
  • twopi 适用于放射状的布局,即从一个中心出发,以固定的半径绘制其他节点,以此扩展开。
  • circo 适用于环状布局,它会先寻找双连通分量,把内聚度较高的子图绘制成团。
  • fdp 基于Force-directed算法的弹性模型,适合绘制没有交叉边的无向图。
  • sfdp 更适用于大型无向图绘制,节点尺寸的比例相对小很多。
  • patchwork 绘制方块形的格状图,该工具忽略边的定义,主要利用subgraph进行布局。

它们都是解释一种名为DOT的语法,只是各自适用于不同风格和布局的绘图。从语言的命名就能看出,一般常用的工具就是dot,还有一个以此命名的交互式绘图工具dotty,适用于X Window图形环境。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
  subgraph : [ subgraph [ ID ] ] '{' stmt_list '}'
compass_pt : (n | ne | e | se | s | sw | w | nw | c | _)

其中,node、edge、graph、digraph、subgraph和strict是关键字。

Update@2008-10-30: BTW,后来一朋友看了这篇短文,说,本来也想用这工具画画图,显示数据的,不过后来都用python替代。言者无心,听者有意。的确多掌握工具,不如只精通一种脚本呢,同学们来学python吧~ 的确很火热,很流行,也很强大。

Update@2011-02-12: 扩展:用 Graphviz 可视化函数调用