Jade Dungeon

Graphivz

绘图

sudo apt-get install graphviz graphviz-doc
dot :file ./img/example1.png :cmdline -Kdot -Tpng

里的:cmdline -Kdot -Tpng就是命令行参数. 他们告诉dot如何渲染和展示。

  • -Kdot使用dot布局方式. 你也可以尝试其他的布局方式,比如Kneato, Kcirco, Ktwopi, Kfdp, Ksfdp
  • -Tpng渲染成png格式

graphviz默认情况下对中文支持不好,如果代码中有中文,则必须使用UTF-8的格式保存文件,并且在代码中指定字体。

基本概念

安装graphviz工具,dot作为图形工具对dot源文件调整。

常用属性

所有结点通用属性

属性名称 默认值 含义
color black 颜色
colorscheme X11 颜色描述
fontcolor black 文字颜色
fontname Times-Roman 字体
fontsize 14 文字大小
label   显示的标签,对于节点默认为节点名称
penwidth 1.0 线条宽度
style   样式
weight   重要性

图像属性

  • label="My Graph" 给图像设置标签
  • rankdir=LR 将图片由原来的从上到下布局变成从左到右布局
  • {rank=same; a, b, c } 将一组元素放到同一个level
  • splines="line" 让边框变为直线,没有曲线和锐角
  • K=0.6 用来在布局中影响spring属性,spring属性可以用于将节点往外推,这个在twopi和sfdp布局中很有用。

译注:暂时还没明白这个spring属性应该怎么翻,初步猜测是弹性。胡克定律里面的常量名也叫K。

属性名称 默认值 含义
bgcolor   背景颜色
concentrate false 让多条边有公共部分
nodesep .25 节点之间的间隔(英寸)
peripheries 1 边界数
rank   same,min,source, max,sink,设置多个节点顺序
rankdir TB 排序方向
ranksep .75 间隔
size   图的大小(英寸)

交点属性

  • [label="Some Label"] 给交点打标签
  • [color="red"] 给交点上色
  • [fillcolor="blue"] 设置交点的填充色
属性名称 默认值 含义
shape ellipse 形状
sides 4 当shape=polygon时的边数
fillcolor lightgrey/black 填充颜色
fixedsize false 标签是否影响节点的大小

边的属性

  • [label="Some Label"] 给边设置标签 (设置路径权重的时候很有用)
  • [color="red"] 给交点上色 (标示路径的时候很有用)
  • [penwidth=2.0] 给边适配厚度,标示路径的时候很有用。
属性名称 默认值 含义
arrowhead normal 箭头头部形状
arrowsize 1.0 箭头大小
arrowtail normal 箭头尾部形状
constraint true 是否根据边来影响节点的排序
decorate   设置之后会用一条线来连接edge和label
dir forward 设置方向:forward,back,both,none
headclip true 是否到边界为止
tailclip true 与headclip类似

尺寸, 背景颜色

  • fixedsize=true
  • size="1,1"
  • resolution=72
  • bgcolor="#C6CFD532"

基本元素

无向图

无向图

graph绘制无向图:

graph gp0101 { 
	a -- b; 
	b -- c;
	b -- d;
	d -- a;
}

{}可以代表多个结点:

无向图

graph gh0106 {
	a -- {b, c, d, e}; 
}

另一个例子:

无向图

graph gh0107 {
	{a, b, c, d} -- e; 
}

节点的形状

digraph gp0501 {
  a [shape=box]
  b [shape=polygon,sides=6]
  c [shape=triangle]
  d [shape=invtriangle]
  e [shape=polygon,sides=4,skew=.5]
  f [shape=polygon,sides=4,distortion=.5]
  g [shape=diamond]
  h [shape=Mdiamond]
  i [shape=Msquare]
  a - b
  a - c
  a - d
  a - e
  a - f
  a - g
  a - h
  a - i
}

无向图

graph gp0502 {
  a [style=filled,color=green]
  b [peripheries=4,color=blue]
  c [fontcolor=crimson]
  d [style=filled,fillcolor=dodgerblue,color=coral4,penwidth=3]
  e [style=dotted]
  f [style=dashed]
  g [style=diagonals]
  h [style=filled,color="#333399"]
  i [style=filled,color="#ff000055"]
  j [shape=box,style=striped,fillcolor="red:green:blue"]
  k [style=wedged,fillcolor="green:white:red"]
  a -> b
  a -> c
  a -> d
  a -> e
  b -> f
  b -> g
  b -> h
  b -> i
  d -> j
  j -> k
}

无向图

指定布局方向

无向图

graph gp0102 { 
    rankdir=LR;  //Rank Direction Left to Right
	a -- b; 
	b -- c;
	b -- d;
	d -- a;
}

指定有向图

无向图

有向图不能用graph,要用digraph

digraph gp0103 { 
	a -> b;
	b -> c;
	a -> c;
}

另一个例子:

无向图

digraph gh0107 {
	a -> {b, c, d, e}; 
}

另一个例子:

digraph gh0109 {
	{a, b, c, d} -> e; 
}

无向图

digraph db0503 {
  a -> b [dir=both,arrowhead=open,arrowtail=inv]
  a -> c [dir=both,arrowhead=dot,arrowtail=invdot]
  a -> d [dir=both,arrowhead=odot,arrowtail=invodot]
  a -> e [dir=both,arrowhead=tee,arrowtail=empty]
  a -> f [dir=both,arrowhead=halfopen,arrowtail=crow]
  a -> g [dir=both,arrowhead=diamond,arrowtail=box]
}

无向图

digraph dg0504 {
  a -> b [color="black:red:blue"]
  a -> c [color="black:red;0.5:blue"]
  a -> d [dir=none,color="green:red:blue"]
  a -> e [dir=none,color="green:red;.3:blue"]
  a -> f [dir=none,color="orange"]
  d -> g [arrowsize=2.5]
  d -> h [style=dashed]
  d -> i [style=dotted]
  d -> j [penwidth=5]
}

无向图

加上说明标签

图

digraph graphname{
	T [label="Teacher"];   // node T
	P [label="Pupil"];     // node P

	T->P [label="Instructions", fontcolor=darkgreen] ;   // edge T->P
}

节点顺序

图

digraph MyGraph {
  rankdir=LR

  a -> b
  b -> c
  a -> d
  a -> c

  {rank=same;c;b}
}

图

digraph MyGraph {
  subgraph cluster_A {
    a1 -> a2
    a2 -> a3

    {rank=same;a1;a2;a3}
  }

  subgraph cluster_B {
    a3 -> b1
    b1 -> b2
    b2 -> b3

    {rank=same;b1;b2;b3}
  }

  begin -> a1
}

图

digraph MyGraph {
  subgraph cluster_A {
    a1
    a2
    a3
    {rank=same;a1;a2;a3}
  }

  subgraph cluster_B {
    b1
    b2
    b3

    {rank=same;b1;b2;b3}
  }

  begin -> a1
  a1 -> a2 [constraint=false]
  a2 -> a3 [constraint=false]
  a3 -> b1
  b1 -> b2
  b2 -> b3
}

The default value for ranksep is .5.

图

digraph MyGraph {
  rankdir=LR
  ranksep=1
  a -> b
  b -> c
  c -> d
}

指定样式

图

常用属性:

  • color
  • fontcolor
  • fontsize
  • shape
digraph gh0105 {
	// node T
    T [label="Teacher" color=Blue, fontcolor=Red, fontsize=24, shape=box];
	// node P
    P [label="Pupil"   color=Blue, fontcolor=Red, fontsize=24, shape=box];

    T->P [label="Instructions", fontcolor=darkgreen]     // edge T->P
}

更多形状看文档:https://graphviz.gitlab.io/_pages/doc/info/shapes.html

高级特性

定义复用组件

图

digraph gp0201 {

    nodesep=1.0 // increases the separation between nodes

	//All nodes will this shape and colour
    node [color=Red, fontname=Courier, shape=box]
    edge [color=Blue, style=dashed] //All the lines look like this

    Headteacher -> {Deputy1 Deputy2 BusinessManager}
    Deputy1 -> {Teacher1 Teacher2}
    BusinessManager -> ITManager
    {rank=same; ITManager Teacher1 Teacher2}  // Put them on the same level
}

定义数据结构

指定形状为record开描述数据结构:

图

digraph gp0202 {

    node[shape=record]

    struct1 [label="<f0> left|<f1> mid\ dle|<f2> right"];
    struct2 [label="{<f0> one|<f1> two\n\n\n}" shape=Mrecord];
    struct3 [label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];

    struct1:f1 -> struct2:f0;
    struct1:f0 -> struct3;
}

另一个例子:

图

digraph gp0203 {
	node[shape=record]

	store1 [label="<f0> left|<f1> Some data store"];
	proc1 [label="{<f0> 1.0|<f1> Some process here\n\n\n}" shape=Mrecord];
	enti1 [label="Customer" shape=box];

	store1:f1 -> proc1:f0;
	enti1-> proc1:f0;
}

使用HTML样式

图

digraph gp0205 {
	abc [shape=none, margin=0, label=<
	    <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
	        <TR><TD ROWSPAN="3"><FONT COLOR="red">hello</FONT><BR/>world</TD>
	            <TD COLSPAN="3">b</TD>
	            <TD ROWSPAN="3" BGCOLOR="lightgrey">g</TD>
	            <TD ROWSPAN="3">h</TD>
	        </TR>
	        <TR><TD>c</TD>
	            <TD PORT="here">d</TD>
	            <TD>e</TD>
	        </TR>
	        <TR><TD COLSPAN="3">f</TD></TR>
	    </TABLE>>];
}

图

digraph dg0508 {
    a [shape=plaintext,label=<
      <table>
        <tr>
          <td color="#ff0000" bgcolor="#008822"><font color="#55ff00">Hello</font></td>
          <td>world!</td>
        </tr>
        <tr>
          <td colspan="2" color="#00ff00" bgcolor="#ff0000">
            <font color="#ffffff">are you ok?</font>
          </td>
        </tr>
      </table>
    >]
}

图

digraph dg0507 {
    a [shape=plaintext,label=<
      <table>
        <tr>
          <td>Hello</td>
          <td>world!</td>
        </tr>
        <tr>
          <td colspan="2" port="a1">are you ok?</td>
        </tr>
      </table>
    >]
    b [shape=plaintext,label=<
      <table border="0" cellborder="1" cellspacing="0">
        <tr>
          <td rowspan="3">left</td>
          <td>top</td>
          <td rowspan="3" port="b2">right</td>
        </tr>
        <tr>
          <td port="b1">center</td>
        </tr>
        <tr>
          <td>bottom</td>
        </tr>
      </table>
    >]

    a:a1 -> b:b1
    a:a1 -> b:b2
}

子图

subgraph定义子图:

图

digraph gp0203 {
	node[shape=record]

	subgraph level0{
		enti1 [label="Customer" shape=box];
		enti2 [label="Manager" shape=box];
	}
	subgraph cluster_level1{
		label ="Level 1";
		proc1 [label="{<f0> 1.0|<f1> One process here\n\n\n}" shape=Mrecord];
		proc2 [label="{<f0> 2.0|<f1> Other process here\n\n\n}" shape=Mrecord];
		store1 [label="<f0>	|<f1> Data store one"];
		store2 [label="<f0>   |<f1> Data store two"];
		{rank=same; store1, store2}
	}

	enti1 -> proc1
	enti2 -> proc2
	store1 -> proc1
	store2 -> proc2
	proc1 -> store2
	store2 -> proc1 
}

子布局

在dot中以cluster*开头的子图会被当做是一个新的布局来处理, 而不是在原图的基础上继续操作。

图

digraph dg0505 {
  subgraph cluster_a {
    b
    c -> d
  }
  a -> b
  d -> e
}

图

digraph dg0506 {
  subgraph cluster_a {
    subgraph cluster_b {
      subgraph cluster_c {
        d
      }
      c -> d
    }
    b -> c
  }
  a -> b
  d -> e
}

图

digraph gp0206 {
    subgraph cluster0 {
        node [style=filled,color=white];
        style=filled;
        color=lightgrey;
        a0 -> a1 -> a2 -> a3;
        label = "process #1";
    }
    subgraph cluster1 {
        node [style=filled];
        b0 -> b1 -> b2 -> b3;
        label = "process #2";
        color=blue
    }

    start -> a0;
    start -> b0;
    a1 -> b3;
    b2 -> a3;
    a3 -> a0;
    a3 -> end;
    b3 -> end;
    start [shape=Mdiamond];
    end [shape=Msquare];
}

如果没有cluster的话我们大概能想象的出来最后的结果是什么样子的。 可能会想能不能将一个节点直接指向cluster?答案是不能! 对于这种需求可以用lhead来搞定:

图

digraph gp0207 {
    compound=true;

    subgraph cluster0 {
        a -> b;
        a -> c;
        b -> d;
        c -> d;
    }
    subgraph cluster1 {
        e -> g;
        e -> f;
    }

    b -> f [lhead=cluster1];
    d -> e;
    c -> g [ltail=cluster0, lhead=cluster1];
    c -> e [ltail=cluster0];
    d -> h;
    cluster0->cluster1;
}

图像节点

图

digraph MyGraph {
  ec2 [shape=none,label="",image="icons/ec2.png"]
  igw [shape=none,label="",image="icons/igw.png"]
  rds [shape=none,label="",image="icons/rds.png"]
  vpc [shape=none,label="",image="icons/vpc.png"]

  subgraph cluster_vpc {
    label="VPC"

    subgraph cluster_public_subnet {
      label="Public Subnet"
      ec2
    }

    subgraph cluster_private_subnet {
      label="Private Subnet"
      ec2 -> rds
    }

    vpc
    igw -> ec2
  }

  users -> igw
}

常用例子

UML

类图

无向图

digraph gp0301 {
	node[shape=record];
	rankdir="BT";

	teacher  [label = "{<f0> Teacher | <f1> \n | <f2> \n }"];
	course   [label = "{<f0> Course  | <f1> \n | <f2> \n }"];
	student  [label = "{<f0> Student | <f1> \n | <f2> \n }"];
	lesson   [label = "{<f0> Lesson  | <f1> \n | <f2> \n }"];
	tutorial [label = "{<f0> Tutorial| <f1> \n | <f2> \n }"];
	assessment [label = "{<f0> Assessment|<f1> \n | <f2> \n }"];
	coursework [label = "{<f0> Coursework|<f1> \n | <f2> \n }"];
	exam [label = "{<f0> Exam|<f1> \n  | <f2> \n }"];

	{rank=same; teacher course student}

	teacher    -> course [dir="forward", arrowhead="none",    arrowtail="normal", headlabel="1", taillabel="1.."];
	student    -> course [dir="forward", arrowhead="none",    arrowtail="normal", headlabel="1", taillabel="1.."];
	lesson     -> course [dir="forward", arrowhead="diamond", arrowtail="normal"];
	tutorial   -> course [dir="forward", arrowhead="diamond", arrowtail="normal"];
	assessment -> course [dir="forward", arrowhead="diamond", arrowtail="normal"];
	coursework -> assessment;
	exam   -> assessment;
}

ER图

无向图

digraph gp0302 {
	node[shape=box];

	Book;
	Customer;
	Loan;

	{rank=same; Book, Loan, Customer}

	Book     -> Loan[dir="forward", arrowhead="crow", arrowtail="normal"];
	Customer -> Loan[dir="forward", arrowhead="crow", arrowtail="normal"];
}

数据流

图

digraph gp0203 {
	node[shape=record]

	subgraph level0{
		enti1 [label="Customer" shape=box];
		enti2 [label="Manager" shape=box];
	}
	subgraph cluster_level1{
		label ="Level 1";
		proc1 [label="{<f0> 1.0|<f1> One process here\n\n\n}" shape=Mrecord];
		proc2 [label="{<f0> 2.0|<f1> Other process here\n\n\n}" shape=Mrecord];
		store1 [label="<f0>	|<f1> Data store one"];
		store2 [label="<f0>   |<f1> Data store two"];
		{rank=same; store1, store2}
	}

	enti1 -> proc1
	enti2 -> proc2
	store1 -> proc1
	store2 -> proc2
	proc1 -> store2
	store2 -> proc1 
}

进程图

图

digraph gp0305 {

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

	subgraph cluster1 {
		node[style=filled];
		color=blue;
		b0 -> b1 -> b2 -> b3;
		label="process #2";
	}   

	start -> a0;
	start -> b0;
	a1    -> b3;
	b2    -> a3;
	a3    -> end;
	b3    -> end;

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

函数调用关系

图

digraph gp0307 {

    node [shape=ellipse, style=filled, color="#40e0d0"];
    edge [color="#606060", penwidth=3];
    main [color=green];

    main     -> init[color=blue, label="hello, I'm \llable of edge"];
    main     -> mainloop;
    main     -> exit;
    init     -> a_init;
    init     -> b_init;
    init     -> c_init;
    mainloop -> select;
}

label中\r, \l, \n都表示换行,但对齐方式分别是右对齐,左对齐,居中。

状态机

图

digraph gp0308 {
	accept -> TS_HTTP_POST_REMAP_HOOK;
	TS_HTTP_POST_REMAP_HOOK -> "check request method (and header)";

	"check request method (and header)" -> "get CacheUrl hash_key using MurmurHash3" [label = "GET request (required_header present)"];
	"check request method (and header)" -> "pass request" [label = "others"];
	"get CacheUrl hash_key using MurmurHash3" -> "check hash_key from hashTable";
	"check hash_key from hashTable" -> "lock URL in hashTable" [label = "not found"];
	"check hash_key from hashTable" -> "pass request" [label = "found, but marked pass"];
	"check hash_key from hashTable" -> "check hash_key from hashTable" [label = "locked or unable to get mutex, wait insert_lock_retry_time"];
	"lock URL in hashTable" -> TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK;
	TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK -> "remove URL from hashTable(1)" [label = "hit_fresh or skipped"];
	TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK -> "request origin server" [label = "miss or stale"];
	"request origin server" -> TS_HTTP_READ_RESPONSE_HDR_HOOK;
	TS_HTTP_READ_RESPONSE_HDR_HOOK -> "remove URL from hashTable(1)" [label = "not 200/OK response"];
	TS_HTTP_READ_RESPONSE_HDR_HOOK -> "check read_while_writer config";
	"check read_while_writer config" -> "remove URL from hashTable(1)" [label = "enabled"];
	"check read_while_writer config" -> TS_HTTP_TXN_CLOSE_HOOK [label = "disabled"];
	TS_HTTP_READ_RESPONSE_HDR_HOOK -> "mark pass in hashTable" [label = "non-cacheable"];
	"remove URL from hashTable(1)" -> TS_HTTP_TXN_CLOSE_HOOK;
	"mark pass in hashTable" -> TS_HTTP_TXN_CLOSE_HOOK;
	"pass request" -> TS_HTTP_TXN_CLOSE_HOOK;
	TS_HTTP_TXN_CLOSE_HOOK -> "remove URL from hashTable(2)";
	TS_HTTP_TXN_CLOSE_HOOK -> "check keep_pass_record_time" [label = "non-cacheable"];
	"check keep_pass_record_time" -> "add into KeepPassList" [label = "> 0"];
	"check keep_pass_record_time" -> "remove URL from hashTable(2)" [label = "= 0"];
	"add into KeepPassList" -> "transaction close";
	"remove URL from hashTable(2)" -> "transaction close";
	"transaction close" -> accept;                                                                                                                                         

	TS_HTTP_POST_REMAP_HOOK [shape = box];
	TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK[shape = box];
	TS_HTTP_READ_RESPONSE_HDR_HOOK [shape = box];
	TS_HTTP_TXN_CLOSE_HOOK [shape = box];

	"check request method (and header)" [shape = diamond];
	"check hash_key from hashTable" [shape = diamond];
	"check read_while_writer config" [shape = diamond];
	"check keep_pass_record_time" [shape = diamond];
}



数据结构

二叉树

图

digraph gp0303 {
    node[shape=record, height=.1];

    node0[label="<f0> |<f1> G|<f2> "];
    node1[label="<f0> |<f1> E|<f2> "];
    node2[label="<f0> |<f1> B|<f2> "];
    node3[label="<f0> |<f1> F|<f2> "];
    node4[label="<f0> |<f1> R|<f2> "];
    node5[label="<f0> |<f1> H|<f2> "];
    node6[label="<f0> |<f1> Y|<f2> "];
    node7[label="<f0> |<f1> A|<f2> "];
    node8[label="<f0> |<f1> C|<f2> "];
        
    "node0":f2->"node4":f1;
    "node0":f0->"node1":f1;
    "node1":f0->"node2":f1;
    "node1":f2->"node3":f1;
    "node2":f2->"node8":f1;
    "node2":f0->"node7":f1;
    "node4":f2->"node6":f1;
    "node4":f0->"node5":f1;
}

哈希表

图

digraph gp0304 {
    nodesep=.05;
    rankdir=LR;
        
    node[shape=record, width=.1, height=.1];
    node0[label="<f0> |<f1> |<f2> |<f3> |<f4> |<f5> |<f6> |", height=2.5]

    node[width=1.5];
    node1[label="{<n> n14 | 719 |<p>}"];
    node2[label="{<n> a1  | 719 |<p>}"];
    node3[label="{<n> i9  | 512 |<p>}"];
    node4[label="{<n> e5  | 632 |<p>}"];
    node5[label="{<n> t20 | 959 |<p>}"];
    node6[label="{<n> o15 | 794 |<p>}"];
    node7[label="{<n> s19 | 659 |<p>}"];
        
    node0:f0 -> node1:n;
    node0:f1 -> node2:n;
    node0:f2 -> node3:n;
    node0:f5 -> node4:n;
    node0:f6 -> node5:n;
    node2:p  -> node6:n;
    node4:p  -> node7:n;
}

模型

化学分子式

图

digraph gp0306 {
	C_0 -- H_0;
	C_0 -- H_1;
	C_0 -- H_2;
	C_0 -- C_1;
	C_1 -- H_3;
	C_1 -- H_4;
	C_1 -- H_5;
}