graphviz 程序生成多种类型图表详解
简介
一幅图抵得上千言万语,这在描述复杂的计算机系统时尤为正确。当系统环境变得更加复杂时,用图将它们表示出来并记入文档就显得更加重要。例如,虚拟化技术有很多优点,但它们通常会让环境变得更加复杂和更难理解。Graphviz 是一个可以创建图表的灵活应用程序,可以轻松实现脚本化。本文将介绍 Graphviz 的安装、使用,以及其中使用 DOT 语言的基础知识,并提供了一些示例脚本。本文有助于您了解 Graphviz 应用程序的基础知识,以及如何编写自动创建图表的脚本。
还有另外一个我觉得更加牛逼的作用,在使用 markdown 时无法直接将图片直接粘贴上去,还得想办法将图片传到某一个中间服务再引入,有么有?而 graphviz 可以完美的解决这个问题,在 markdown 中也可以直接编写相应的代码生成相应的图表,使用起来相当 easy,越用越 happy。
针对 graphviz 想要了解更加详细内容,请查看其对对应的 官方网址
安装 graphviz
Graphviz 是一个开源工具,可以运行在类似于 UNIX® 的大多数平台和 Microsoft® Windows® 之上。graphviz 支持 Windows、Mac OS X、FreeBSD、Solaris、Linux 等多种系统
- Ubuntu 或 Debian 下安装:
1 2 3 | sudo apt-get install graphviz 或 sudo yum install graphviz |
- Mac 下安装使用 brew 命令:
我本人 mac 上安装的时候并没有装 ruby,故需要先安装 ruby 再进行安装 graphviz
1 2 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null ; brew install caskroom /cask/brew-cask 2> /dev/null brew install graphviz |
- Windows 下安装:
由于本人一直使用的是 mac 和 linux,故此次试验并没有在 windows 上做验证,请查看官方文档进行安装。
DOT 语言基础
安装 Graphviz 之后,就可以开始使用工具创建图表,第一步是创建一个 DOT 文件。该 DOT 文件是一个文本文件,描述了图表的组成元素以及它们之间的关系,以便该工具可以生成这些组成元素和它们之间的关系的图形化表示。
1. 编写以 dot 为后缀的源代码文件 hello.dot,内容如下:
1 2 3 | digraph { hello -> world; } |
2. 使用 dot 命令编译
1 | dot hello.dot -T png -o hello.png |
完整的命令格式为:
1 | <cmd> <inputfile> -T <format> -o <outputfile> |
其中graphviz 的 <cmd>
有好几种,每种使用方法都完全相同,差别只在于渲染出来的图片效果不一样。 man
中的简介是这样的
<cmd> | 介绍 |
---|---|
dot | 渲染的图具有明确方向性。 |
neato | 渲染的图缺乏方向性。 |
twopi | 渲染的图采用放射性布局。 |
circo | 渲染的图采用环型布局。 |
fdp | 渲染的图缺乏方向性。 |
sfdp | 渲染大型的图,图片缺乏方向性。 |
可以透过 man <cmd>
取得进一步说明。但还是亲自用用比较容易理解。在本文中,凡没有说明的图,预设都是以 dot
渲染出来的。
3. 查看效果
运行 2 中的命令后会生成对应的 png 文件,双击打开查看效果如下所示:
基础应用
1. 编写一个案例 dot 文件为:example1.dot
1 2 3 4 5 | graph example1 { Server1 -- Server2 Server2 -- Server3 Server3 -- Server1 } |
上述内容中共有三个节点(Server1、Server2 和 Server3)。--
定义了节点之间的联系。这个使用 DOT 语言的例子说明,Server2、 Server2 连接到 Server3,而 Server3 连接到 Server1。
创建 DOT 文件后,可以运行 dot
命令来生成图表,如 2 中所示。–
T png
将输出格式指定为 PNG,而 –o example1.png
指定必须将输出保存到一个名叫 example1.png 的文件中。
2. 从 DOT 文件生成图像
1 | $ dot example1.dot –T png –o example1.png |
生成的图表如下:
第一个示例 (example1.dot) 描述了一个无向图,即用不带箭头的直线表示节点之间的联系的图。
有向图不仅能表示节点之间的联系,而且能用箭头表示节点之间流动的方向。要创建有向图,可以在 DOT 文件的第一行上指定 digraph
而非 graph
,并在节点之间使用 ->
,而不是 --
。
3. 生成有向图,创建 dot 文件:example2.dot
1 2 3 4 5 | digraph example2 { Server1 -> Server2 Server2 -> Server3 Server3 -> Server1 } |
使用 dot 命令生成对应的图表如下:
你也可以轻松控制图中每个节点的形状、颜色和标签。具体方法是列出每个节点的名称,然后将选项放在名称后面的括号中。例如,代码行
1 | Server1[shape=box, label= "Server1\nWebServer" , fillcolor= "#ABACBA" , style=filled] |
定义了 Server1 节点应该是一个长方形,有一个 Server1\nWeb Server 标签(\n 表示一个新行),颜色设为十六进制 (hex) 颜色 #ABACBA,而且该颜色应该填充了节点。
4. 生成有颜色和形状的图表
创建 dot 文件:example3.dot
1 2 3 4 5 6 7 8 9 | digraph example3 { Server1 -> Server2 Server2 -> Server3 Server3 -> Server1 Server1 [shape=box, label= "Server1\nWeb Server" , fillcolor= "#ABACBA" , style=filled] Server2 [shape=triangle, label= "Server2\nApp Server" , fillcolor= "#DDBCBC" , style=filled] Server3 [shape=circle, label= "Server3\nDatabase Server" , fillcolor= "#FFAA22" , style=filled] } |
对应的生成相应图表如下:
编写脚本创建 Graphviz 图表
在了解了 Graphviz DOT 语言的基础知识之后,您可以开始创建脚本,从而动态创建一个 DOT 文件。这允许您动态创建始终准确且保持最新的图表。
以下示例是一个 bash shell 脚本(hmc_to_dot.sh),它连接到 Hardware Management Console (HMC),收集托管服务器和逻辑分区 (LPAR) 的相关信息,然后使用这些信息来创建 DOT 输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/bin/bash HMC= "$1" serverlist=` ssh -q -o "BatchMode yes" $HMC lssyscfg -r sys -F "name" | sort ` echo "graph hmc_graph{" for server in $serverlist; do echo " \"$HMC\" -- \"$server\" " lparlist=` ssh -q -o "BatchMode yes" $HMC lssyscfg -m $server -r lpar -F "name" | sort ` for lpar in $lparlist; do echo " \"$server\" -- \"$lpar\" " done done echo "}" |
通过提供一个 HMC 服务器名称作为参数传递给脚本,便可运行此脚本。该脚本将传递的第一个参数设置为 serverlist 变量的方法是连接到 HMC 并获得该 HMC 控制的所有托管服务器的清单。在这些托管服务器上进行循环,而脚本将为每台托管服务器打印一行 "HMC" -- "server" ,这表明 Graphviz 在每台 HMC 与其托管服务器之间绘制了一条直线。此外针对每台托管服务器,脚本再次连接到 HMC 并获得该托管系统上的 LPAR 清单,然后通过它们循环打印一行 "server" -- "LPAR"。这表明 Graphviz 在每台托管服务器与其 LPAR 之间都绘制了一条直线。(此脚本要求您在运行脚本的服务器与 HMC 之间设置 Secure Shell (SSH) 密钥身份验证)。
命令执行如下:
1 | . /hmc_to_dot .sh hmc_name |
以上执行对应输出的内容如下所示:
1 2 3 4 5 6 7 8 9 10 11 | graph hmc_graph{ "hmc01" -- "test520" "test520" -- "lpar2" "test520" -- "lpar3" "hmc01" -- "test570" "test570" -- "aixtest01" "test570" -- "aixtest02" "test570" -- "aixtest03" "hmc01" -- "test510" "test510" -- "lpar1" } |
你可以轻松从脚本生成图,具体方法是运行以下命令:
1 | . /hmc_to_dot .sh hmc_server_name | dot -T png -o hmc_graph.png |
运行脚本,该脚本会动态创建 DOT 语言,然后将这些输出传递给 dot 命令,以便让它创建一个文件名为 hmc_graph.png 的图表。下图显示了创建的图表。
基础语法总结(供有识之士参考)
具体的图说明内容包含属性(attr)、节点(node)、边(edge)和子图(subgraph)说明。
节点属性如下 :
Name | Default | Values |
---|---|---|
color | black | node shape color |
comment | any string (format-dependent) | |
distortion | 0.0 | node distortion for shape=polygon |
fillcolor | lightgrey/black | node fill color |
fixedsize | false | label text has no affect on node size |
fontcolor | black | type face color |
fontname | Times-Roman | font family |
fontsize | 14 | point size of label |
group | name of node’s group | |
height | .5 | height in inches |
label | node name | any string |
layer | overlay range | all, id or id:id |
orientation | 0.0 | node rotation angle |
peripheries | shape-dependent | number of node boundaries |
regular | false | force polygon to be regular |
shape | ellipse | node shape; see Section 2.1 and Appendix E |
shapefile | external EPSF or SVG custom shape file | |
sides | 4 | number of sides for shape=polygon |
skew | 0.0 | skewing of node for shape=polygon |
style | graphics options, e.g. bold, dotted, filled; cf. Section 2.3 | |
URL | URL associated with node (format-dependent) | |
width | .75 | width in inches |
z | 0.0 | z coordinate for VRML output |
边框属性:
Name | Default | Values |
---|---|---|
arrowhead | normal | style of arrowhead at head end |
arrowsize | 1.0 | scaling factor for arrowheads |
arrowtail | normal | style of arrowhead at tail end |
color | black | edge stroke color |
comment | any string (format-dependent) | |
constraint | true | use edge to affect node ranking |
decorate | if set, draws a line connecting labels with their edges | |
dir | forward | forward, back, both, or none |
fontcolor | black | type face color |
fontname | Times-Roman | font family |
fontsize | 14 | point size of label |
headlabel | label placed near head of edge | |
headport | n,ne,e,se,s,sw,w,nw | |
headURL | URL attached to head label if output format is ismap | |
label | edge label | |
labelangle | -25.0 | angle in degrees which head or tail label is rotated off edge |
labeldistance | 1.0 | scaling factor for distance of head or tail label from node |
labelfloat | false | lessen constraints on edge label placement |
labelfontcolor | black | type face color for head and tail labels |
labelfontname | Times-Roman | font family for head and tail labels |
labelfontsize | 14 | point size for head and tail labels |
layer | overlay range | all, id or id:id |
lhead | name of cluster to use as head of edge | |
ltail | name of cluster to use as tail of edge | |
minlen | 1 | minimum rank distance between head and tail |
samehead | tag for head node; edge heads with the same tag are | |
sametail | merged onto the same port | |
style | tag for tail node; edge tails with the same tag are merged onto the same port | |
taillabel | graphics options, e.g. bold, dotted, filled; cf. Section 2.3 | |
tailport | label placed near tail of edge n,ne,e,se,s,sw,w,nw | |
tailURL | URL attached to tail label if output format is ismap | |
weight | 1 | integer cost of stretching an edge |
图属性如下:
Name | Default | Values |
---|---|---|
bgcolor | background color for drawing, plus initial fill color | |
center | false | center drawing on page |
clusterrank | local | may be global or none |
color | black | for clusters, outline color, and fill color if fillcolor not defined |
comment | any string (format-dependent) | |
compound | false | allow edges between clusters |
concentrate | false | enables edge concentrators |
fillcolor | black | cluster fill color |
fontcolor | black | type face color |
fontname | Times-Roman | font family |
fontpath | list of directories to search for fonts | |
fontsize | 14 | point size of label |
label | any string | |
labeljust | centered | ”l” and ”r” for left- and right-justified cluster labels, respectively |
labelloc | top | ”t” and ”b” for top- and bottom-justified cluster labels, respectively |
layers | id:id:id… | |
margin | .5 | margin included in page, inches |
mclimit | 1.0 | scale factor for mincross iterations |
nodesep | .25 | separation between nodes, in inches. |
nslimit | if set to f, bounds network simplex iterations by (f)(number of nodes) when setting x-coordinates | |
nslimit1 | if set to f, bounds network simplex iterations by (f)(number of nodes) when ranking nodes | |
ordering | if out out edge order is preserved | |
orientation | portrait | if rotate is not used and the value is landscape, use landscape orientation |
page | unit of pagination, e.g. “8.5,11” | |
pagedir | BL | traversal order of pages |
quantum | if quantum ¿ 0.0, node label dimensions will be rounded to integral multiples of quantum | |
rank | same, min, max, source or sink | |
rankdir | TB | LR (left to right) or TB (top to bottom) |
ranksep | .75 | separation between ranks, in inches. |
ratio | approximate aspect ratio desired, fill or auto | |
remincross | if true and there are multiple clusters, re-run crossing minimization | |
rotate | If 90, set orientation to landscape | |
samplepoints | 8 | number of points used to represent ellipses and circles on output (cf. Appendix C |
searchsize | 30 | maximum edges with negative cut values to check when looking for a minimum one during network simplex |
size | maximum drawing size, in inches | |
style | graphics options, e.g. filled for clusters | |
URL | URL associated with graph (format-dependent) |
具体实例
这里列举几个常用到的例子,还有更加详细的例子还可以参考 官网例子中心
下面是一个二叉树代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | digraph g { node [shape = record,height=.1]; node0[label = "<f0> |<f1> G|<f2> " ]; node1[label = "<f0> |<f1> E|<f2> " ]; node2[label = "<f0> |<f1> B|<f2> " ]; node3[label = "<f0> |<f1> F|<f2> " ]; node4[label = "<f0> |<f1> R|<f2> " ]; node5[label = "<f0> |<f1> H|<f2> " ]; node6[label = "<f0> |<f1> Y|<f2> " ]; node7[label = "<f0> |<f1> A|<f2> " ]; node8[label = "<f0> |<f1> C|<f2> " ]; "node0" :f2 -> "node4" :f1; "node0" :f0 -> "node1" :f1; "node1" :f0 -> "node2" :f1; "node1" :f2 -> "node3" :f1; "node2" :f2 -> "node8" :f1; "node2" :f0 -> "node7" :f1; "node4" :f2 -> "node6" :f1; "node4" :f0 -> "node5" :f1; } |
python 调用
除了可以使用 dot
文件编写图形外,也可以使用python编写相关的代码,生成图形文件, 安装 python 对应的 graphviz 相应的模块
1 | pip install pygraphviz |
引用 pygraphviz
1 | import pygraphviz as pgv |
初始化图类
1 | G = pgv.AGraph() |
增加节点和边
1 2 | G.add_node( 'a' ) # adds node 'a' G.add_edge( 'b' , 'c' ) # adds edge 'b'-'c' (and also nodes 'b', 'c') |
设置属性
1 2 3 | G.graph_attr[ 'label' ] = 'test graphf' G.node_attr[ 'shape' ] = 'circle' G.edge_attr[ 'color' ] = 'red' |
设置输出的格式
1 2 | G.layout() # default to neato G.layout(prog = 'dot' ) # use do |
输出到文件
1 2 | G.draw( 'file.png' ) # write previously positioned graph to PNG file G.draw( 'file.ps' ,prog = 'circo' ) # use circo to position, write PS file |
效果如下图所示:
结束语
由于当今的动态虚拟环境的存在,系统在不断变化,很难保持文档与图表的时效性和准确性。本文介绍了 Graphviz 的基础知识,以及如何通过编写脚本,利用 Graphviz 的强大功能来创建最新、最准确的自动化环境图表。您可以从 cron 运行这些脚本,并将图表放在 Web 服务器上,这样就可以在您需要时随时重新创建图表,并通过 Web 浏览器轻松访问它们。
总结使用案例
案例一:
digraph startgame { label="游戏资源更新流程" rankdir="TB" start[label="启动游戏" shape=circle style=filled] ifwifi[label="网络环境判断是否 WIFI" shape=diamond] needupdate[label="是否有资源需要更新" shape=diamond] startslientdl[label="静默下载" shape=box] enterhall[label="进入游戏大厅" shape=box] enterroom[label="进入房间" shape=box] resourceuptodate[label="资源不完整" shape=diamond] startplay[label="正常游戏" shape=circle fillcolor=blue] warning[label="提醒玩家是否更新" shape=diamond] startdl[label="进入下载界面" shape=box] //{rank=same; needupdate, enterhall} {shape=diamond; ifwifi, needupdate} start -> ifwifi ifwifi->needupdate[label="是"] ifwifi->enterhall[label="否"] needupdate->startslientdl[label="是"] startslientdl->enterhall needupdate->enterhall[label="否"] enterhall -> enterroom enterroom -> resourceuptodate resourceuptodate -> warning[label="是"] resourceuptodate -> startplay[label="否"] warning -> startdl[label="确认下载"] warning -> enterhall[label="取消下载"] startdl -> enterhall[label="取消下载"] startdl -> startplay[label="下载完成"] }
案例二:
digraph G{ size = "5, 5";//图片大小 main[shape=box];/*形状*/ main->parse; parse->execute; main->init[style = dotted];//虚线 main->cleanup; edge[color = green]; // 连接线的颜色 execute->{make_string; printf}//连接两个 init->make_string; main->printf[style=bold, label="100 times"];//线的 label make_string[label = "make a\nstring"]// \n, 这个node的label,注意和上一行的区别 node[shape = box, style = filled, color = ".7.3 1.0"];//一个node的属性 execute->compare; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix