数据结构与算法可视化(二)——DOT用法 | 八月更文挑战

1,009 阅读4分钟

DOT中使用图(digraph/graph/subgraph)、节点(node)和边(edge)来描述关系图/流程图,在配合一些属性的设置完成绘图。

1、图的基本用法

DOT基本语法如下:

digraph/graph/subgraph graphName{
    label="示例";
    bgcolor="beige"
    ......
}

其中,digraph/graph/subgraph分别代表无向图、有向图和子图,graphName则是图片的名称。

  • digraph用来描述有向图,关系使用 -> 来描述
  • graph 用来描述无向图,关系使用 --来描述
  • labelbgcolor为定义的图片属性
  • graphName定义图片的名称
  • 注释和C语言类似,//# 注释单行, /* */多行注释。
  • DOT的写法不算严格,比如结束可以有分号,属性可以没有引号。

常用图属性

属性名默认值说明
label图片标签,如上面示例
bgcolor背景颜色,颜色文档点此
fontcolorblack字体颜色,定义上面示例的颜色
fontnameTimes-Roman字体
fontsize14字体大小
rank子图等级限制, same,min,max,source,sink
rankdirTB排序方向,LR(left to right) or TB(top to bottom)
compoundfalseIf true, allow edges between clusters. 配合 lhead 和 ltail 使用

2、节点(node)的用法

digraph demo {
    label="示例"
    bgcolor="beige"
​
    //定义节点默认属性
    node[color="grey"]
    //定义节点
    root[label="根节点", shape="box"]
    left[label="左子节点", shape="box"]
    
    node[color="#FF6347"]
    right[label="右子节点", shape="ellipse"]
    
    //定义关系(边)
    root -> {left,right}[label="父子"]
    left -> subnode[label="父子"]
    
    {rank=same; left, right}
}
  • rootleftrightsubnode为节点。节点可以提前定义如root[label="根节点", shape="box"],也可以在定义边的关系时直接使用如left -> subnode[label="父子"]
  • node用来定义节点的默认属性,作用域从本次定义到下一次定义截住。特定节点设置的属性会覆盖默认值。
  • []内属性,属性可以针对图、节点、边来设置。
  • rank 定义设置节点处在同一行,辅助渲染出来的图的效果。

实例图一.png

常用节点属性

属性名默认值说明
labelnode name节点显示内容
colorblacknode边框颜色
fontcolorblack字体颜色
fillcolor背景色
fontnameTimes-Roman字体
fontsize14字体大小
shapeellipse形状,box、ellipse、circle、diamond、plaintext、point、triangle、invtriangle
style图形样式,eg. bold、dashed、dotted、filled
image背景图片地址

shape示例

digraph demo {
    bgcolor="floralwhite"
    "box"[shape=box]
    "polygon"[shape=polygon,sides=7] 
    "ellipse"[shape=ellipse]
    "circle"[shape=circle]
    "point"[shape=point]
    "triangle"[shape=triangle]
    "invtriangle"[shape=invtriangle]
    "plaintext"[shape=plaintext]
    "diamond"[shape=diamond]
}

示例图二.png

3、边(edge)的用法

digraph demo {
    label="示例"
    bgcolor="beige"
​
    //定义节点默认属性
    node[color="grey"]
    //定义节点
    root[label="根节点", shape="box"]
    left[label="左子节点", shape="box"]
    
    node[color="#FF6347"]
    right[label="右子节点", shape="ellipse"]
    
    //定义关系(边)
    root -> {left,right}[label="父子"]
    
    //定义边的默认属性
    edge[color="#FF6347"]
    left -> subnode[label="父子"]
    
    {rank=same; left, right}
}
  • edge用来定义边的默认属性。用法与node相似,作用域从本次定义到下一次定义截住。特定边设置的属性会覆盖默认值。

  • 本质上来说,node和edge也是属于节点,是预留用于描述节点属性和边属性的特殊节点

  • 无向图关系使用--描述,有向图关系使用->描述

示例图三.png

常用边属性

属性名默认值说明
label描述关系
colorblack箭头颜色
fontcolorblack关系文字颜色
dirforward设置方向:forward,back,both,none
arrowheadnormal箭头头部形状。box、crow、diamond、dot、none、normal、vee。箭头文档点此
arrowtail箭头尾部形状
arrowsize1.0箭头大小
style图形样式,eg. bold、dashed、dotted、filled
lhead当 compound 为true时,lhead用于指定边指向的cluster
ltail与ltail类似

arrowhead示例

digraph demo {
    bgcolor="floralwhite"
    rankdir=LR
​
    "box"->"crow"[arrowhead=box]
    "crow"->"curve"[arrowhead=crow]
    "curve"->"diamond"[arrowhead=curve]
    "diamond"->"dot"[arrowhead=diamond]
    "dot"->"inv"[arrowhead=dot]
    "inv"->"none"[arrowhead=inv]
    "none"->"normal"[arrowhead=none]
    "normal"->"tee"[arrowhead=normal]
    "tee"->"vee"[arrowhead=tee]
    "vee"->"box"[arrowhead=vee]
​
    #来个高级的用法
    a->b[arrowhead=lcrowortee]
}

示例图四.png

4、一些例子

子图

一个图可以包含多个子图,以及子图也可以嵌套子图。子图的名字须为cluster*,否则就直接当节点渲染了。

digraph demo {
    bgcolor="beige"
    subgraph cluster_husband {
        node[color="grey"]
        {"爸爸", "妈妈"} -> "我"
    }
     subgraph cluster_wife {
         {"岳父", "岳母"} -> "老婆"
     }
     "我" -> "老婆"[label="夫妻", dir="both"]
     {rank=same; "我", "老婆"}
}

渲染效果如下:

示例图五.png

链表

digraph demo {
    bgcolor="beige"
    rankdir=LR;
    node [shape="record", height=0.1]
    node0[label="{<f1> G | <f2> next}"]
    node1[label="{<f1> E | <f2> next}"]
    node0:f2 -> node1:f1
}
  • rankdir=LR 描述图像为横向
  • 用 | 隔开的串会在绘制出来的节点中展现为一条分隔符
  • 用 <> 括起来的串称为锚点
  • node0[label="{<f1> G | <f2> next}"]中,{}描述同个节点中的多个分割位与rankdir一致

示例图六.png

B树

digraph demo {
    bgcolor="beige"
    node [shape="record", height=.1]
    node0[label="<f1> A | <f2> B | <f3> C | <f4> "]
    node1[label="<f1> D | <f2> E | <f3> F"]
    node2[label="<f1> G | <f2> H | <f3> I"]
    node0:f1 -> node1:f1
    node0:f2 -> node2:f1
}

示例图七.png