图片来源: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
// Date: 2010-06-21
// Author: Emden R. Gansner
// From: [[email protected]]
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 国际许可协议进行许可。