语雀官方的Graphviz感觉太复杂,我还是写一个简单一点的吧。

两个圆一条线

注意

  • graph是用来标记无向图,里面只能用–,不能用->,否则无法显然出图片
  • digraph用来标记有向图,里面只用用-> 不能用–, 否则无法显然出图片
graph easy {
  a -- b;
}

连线加个备注

graph easy{
  a--b [label="你真漂亮"]
}

你真漂亮,要大点,红色显眼点

graph easy{
  a--b [label="你真漂亮", fontcolor=red, fontsize=34]
}

两个圆,一个带有箭头的线

注意,这里用的digraph, 用来表示有向图

digraph easy {
  a -> b;
}

如何画虚线呢?

digraph easy {
  a -> b [style=dashed];
}

椭圆太单调了,有没有其他形状?

shape

  • box  矩形
  • polygon
  • ellipse
  • circle  圆形
  • point
  • egg 蛋形
  • triangle 三角形
  • plaintext 使用文字
  • diamond 钻石型
  • trapezium 梯形
  • parallelogram 斜的长方形
  • house
  • hexagon
  • octagon
  • doublecircle
  • doubleoctagon
  • tripleoctagon
  • invtriangle
  • invtrapezium
  • invhouse
  • Mdiamond
  • Msquare
  • Mcircle
  • none
  • record
  • Mrecord

graph easy {
	node [shape=box]
  a -- b;
}

形状也可以直接给节点定义。

graph easy{
	a [shape=parallelogram]
	b [shape=egg]
  a--b;
}

还有什么布局姿势?

默认图是从上到下画的,你可以用rankdir = LR来让图从左往右绘制

digraph easy {
	rankdir = LR;
  a -> b;
}

当然,还有其他姿势

rankdir

  • LR  从左往右布局
  • RL 从右往左布局
  • TB  从上下往下布局(默认)
  • BT 从下往上布局

多来几个圆,看看效果

digraph easy {
	rankdir = LR;
  a -> b;
  b -> c;
  a -> c;
  c -> d;
  a -> d;
}

怎么加注释?

支持两种注释

  • //
  • /**/
digraph easy {
  a -> b; // 从a到b
  b -> c; /* 从b到c */
}

句尾要不要加分号?

答:分号不是必须的,你随意

如何起个别名?

不起别名的时候,名字太长,引用不方便。

graph easy{
  "直到确定,手的温度来自你心里"--"这一刻,也终于勇敢说爱你";
  "这一刻,也终于勇敢说爱你" -- "一开始 我只顾着看你, 装做不经意 心却飘过去"
}

起个别名,快速引用

graph easy{
	a [label="直到确定,手的温度来自你心里"];
  b [label="这一刻,也终于勇敢说爱你"];
  c [label="一开始 我只顾着看你, 装做不经意 心却飘过去"]
  a -- b;
  b -- c;
}

统一设置点线的样式

digraph easy{
	rankdir = LR;
	node [color=Red,shape=egg]
	edge [color=Pink, style=dashed]
  a -> b;
  b -> c;
  a -> c;
  c -> d;
	a -> d;
}

加点颜色

digraph easy{
	bgcolor=Pink;
	b [style=filled, fillcolor=yellow, center=true]
  a->b;
}

禁用关键词

下面的关键词,不区分大小写,不能作为节点的名字,如果你用了,你的图就画不出来

 nodeedgegraphdigraphsubgraph, and strict

下面的写法会导致绘图失败

graph a {
 node -- edge
}

但是关键词可以作为Label

graph a {
	a [label="node"]
  b [label="edge"]
	a -> b
}

快捷方式 - 串起来

# 方式1 两点之间一个一个连接
digraph {
	a -> b;
  b -> c;
  c -> d;
}

# 方式2 直接串起来所有的点
digraph {
	a -> b -> c -> d;
}

# 方式3 直接串起来所有的点, 也可换行
digraph {
	a->b 
  ->c
  ->d
  ->e;
}

对比发现,直接串起来的话,更简单,速度更快。对于无向图 也可以用 a -- b -- c -- d 的方式串起来。

快捷方式 - 大括号

对于上面的图,也有两种绘制方法。用大括号的方式明显更好呀! 😺

# 方式1 
digraph {
	a -> b;
	a -> c;
	a -> d;
	b -> z;
	c -> z;
	d -> z;
}

# 方式2
digraph {
	a -> {b;c;d}
	{b;c;d} -> z
}

数据结构 UML 怎么画呀?

比如说下面的typescript数据结构

interface Man {
	name: string;
  age: number;
  isAdmin: boolean
}

interface Phone {
	id: number;
  type: string;
}

注意:node [shape=“record”]

digraph {
	node [shape="record"]
	man[label="{Man|name:string|age:number|isAdmin:boolean}"]
	
	phone[label="{Phone|id:number|type:string}"]
}

数据结构之间的关系如何表示? 锚点

例如Man类型有个字段phone, 是Phone类型的

interface Man {
	name: string;
  age: number;
  isAdmin: boolean
  phone: Phone
}

interface Phone {
	id: number;
  type: string;
}

interface Plain {
	key1:aaa;
  key2:bbb;
}

注意lable里面的内容,其中<>这个符号可以理解为一个锚点。

man:age->plain:key1  这个意思是man的age锚点连接到plain的key1锚点。

digraph {
	node [shape="record"]
	man[label="{Man|name:string|<age>age:number|isAdmin:boolean|<phone>phone:Phone}"]
	phone[label="{Phone|id:number|<type>type:string}"]
	plain[label="{Plain|<key1>key1:aaa|key2:bbb}"]
	
	man:phone->phone
	man:age->plain:key1 [color="red"]
	phone:type->plain:key1
}

hash 链表

digraph {
rankdir=LR;
node [shape="record",height=.1, width=.1];

node0 [label = "<f0>a |<f1>b |<f2>c|", height=2.5];

node1 [label = "{<n> a1 | a2 | a3 | a4 |<p> }"];
node2 [label = "{<n> b1 | b2 |<p> }"];
node3 [label = "{<n> c1 | c2 |<p> }"];

node0:f0->node1:n [headlabel="a link"]
node0:f1->node2:n [headlabel="b link"]
node0:f2->node3:n [headlabel="c link"]
}

label {}的作用

digraph {
	node [shape="record"];
	node0 [label = "0|a|b|c|d|e",height=2.5];
	node1 [label = "{1|a|b|c|d|e}",height=2.5];
}

对于record而言

  • 有{} , 则属性作用于整体
  • 无{}, 则属性作用于个体

分组子图

  • subgraph 关键词标记分组
  • 组名必需以cluster开头
graph {
  rankdir=LR
  node [shape="box"]

  subgraph cluster_1 {
    label="network1";
    bgcolor="mintcream";
    host_11 [label="router"];
    host_12;
    host_13;
  }

  subgraph cluster_2 {
    label="network2";
    bgcolor="mintcream";
    host_21 [label="router"];
    host_22;
    host_23;
  }

  host_12--host_11;
  host_13--host_11;

  host_11--host_21;

  host_22--host_21;
  host_23--host_21;
}

流程图

二等车厢座位示意图

digraph{
	label="二等车厢座位示意图"
	node [shape=record];
  struct3 [
	shape=record,
	label="车窗|{
	{01A|01B|01C}|
	{02A|02B|02C}|
	{03A|03B|03C}
	}
	|过道|{
	{01D|01F}|
	{02D|02F}|
	{03D|03F}
	}|车窗"
	];
}

Node Port

可以使用nodePort来调整目标的连接点, node Port可以理解为地图上的东南西北。

      n
      |
w<----+----> e
      |
      s
digraph {
	rankdir=LR
	node [shape=box]
	
	a->b:n [label=n]
	a->b:ne [label=ne]
	a->b:e [label=e]
	a->b:se [label=se]
	a->b:s [label=s]
	a->b:sw [label=sw]
	a->b:w [label=w]
	a->b:nw [label=nw]
}

电磁感应线圈

<>可以用来自定义锚点,锚点可以用来连线。

digraph{
	node [shape=record];
	edge[style=dashed]

	t [style=filled;fillcolor=gray;label="<l>N| |||||||<r>S"]

	t:l->t:r [color=red]
	t:l->t:r[color=red]
	t:l->t:r[color=red]
	t:l->t:r[color=red]
	t:l->t:r[color=red]
	t:r:s->t:l:s[color=green]
	t:r:s->t:l:s[color=green]
	t:r:s->t:l:s[color=green]
	t:r:s->t:l:s[color=green]
	t:r:s->t:l:s[color=green]
}

三体纠缠

digraph{
nodesep=.8
ranksep=1
rankdir=TD
node[shape=circle]
edge [style=dashed]


a[style=filled;fillcolor=red;label="";color=red]
b[style=filled;fillcolor=red2;label="";color=red2]
c[style=filled;fillcolor=red4;label="";color=red4]

a->b[color=red]
a->c[color=green]
a->b[color=red]
a->c[color=green]
a->b[color=red]
a->c[color=green]


b->c[color=orange]
b->a[color=red]
b->c[color=orange]
b->a[color=red]
b->c[color=orange]
b->a[color=red]

c->a[color=green]
c->b[color=orange]
c->a[color=green]
c->b[color=orange]
c->a[color=green]
c->b[color=orange]
}

二叉树

digraph {
	node [shape = record,height=.1];
	t0 [label="<l>|9|<r>"]
	t1 [label="<l>|1|<r>"]
	t5 [label="<l>|5|<r>"]
	t6 [label="<l>|6|<r>"]
	t11 [label="<l>|11|<r>"]
	t34 [label="<l>|34|<r>"]
	t0:l->t5
	t0:r->t11
	t5:l->t1
	t5:r->t6
	t11:r->t34
}

水平分层

相关的节点,可以使用rank属性,使其分布在相同的水平层次。

digraph{
	nodesep=.3
	ranksep=.8
	node [shape=none]
	应用层 -> 运输层 -> 网络层 -> 链路层;

	node [shape=box];
	http;websocket;sip;ssh;
	tcp;udp;
	icmp;ip;igmp;
	arp;rarp;
	
	{rank=same;应用层;http;websocket;sip;ssh}
	{rank=same;运输层;tcp;udp}
	{rank=same;网络层;icmp;ip;igmp}
	{rank=same;链路层;arp;硬件接口;rarp}
	
	http->tcp
	websocket->tcp;
	sip->tcp;
	sip->udp;
	ssh->tcp;
	tcp->ip;
	udp->ip;
	ip->igmp;
	icmp->ip;
	ip->硬件接口;
	arp->硬件接口;
	硬件接口->rarp;
}

最后挑战,画个小人

digraph easy{
	nodesep = 0.5
	header [shape=circle, label="^_^", style=filled, fillcolor=pink]
	body [shape=invhouse, label="~ ~\n~ ~\n~ ~", center=true, style=filled, fillcolor=peru]
	leftHand [shape=Mcircle, label="", style=filled, fillcolor=palegoldenrod]
	rightHand [shape=Mcircle, label="", style=filled, fillcolor=palegoldenrod]
	
	leftFoot [shape=egg, label="", style=filled, fillcolor=palegoldenrod]
	rightFoot [shape=egg, label="", style=filled, fillcolor=palegoldenrod]
	
  header->body [arrowhead=crow];
	body->leftHand [arrowhead=invodot, penwidth=3, color=cornflowerblue, tailport=ne];
	body-> rightHand [arrowhead=invodot, penwidth=3, color=cornflowerblue, tailport=nw];
	
	body -> leftFoot [arrowhead=tee, penwidth=5, color=cornflowerblue]
	body -> rightFoot [arrowhead=tee, penwidth=5, color=cornflowerblue]
}

还有那些颜色可以使用呢?

颜色预览:http://www.graphviz.org/doc/info/colors.html

还有那些箭头的样式可以用呢?

我的图没预览出来,怎么办?

一般来说,如果图没有渲染出来,都是因为绘图语法出问题了。

我刚刚开始用的时候,就常常把–用在有向图中,导致图无法预览。建议官方可以把报错信息提示给用户。

目前来说,这个错误信息只在控制台中打印了,需要按F12打开浏览器的console界面。看看哪里出错了,然后找到对应的位置修改。

参考

附件

dotguide.pdf