图片来源:https://www.pixiv.net/artworks/97882990
Table of Contents
基本
文件后缀
.dot
或者.gv
节点和边
digraph graphname{
// Node
node1
node2
// Edge
node1 -> node2
}
无向图
graph graphname {
a -- b -- c;
b -- d;
}
有向图
digraph graphname {
a -> b -> c;
b -> d;
}
注释
// C风格单行注释
/* C风格
多行
注释 */
# Shell风格注释
命令行渲染命令
dot -Tsvg input.dot > output.svg
子图(subgraph)和集群(cluster)
可以用“{}”创建一个匿名的子图,仅仅起到语句块的作用
digraph graphname {
a -> {b,c}
}
可以给子图设置“集群
”属性让graphviz给子图渲染一个边框,设置方法有两种
- 子图命名以“cluster”开头
- “cluster=true”(VSCode的插件“Graphviz (dot) language support for Visual Studio Code”不认这个属性)
digraph cats {
subgraph cluster_big_cats {
// This subgraph is a cluster, because the name begins with "cluster"
"Lion";
"Snow Leopard";
}
subgraph domestic_cats {
// This subgraph is also a cluster, because cluster=true.
cluster=true;
"Siamese";
"Persian";
}
subgraph not_a_cluster {
// This subgraph is not a cluster, because it doesn't start with "cluster",
// nor sets cluster=true.
"Wildcat";
}
}
子图中定义的节点也是全局共享的
digraph graphname{
subgraph cluster_1 {
node1
node2
}
subgraph cluster_2 {
node1 -> node3
}
}
属性(Attributes)
方向
属性名:rankdir
作用:设置渲染开始方向
可选值:TB(
默认), LR
, BT
, RL
graph graphname {
rankdir = RL; // Right to Left
a -- b -- c;
b -- d;
}
graph graphname {
rankdir = BT; // Bottom to Top
a -- b -- c;
b -- d;
}
标签
属性名:lable
作用:设置图、子图、节点、边等显示的内容
digraph plants{
label="Plants"
subgraph cluster_flowers {
label="Flowers"
sf [label="Sunflowers"]
ab [label="Almond Blossom"]
}
subgraph cluster_Bambusoideae {
label="Bambusoideae"
sht [label="bamboo shoot"]
bam [label="bamboo"]
sht -> bam [label="grow into"]
}
}
节点形状
属性名:shape
作用:设置节点形状
可选值:值较多,参看https://graphviz.org/doc/info/shapes.html#polygon

其他
Graphviz画树的输出优化脚本
graph tree {
node [shape=circle]
0 -- 1
0 -- 2
1 -- 3
1 -- 4
2 -- 5
2 -- 6
}
优化命令,其中tree.g文件即为Emden Gansner大佬的优化脚本
dot tree.dot | gvpr -c -ftree.g | neato -n -Tsvg -otree_1.svg
tree.g// Date: 2010-06-21 // Author: Emden R. Gansner // From: [graphviz-interest@research.att.com] BEGIN { double tw[node_t]; // width of tree rooted at node double nw[node_t]; // width of node double xoff[node_t]; // x offset of root from left side of its tree double sp = 36; // extra space between left and right subtrees double wd, w, w1, w2; double x, y, z; edge_t e1, e2; node_t n; } BEG_G { $.bb = ""; $tvtype=TV_postfwd; // visit root after all children visited } N { sscanf ($.width, "%f", &w); w *= 72; // convert inches to points nw[$] = w; if ($.outdegree == 0) { tw[$] = w; xoff[$] = w/2.0; } else if ($.outdegree == 1) { e1 = fstout($); w1 = tw[e1.head]; tw[$] = w1 + (sp+w)/2.0; if (e1.side == "left") xoff[$] = tw[$] - w/2.0; else xoff[$] = w/2.0; } else { e1 = fstout($); w1 = tw[e1.head]; e2 = nxtout(e1); w2 = tw[e2.head]; wd = w1 + w2 + sp; if (w > wd) wd = w; tw[$] = wd; xoff[$] = w1 + sp/2.0; } } BEG_G { $tvtype=TV_fwd; // visit root first, then children } N { if ($.indegree == 0) { sscanf ($.pos, "%f,%f", &x, &y); $.pos = sprintf("0,%f", y); } if ($.outdegree == 0) return; sscanf ($.pos, "%f,%f", &x, &y); wd = tw[$]; e1 = fstout($); n = e1.head; sscanf (n.pos, "%f,%f", &z, &y); if ($.outdegree == 1) { if (e1.side == "left") n.pos = sprintf("%f,%f", x - tw[n] - sp/2.0 + xoff[n], y); else n.pos = sprintf("%f,%f", x + sp/2.0 + xoff[n], y); } else { n.pos = sprintf("%f,%f", x - tw[n] - sp/2.0 + xoff[n], y); e2 = nxtout(e1); n = e2.head; sscanf (n.pos, "%f,%f", &z, &y); n.pos = sprintf("%f,%f", x + sp/2.0 + xoff[n], y); } }
参考:

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。