DOT语言(graph description language)

图片来源:https://www.pixiv.net/artworks/97882990

基本

文件后缀

.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给子图渲染一个边框,设置方法有两种

  1. 子图命名以“cluster”开头
  2. “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 国际许可协议进行许可。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注