『dot 学习笔记』一. 基础概念

LiYanrui posted @ Nov 07, 2008 10:35:42 PM in 数据可视化 with tags dot graphviz , 30472 阅读

dot 是一种绘图语言,它可以方便你采用图形的方式快速、直观地表达一些想法,比如描述某个问题的解决方案,构思一个程序的流程,澄清一堆貌似散乱无章的事物之间的联系……等等。总之,当你打算使用铅笔在纸上乱画一些圈圈框框并用一些带箭头的线将它们联系起来的时候,不妨考虑一下使用 dot 来完成这个工作。

安装

dot 是 graphviz 软件包的一部分,这个 graphviz 是大名鼎鼎的贝尔实验室中的科学家们开发的,所以当我开始使用 dot 涂鸦的时候,感觉自己也很科学起来。graphviz 被很多 Unix-like 发行版的软件仓库收录了,因此 Unix-like 系统用户们略微动动手指即可拥有它。如果是 Windows 用户,也可以在 graphiviz 官方网站的下载页面上获得 Windos 版本。

dot 一下 Hello world

下面,在我好为人师的过程中,我假定你已经正确安装了 graphviz。至于怎样验证已经正确安装了,这就是下面的 Hello World 要做的。

首先用你喜欢的文本编辑器(呆会我会建议你使用 Emacs 来写 dot 文件)建一个名为 hello.dot 的文件(或许应该要用 utf-8 编码),在其中填写以下内容:

graph hello {
        Node1 [label="Hello, World!"]
}

然后,在终端中使用 dot 命令编译这个文件: 

$ dot -Tpng hello.dot -o hello.png

其中,dot 命令的 '-T' 选项及其 'png' 参数告诉 dot 要将 hello.dot 文件编译输出为 png 格式的图形文件 hello.png,如下图所示:

如果你高兴,你也可以将 '-T' 选项的参数设置为 'pdf', 'svg, 'gif, 'dia'…… 至于 dot 具体有支持哪些格式的图形输出,可以通过 'man dot',查看 'OUTPUT FORMATS' 一节内容获知。

对我而言,最欣赏的是 dot 可以输出 'dia' 格式,这让我可以在 dia 这个软件中去对 dot 图形进行后续的一些调整或修改。不过,目前所导出的 dia 格式文档还不是很标准。dot 的文档中推荐使用 dotty 工具作为 GUI 工具直接对 dot 源文档进行调整。但是,我感觉 dotty 实在太丑陋。

dot 图形的基本结构

dot 所绘制的图形,其主要成分可以概括为:图、结点、边、标注。下面几个小例子可以帮助你理解这些概念。

首先来看一个只有图、结点和边的 dot 图形:

digraph test1{
    A -> B;    A -> C;   B -> D;    C -> D
}

digraph 是 dot 用于定义有向图的命令,在这里它定义了一幅名为 test1 的有向图,花括号中所包含的内容即为该有向图的内容,也就是结点和边。A, B, C, D 均为结点,而 '->' 符号表示有向边,从一个结点指向另一个结点。代码中的分号并非必须,只有你在将多行绘图语句放置在一行代码中的时候才需要用分号了隔离绘图语句。

从上述代码可见,你只需要将结点之间的关系告诉 dot,至于 dot 如何来绘制这幅图形,那不是你应该关心的,或许你想不到 dot 居然给出了如下图所示的输出,这或许与你原来的设想有些不一样,比如你可能是希望结点的分布是从左向右的,而不是从上向下的(其实也可以调整成从左向右的,但这是后话)。

dot 的图也可以是无向图,使用 graph 命令来定义。比如,将上例改写成无向图:

 

graph test2{
    A -- B;    A -- C;   B -- D;    C -- D
}

无向图与有向图的区别除了使用的定义命令不同之外,边的符号也由原来的 '->' 变为 '--'. 上例无向图输出如下图所示:

知道了这些,我们已经有了绘制 dot 图形的能力了,可以谈笑间绘出以下这幅图形来:

digraph test4 {
    main -> parse -> execute
    main -> init
    main -> cleanup
    execute -> make_string
    execute -> printf
    init -> make_string
    main -> printf
    execute -> compare
}

图形元素的属性

图、结点、边都可以进行许多属性方面的设置,这些属性主要用于改善图形的外观。我不鼓励你在设置 dot 图形元素属性方面投入很多的精力,因为 dot 图主要是用来达意的。除非你认为必须要对某些 dot 图形元素属性进行一些调整,如果不这样做,dot 图形就无法充分体现你的意图。下面通过一些很简化的示例来说明 dot 图形属性设定方式,具体的细节尚需要查看 dot 文档并动手尝试才可以获知。

图的属性

现在对一幅 dot 图形提出了以下外观的要求:

  1. 结点的布置是从左向右的
  2. 图带有标签,字体为 10pt

按照上述要求,再对照着『Drawing graphs with dot』文档的表 3(即图的属性表),可以很轻易地写出以下代码:

digraph g_attr_01 {
        rankdir = LR
        fontsize = 10
        label = "图的属性设置示例"
       
        A -> B -> C -> D
}

结果如下图所示:

结点的属性

对于上例中的图形,进一步提出以下外观要求:

  1. 要求结点的形状是矩形
  2. 边框颜色为绿色
  3. 结点背景为浅蓝色
  4. 字号为 10pt

对照着『Drawing graphs with dot』文档的表 3(即图的属性表),则可以很轻易地写出以下代码:

digraph g_attr_01 {
        rankdir = LR
        fontsize = 10
        label = "结点的属性设置示例"
       
        node [shape=box,style=filled, fillcolor=".7 .3 1.0", color=green, fontsize=10]
       
        A -> B -> C -> D
}

结果见下图:

由上例可见,使用在 node 命令的参数中所设置的结点属性会影响到其后所有的结点。有时候,我们需要单独设置某个结点的属性。譬如,要将结点 B 的形状设置为圆形,边框为红色并且不要背景填充,具体设置见下例:

digraph g_attr_01 {
        rankdir = LR
        fontsize = 10
        label = "结点的属性设置示例"
       
        node [shape=box,style=filled, fillcolor=".7 .3 1.0", color=green, fontsize=10]
       
        A -> B -> C -> D
       
        B [shape = circle, color = red, style=solid]
}

到目前位置,图形中结点的文本一直是默认使用它的 ID,事实上我们可以设定结点的 label 属性来显示我们期望显示的文本。譬如:

digraph g_attr_01 {
        rankdir = LR
        fontsize = 10
        label = "结点的属性设置示例"
       
        node [shape=box,style=filled,
                  fillcolor=".7 .3 1.0", color=green,fontsize=10]
       
        A -> B -> C -> D
       
        B [shape = circle, color = red, style=solid, label="我是结点"]
}

边的属性

以我个人的审美标准来判断,上述所有示例输出的图形有一个特点,那就是有向边的箭头过大。这可以通过设置边的属性进行调整。dot 图形的边属性可以从『Drawing graphs with dot』文档的表 2 查阅。下面的例子将箭头大小调整为默认大小的 0.5 倍。

digraph g_attr_01 {
        rankdir = LR
        fontsize = 10
        label = "边的属性设置示例"
       
        node [shape=box,style=filled,
                  fillcolor=".7 .3 1.0", color=green,fontsize=10]
        edge [arrowsize= .5]
       
        A -> B -> C -> D
       
        B [shape = circle, color = red, style=solid, label="我是结点"]
}

下面看一下如何设置边的标注 label 属性:

digraph g_attr_01 {
        rankdir = LR
        fontsize = 10
        label = "边的属性设置示例"
       
        node[shape=box,style=filled,
                  fillcolor=".7 .3 1.0", color=green,fontsize=10]
        edge[arrowsize= .5, fontsize=10]

        A -> B[label="进入"]
        B -> C -> D
       
        B [shape = circle, color = red, style=solid, label="我是结点"]
}

在上例中,首先将边的标注字号设置为 10pt,然后为路径 A -> B 上的边添加了一个“进入”的标注。

bobye 说:
2008年11月29日 09:01

顶一下!赞一个!

helloworld 说:
2012年7月27日 16:47

受教了!

keroro 说:
2014年3月11日 11:23

一般的用法都涉及到了,赞一个!


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter