玩转graphviz绘图

初识

初次见面

graphviz是一个非常棒的画图工具集,由AT&T实验室出品,码农装逼一大利器。

小试牛刀

如学习新语言一样,我们从hello world开始。

1
digraph HelloWorld {
  h;
  e;
  l;
  l;
  o;

  w;
  o;
  r;
  l;
  d;

  h -> e -> l -> l -> o 
  w -> o -> r -> l -> d 
}

我们用graphviz工具集中的dot转换成图片:

dot -Tpdf *.dot > *.pdf

效果如下:

效果不错,但似乎有点单调,我们下面来剖析下。

剖析

graph

首先,graph可以设置许多特性,比如labelrankdirsplines等。具体说明参见:

  • label=”My Graph”; Label a graph itself

  • rankdir=LR; Lay the graph out from Left to Right, instead of Top to Bottom

  • {rank=same; a, b, c} Group nodes together at the same level of a graph

  • splines=”line”; Force edges to be straight, no curves or angles

  • K=0.6; Used to influence the ‘spring’ used in the layout, Can be used to push nodes further apart, which is especially useful for twopi and sfdp layouts

顶点

我们再来改变下顶点的特点,比如将顶点从原先的圆形修改成鸡蛋型。我们加入对顶点设置:

1
node [shape="egg", style="filled"]

效果如下:

当然,顶点还有很多特性可以设置,除了shape外,还有labelfillcolorstyle等。

我们对边也可以进行某些特性的设置,如果labelcolorpenwidth等。

我们简单设置下:

1
edge [color="blue", style="dashed"]

效果如下:

子图

graphviz另外还支持子图的绘制。比如:

1
subgraph cluster_world {
  label="world"
  bgcolor="gray"
  ...
}

效果如下:

玩转

下面我们直接来看一下不同的效果图。

抽像树

1
digraph ast {
  fontname = "Microsoft YaHei"
  fontsize = 10

  node [shape="plaintext", fontname="Microsoft YaHei", fontsize=10]
  edge [fontname="Microsoft YaHei", fontsize=10]

  mul [label="mul(*)"]
  add [label="add(+)"]

  add -> 3
  add -> 4
  mul -> add
  mul -> 5
}

状态机

1
digraph automate {
  size = "8.5, 11"
  fontname = "Microsoft YaHei"
  fontsize = 10

  node [shape=circle, fontname="Microsoft YaHei", fontsize=10]
  edge [fontname="Microsoft YaHei", fontsize=10]

  0 [style=filled, color=lightgray]
  1
  2 [shape=doublecircle]

  0 -> 2 [label="a"]
  0 -> 1 [label="other"]
  1 -> 2 [label="a"]
  1 -> 1 [label="other"]
  2 -> 2 [label="a"]
  2 -> 1 [label="other"]

  "Machine a" [shape=plaintext]
}

hash表

1
digraph hashtable {
  fontname = "Verdana"
  fontsize = 10
  rankdir=TB

  node [fontname="Verdana", fontsize=10, color=skyblue, shape=record]
  edge [fontname="Verdana", fontsize=10, color=crimson, style=solid]

  st_hash_type [label="{<head>st_hash_type|(*compare)|(*hash)}"]
  st_table_entry [label="{<head>st_table_entry|hash|key|record|<next>next}"]
  st_table [label="{st_table|<type>type|num_bins|num_entries|<bins>bins}"]

  st_table:bins -> st_table_entry:head
  st_table:type -> st_hash_type:head
  st_table_entry:next -> st_table_entry:head [style=dashed, color=forestgreen]
}

流程图

1
digraph JobStateDiagram {
  rankdir = LR
  size = "8,5"
  concentrate = true

  node [style="rounded,filled,bold", shape=box, fixedsize=true, width=1.3, fontname="Arial"]
  Created [fillcolor=black, shape=circle, label="", width=0.25]
  Destroyed [fillcolor=black, shape=doublecircle, label="", width=0.3]
  Empty [fillcolor="#a0ffa0"]
  Failed [fillcolor="#ffa0a0"]
  Announced [fillcolor="#a0ffa0"]
  Assigned [fillcolor="#a0ffa0"]
  Working [fillcolor="#a0ffa0"]
  Ready [fillcolor="#a0ffa0"] 
  TimeOut [fillcolor="#ffa0a0"]

  {
    rank=source; Created; Destroyed;
  }
  {
    rank=same; Announced; Failed;
  }
  {
    rank=same; Assigned; TimeOut;
  }

  edge [style=bold, fontname="Arial", weight=100]
  Empty -> Announced [label="announce"]
  Announced -> Assigned [label="assign"]
  Assigned -> Working [label="start"]
  Working -> Ready [label="finish"]
  Ready -> Empty [label="revoke", weight=1]

  edge [color="#aaaaaa", weight=1]
  Announced -> TimeOut [label="timeout"] 
  Assigned -> TimeOut [label="timeout"]
  Working -> TimeOut [label="timeout"]
  Working -> Failed [label="error"]
  TimeOut -> Announced [label="annouce"]
  TimeOut -> Empty [label="revoke"]
  Failed -> Announced [label="announce"]
  Failed -> Empty [label="revoke"]

  Created -> Empty [label="initialize"]
  Empty -> Destroyed [label="finalize"]
  Announced -> Empty [label="revoke"]
  Assigned -> Empty [label="revoke"]
  Working -> Empty [label="revoke"]
}

(来自stackoverflow)