zoukankan      html  css  js  c++  java
  • Graphviz

    http://www.linuxidc.com/Linux/2016-05/131049.htm

    简介

    Graphviz 是一个运用广泛的命令行绘图软体,不过说是绘图软体,它能绘的图并不是一般人想像中的漫画或 logo,而是数学意义上的 "graph",比较通俗的说法就是「关系图」。

    举例来说,像是下面这种图:

    Graphviz - 用指令来画关系图吧!

    ▲ 图1:Unix 家族。Graphviz 官网的示范图片之一。

    用手画会很痛苦,而 Graphviz 可以替使用者搞定它。Graphviz 提供一套语言,让您能直接陈述图片上的节点、边、方向等性质。之后,由它来为您产生整张图片。

    Graphviz 能画的图片有许多种,您可在官网挖到更多范例。

    安装

    Graphviz 支援 Windows、Mac OS X、FreeBSD、Solaris、Linux 等多种作业系统。

    若您是 Linux 使用者,基于这款软体的名气,您的套件管理器中几乎一定会有,从套件库中安装吧!倘若真找不到,请看官网下载页面,试试原始码。

    若您是 Windows 用户,请前往这里下载安装档:http://www.graphviz.org/Download_windows.php

    Mac OS X 的使用者请往这边走:http://www.graphviz.org/Download_macos.php

    Graphviz 的使用

    1  # Graphviz
    2  ><cmd> <inputfile> -T <format> -o <outputfile>
    3 
    4  # 举例:输出 png
    5  > dot input.dot -T png -o output.png
    6  # 举例:一样是输出 png,只不过档名是 txt
    7  > dot input.dot -T png -o output.txt
    

    首先,我们看看上面的 <cmd> 部份。

    Graphviz 的 <cmd> 有好几种,每种使用方法都完全相同,差别只在于渲染出来的图片效果不一样。man 中的简介是这样写的......

    dot

    渲染的图具有明确方向性。

    neato

    渲染的图缺乏方向性。

    twopi

    渲染的图採用放射性佈局。

    circo

    渲染的图採用环型佈局。

    fdp

    渲染的图缺乏方向性。

    sfdp

    渲染大型的图,图片缺乏方向性。

    您可以透过 man <cmd> 取得进一步说明。但还是亲自用用比较容易理解。在本文中,凡没有说明的图,预设都是 以 dot 渲染出来的。

    继续往下看。在 Graphviz 中,若您不指定 -T 参数,Graphviz 并不会自动猜测您想要产生什么格式,只会以预设格式渲染。可选格式相当多,包括(但不限于)jpg、png、svg 等,全部列表可见官网说明页的最下方。

    -o 可让您指定储存档案的档名。如果您不用 -o 选项指定输出档名,Graphviz 则会将结果输出到标准输出上。

    除非用法很特殊,否则这两个参数,每次都要记得下达才行。

    dot 语言说明

    指挥 Graphviz 绘图时,所使用的语言叫作 "dot"。下边就来介绍如何使用它。

    有向图与无向图

    使用 dot 语言,第一步就是决定要画哪种图。

    图分两种:有向图与无向图。

    Graphviz - 用指令来画关系图吧!

    ▲ 图2:有向图

    Graphviz - 用指令来画关系图吧!

    ▲ 图3:无向图

    有向图以 digraph 宣告图片,节点间的关系写为 "->"。

    1  /*demo1。顺便一提,在 dot 语言中可使用 C++ 中允许的註解。本行为 C 风格註解*/
    2  digraph demo1{ //这也是註解,C++ 风格的。
    3        a -> b -> c;
    4        c -> a;
    5  }
    

    无向图以 graph 宣告图片,节点间的关系可以写为 "--"。

    1  //demo2
    2  graph demo2{
    3       a -- b -- c;
    4       c -- a;
    5  }
    

    其中 demo1 与 demo2 是图片的名称,一般使用时常常留白不打。

    使用引号

    上文中的 a, b, c 除了作为程式内的识别字以外,也会成为节点的显示名称 (label)。不过如果这名称中混了中文或夹了空格,Graphviz 就有可能搞错你的意思。

    为防不必要的误解,所以平常最好都用英文引号括住。就像下面这样:

    1  //demo3
    2  digraph {
    3      "总 攻" -> "受";
    4      "强 攻" -> "受";
    5      "健气攻" -> "受";
    6  }
    
    Graphviz - 用指令来画关系图吧!

    ▲ 图4:混合了空白的示范,採用 fdp 渲染。

    这样就没问题了!

    子图与简化技巧

    来看个复杂一点的例子,这是一份地中海海域的大略连接图:

    1  graph G{
    2      "黑海" -- "亚速海";
    3      "黑海" -- "博斯普鲁斯海峡"
    4      "达达尼尔海峡" -- "爱琴海"
    5      subgraph cluster_T{ // 新东西
    6          label = "黑海海峡"; // 新东西
    7           "达达尼尔海峡" -- "马尔马拉海" -- "博斯普鲁斯海峡";
    8      }
    9       subgraph cluster_M{
    10          label = "地中海海域";
    11          "中部地中海" -- {"爱琴海" "爱奥尼亚海" "西西里海峡"}; // 也是新东西
    12          "西部地中海" -- {"西西里海峡" "第勒尼安海" "利古里亚海" "伊比利海" "阿尔沃兰海"};
    13          "爱奥尼亚海" -- "亚得里亚海";
    14          "阿尔沃兰海" -- "直布罗陀海峡";
    15     }
    16  }
    
    Graphviz - 用指令来画关系图吧!

    ▲ 图5:地中海海域连接图,使用 fdp 渲染,种子为 8 (-Gstart=8)。

    这张图有些新东西可以看。

    第一个是 subgraph 关键字。一如名字所示,他是用来定义「次级图片」用的。

    次级图片在 dot 的官方文件中常被叫作 cluster subgraph,特指图示中被方框包裹起来的那两块,其定义方式和一般的 graph 非常相似,不过使用上有两件事需要留意:

    1. 他的命名得以 cluster 前缀开头,否则语法虽然能过关,但生不出图面上您预期的效果。
    2. 如果父图是无向图,他本身也得是无向图;反之如果父图是有向图,这边也得乖乖照着来。

    第二个重点是下面这段:

    1        "中部地中海" -- {"爱琴海" "爱奥尼亚海" "西西里海峡"};

    用大括号括起,用空格分开-这是一口气将好几个节点群组起来同时操作的方法,其等效于:

    1        "中部地中海" -- "爱琴海";
    2        "中部地中海" -- "爱奥尼亚海";
    3        "中部地中海" -- "西西里海峡";
    

    您甚至可以用以下程式码画出图6:

    1  digraph G{
    2     {a b c} -> {d e f}
    3  }
    
    Graphviz - 用指令来画关系图吧!

    ▲ 图6:大括号效果示意图

    这语法糖很方便好吃,可以灵活运用。

    第三个不同处在于 label = XXX 这行。这是「属性」的指定方式。

    关于属性,我们下章再讲。

    属性

    有了前面介绍过的技巧,所有图面关系都可以顺利地绘制出来。

    然而,通常我们画图的时候,还会对图片做一些特别的处理。好比说把字加粗、把图变色、把标籤或连接线的外型 改变、把某些节点水平对齐......诸如此类。

    要控制这些东西,就要用到属性。

    属性有四种:

    1. 用在节点上 (Node, N)
    2. 用在线段上 (Edge, E)
    3. 用在根图片上 (Graph, G)
    4. 用在子图片上 (Cluster subgraph, C)

    您可以阅读手册中的表,判断哪些属性能用在哪些地方。

    那么,属性要怎么用呢?

    属性的套用

    如果要设定根图片或子图片的属性,得像前面范例中所示的那样,在图片的大括号范围内指定......

    属性名称=值;

    这样就行了。

    对于节点 (node) 的属性,有以下几种指定法:

    1  节点名 [节点属性名=值];
    2  节点名 [节点属性名=值, 节点属性名=值];
    3  node [节点属性名=值,节点属性名=值];
    

    属性指定的语句必须要被中括号括起。当一次指定多值时,需用英文逗点隔开。

    第三行中的 node 是个关键字,用来代称「图片范围内」所有「还没创建」的节点,或者您也可将它理解为:在当前大括号的范围内,所有尚未创建节点的属性预设值,会被这个语句给变更。

    线段 (edge) 的属性指定,与节点属性指定方式很类似:

    1  节点名 -> 节点名 [线段属性名=值];
    2  节点名 -- 节点名 [线段属性名=值, 线段属性名=值];
    3  edge [线段属性名=值,线段属性名=值];
    

    其中 edge 是关键字。

    这边顺便补充一个关于线段的观念:有些线段相关的属性,具有 head 值与 tail 值。而这边说的 head 与 tail,得将它想 像成一个「箭头」的形状(就像是「a -> b」这样)。

    对于线段来说,这个箭头的头部才是 head。所以啰,这可能和您最初想像的不一样,因为这边说的「Head」其实是 两个节点中,后面的那一个。

    属性范例

    把先前的看过的例子加上一些属性试试。

    1  graph G{
    2      "黑海" [shape = circle, color = blueviolet, fontcolor = blueviolet, fontsize = 20];
    3      "黑海" -- "亚速海" [label = "刻赤海峡"];
    4 
    5      subgraph cluster_T{
    6          label = "黑海海峡";
    7          fontsize = 24;
    8          fillcolor = darkslategray;
    9          style = filled;
    10         fontcolor = white;
    11         node [fontcolor = white, color = white];
    12         "博斯普鲁斯海峡" -- "马尔马拉海" -- "达达尼尔海峡" [color = white];
    13         "博斯普鲁斯海峡" [shape = parallelogram];
    14         "达达尼尔海峡" [shape = parallelogram];
    15     }
    16 
    17      "黑海" -- "博斯普鲁斯海峡" [color = red ,penwidth = 2];
    18      "达达尼尔海峡" -- "爱琴海" [color = red ,penwidth = 2];
    19 
    20      subgraph cluster_M{
    21          label = "地中海海域";
    22          fontsize = 24;
    23          "西部地中海" [shape = Mcircle, style = filled, color = grey, fillcolor = aquamarine, fontsize = 20];
    24          "中部地中海" [shape = Mcircle, style = filled, color = grey, fillcolor = aquamarine, fontsize = 20];
    25          "直布罗陀海峡" [shape = parallelogram, fontcolor = red];
    26          "西西里海峡" [shape = parallelogram];
    27          "中部地中海" -- {"爱琴海" "爱奥尼亚海" "西西里海峡"};
    28          "西部地中海" -- {"西西里海峡" "第勒尼安海" "利古里亚海" "伊比利海" "阿尔沃兰海"};
    29          "爱奥尼亚海" -- "亚得里亚海";
    30          "阿尔沃兰海" -- "直布罗陀海峡";
    31      }
    32  }
    
    Graphviz - 用指令来画关系图吧!

    ▲ 图7:地中海海域连接图(加入属性)。使用 fdp 渲染,种子为 3 (-Gstart=3)。

    诸多属性中,最常用的大概是 label 了。

    label 可以决定节点、线段或子图片上要显示些什么。如果您的节点名很长的话,可以在程式内部取个简短的名称, 之后透过短名称操作它,另外透过 label 指定它的显示内容。

    color、fillcolor、fontcolor 这些属性都是控制颜色用的,不过 fillcolor 只有在 style 被指定为 "filled" 时才会生效。

    shape 可以指定节点的形状,形状列表官网这边有一份资料可参考。

    线段属性方面。有向图中的箭头可透过 arrowhead 与 arrowtail 属性来指定头尾样式。至于线段本身,则可透过 style 属 性,指定不同类型的虚线与短截线。使用者还可以用 dir 属性让箭头方向反过来。

    另外还有一个 image 属性,可以指定让 node 显示图片,需要时也可参考看看。

    ......属性实在太多,无法一一介绍,请查官网手册获得全面讯息

    rank

    dot 语言中有一个叫作 rank 的概念。

    所谓的 rank,在 dot 语言中,含意比较接近于「等级」。他主要用在 dot 渲染器中。

    请看以下的图:

    Graphviz - 用指令来画关系图吧!

    ▲ 图8:rank 示例。

    很明显可以看出来,图片被从上到下分为四层-这就是 rank。

    下方是与上图对应的 dot 陈述......

    1  digraph demo{
    2     a -> b -> c -> d;
    3     b -> {e f};
    4  }
    

    观察程式码,可看出 rank 是如何被指定的。

    其基本规则在于:每个线段的头端,都会比尾端多出一个等级(在图上面就是往下面一层)。

    但等等,如果等级指定的语句彼此矛盾呢?

    修改以上程式码为......

    1  digraph demo{
    2     a -> b -> c -> d [label = "rank 增加"];
    3     b -> {e f} [label = "rank 增加"];
    4     f -> a [label = "不影响 rank"];
    5  }
    
    Graphviz - 用指令来画关系图吧!

    ▲ 图9:rank 示例。

    看上面的结果,显然 rank 的指定是「先说先赢」的。

    除了基本规则外,rank 也可以透过属性来加以调节,有必要时就把手册抓出来查查看。 

    参考资料

    1. 官网属性手册,要查属性就来这看:
      http://www.graphviz.org/content/attrs
    2. 官网纯文字版 Graphviz 使用说明兼 dot 语言手册:
      http://www.graphviz.org/doc/Dot.ref
    3. 如果您偏好 pdf 版本的说明书,请到这边下载:
      http://www.graphviz.org/doc/dotguide.pdf

  • 相关阅读:
    komodo install on ubuntu
    关于scrapbook的导入导出
    hg常用命令小记

    在cygwin使用python
    命运多cuai
    常用shell命令
    360做电视广告了
    ubuntu im安装
    ubuntu下的路径
  • 原文地址:https://www.cnblogs.com/ztguang/p/12644531.html
Copyright © 2011-2022 走看看