概述

Markdown 是一个轻量级的标记语言,语法简单、易于上手,深受程序员、博主等人群的钟爱。Markdown 工具链也非常丰富,如graphviz软件,就是可以嵌入markdown文本,进行思维导图、流程图、系统框图绘制的利器,让你心无旁骛,全心投入到系统架构、软件、算法的设计中。

在markdown使用 graphviz 语法,推荐使用 vnote 软件

graphviz 是 AT&T的bell实验室开源的脚本自动化绘图软件,其主要用于绘制关系图,自动排版,有效提升工作效率。同时,其也是自动化绘图工具plantuml、很多数据可视化工具的基础。类似于python中的matplotlib。

graphviz 的基本结构如下所示,其主要包含三部分:

  • 1) layout 自动化布局工具:dot,neato等,本文重点讲解dot的使用。
  • 2) script脚本:主要包含 graph,node,edge三类实体,以及attributes属性;
  • 3)APIs:若需要在其它语言中调用,graphviz提供了 C,java,python,php等语言的API。

graphviz的dot的基本使用也非常简单,流程如下:

graphviz示例,也是上述基础流程的dot脚本代码如下:

  1. digraph base_flow {
  2. // 步骤1: 定义digraph的属性
  3. label = <<B>graphviz使用流程</B>>;
  4. // 步骤2: 定义node、edge的属性
  5. node[shape=box];
  6. // 步骤3: 添加node、edge
  7. graph_attr -> node_edge_attr -> node_edge_added -> custom_attr;
  8. // 步骤4: 定义特定node,edge的属性
  9. graph_attr[label="1. 定义digraph的属性"];
  10. node_edge_attr[label="2. 定义node、edge的属性"];
  11. node_edge_added[label="3. 添加node、edge"];
  12. custom_attr[label="4. 定义特定node,edge的属性"];
  13. }

graphviz 脚本语法结构

Graphviz 语法非常简单,主要由代码块、语句、标识符、注释等几部分组成:

  • 代码块: 位于{}语句中的语句即为代码块;
  • 语句:以;结尾,主要分为代码块,节点,连线,属性四种语句类型;
  • 实体对象标识符:除了特殊字符外的所有字符都可以用于标识符,如数字,中英文字符串等;
  • 注释//表示单行注释,/*...*/表示多行注释。

graphviz 图实体主要分三类:

  • graph: 1)digraph {...} 定义有向图;2)graph {...}定义无向图;
  • subgraph:subgraph {...}定义子图;
  • cluster subgraph: subgraph cluster_xxx {...}定义的代码块

子图的类型(有向图还是无向图)与父图相同,子图的名称以cluster开头才被当成聚集子图渲染。示例如下:

  1. digraph graph_name{
  2. bgcolor="transparent";//背景透明
  3. subgraph cluster_subgraph_name{//聚集子图
  4. node[shape=box];
  5. cluster_A -> cluster_B;
  6. }
  7. subgraph subgraph_name{//子图
  8. node[shape=none];
  9. sub_A -> sub_B;
  10. }
  11. {//匿名子图
  12. node[shape=octagon];
  13. nest_A -> nest_B;
  14. }
  15. global_A -> global_B;
  16. cluster_B -> global_B;
  17. sub_B -> global_B;
  18. nest_B -> global_B;
  19. }

方向,尺寸,间距

两个重要的属性决定了图的尺寸,分别为 nodesep, ranksep。

  • nodesep : 同一个 rank 中的相邻节点的最小距离,单位为英寸(=2.54 cm)。直线的不同端点属于不同的 rank;
  • ranksep : 相邻 rank 之间的距离;
  • rankdir: rank的指向,如 LR (left to right) or RL,或者 TB (top to bottom) or BT;
  1. digraph G {
  2. nodesep = 2;
  3. ranksep = 1;
  4. rankdir = LR;
  5. a -> b;
  6. c;
  7. b -> d;
  8. }

节点

graphviz的节点的定义方式如下:

  1. 节点标识符[节点属性]

所有的节点属性见官网的节点属性介绍,下面,介绍常用的节点属性。

当想让节点的形状完全由类HTML的标签设置时,一般设置属性 width=0, height=0, margin=0

shape 属性

graphviz 主要有三种类型的形状(shape)类型:多边形(polygon), 记录(record)形状, 用户定义(user-defined)形状。基于记录的形状在很大程度上已经被类似HTML的标签所取代。也就是说,可以考虑使用shape=none、margin=0和类HTML标签,而不是使用shape=record。

多边形

所有的多边形的属性值与形状如下,其中 rect/rectanglebox 是同义词,noneplaintext 是同义词。

当想让节点的形状完全由类HTML的标签设置时,一般设置属性 width 0, height=0, margin=0

![](https://raw.githubusercontent.com/melon-li/markdown_pics/master/1598067382_20200816110541022_17972.png =556x)

record-based 的形状

基于 record的形状,是指节点的属性为 record 或者 Mrecord 的节点,其节点的表现形式由 label 属性决定。 record 与 Mrecord 的区别在于 Mrecord 的外围是圆角。

label 属性的语法结构如下:

  • 不同的字段使用|隔开;
  • 字段的 portname 使用 <...>尖括号括起来;
  • {...}中的内容,在水平和垂直布局之间翻转,取决于 graph 的 rankdir 属性:1)若 graph[rankdir=TB],则整体图片垂直布局,{...}中的内容垂直布局。2)graph[rankdir=LR],则整体图片水平布局,{...}中的内容水平布局;
  1. digraph structs {
  2. node[shape=record];
  3. graph[rankdir=TB];
  4. struct1[label="<f0> left|<f1> mid\ dle|<f2> right"];
  5. struct2[label="<f0> one|<f1> two"];
  6. struct3[label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
  7. struct1:f1 -> struct2:f0;
  8. struct1:f2 -> struct3:here;
  9. }

修改 graph 属性为 LR,则整体水平布局。

  1. digraph structs {
  2. node[shape=record];
  3. graph[rankdir=LR];
  4. struct1[label="<f0> left|<f1> mid\ dle|<f2> right"];
  5. struct2[label="<f0> one|<f1> two"];
  6. struct3[label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
  7. struct1:f1 -> struct2:f0;
  8. struct1:f2 -> struct3:here;
  9. }

用户定制

用户定制图形有几种方式:

  • 通过类HTML的 label 使用 IMG 属性加载用户定制的图像;
  1. digraph structs {
  2. node [shape=plaintext];
  3. struct1 [label=<<TABLE>
  4. <TR><TD><IMG SRC="eqn.png"/></TD></TR>
  5. <TR><TD>caption</TD></TR>
  6. </TABLE>>];
  7. }
  • 如果使用的是 SVG (-Tsvg),或者 postScript (-Tps, -Tps2) 或者 光栅格式 (-Tgif, -Tpng, 或者-Tjpg),可以通过指定图像文件名加载图片,例如:
  1. graph pic_test {
  2. your_pic[shape=none, label="", imagepath="D:\\cloud_sync\\vnote_book\\效率工具", image="test.png"];
  3. }

关于 image 的路径,参考环境变量的设置

label 属性

基本用法

label 属性的基本用法是设置节点的文本显示,若节点没有显示设置label属性,则文本显示节点的标识符。

  1. graph lebel_demo {
  2. node1;
  3. node2[label="文本显示"];
  4. }

HTML用法

label 属性HTML用法是将节点转换为一个类似于HTML的实体,实体的具体呈现完全由HTML脚本语言控制,其注意事项如下:

  • 节点的 shape 属性设置为 record 或 none,建议 none ;
  • 节点的 宽、高、边缘属性设置为0:width=0, height=0, margin=0
  • 节点的 label 属性字符串通过尖括号<...>包含HTML语法字符串;

示例:使用HTML实现一个表格节点实体(注意:html不区分大小写)。

  1. digraph html_label_Example
  2. {
  3. label = "html_like_label_example";
  4. bgcolor="transparent";//背景透明
  5. html_ex_node[shape=record, margin=0, label=<
  6. <table border="0" cellborder="1" cellspacing="0" cellpadding="4">
  7. <tr>
  8. <td rowspan="2">test</td>
  9. <td>a</td>
  10. <td rowspan="2">HTML-Like<br/>label</td>
  11. </tr>
  12. <tr>
  13. <td>b</td>
  14. </tr>
  15. </table>
  16. >];
  17. }

graphviz不支持所有的html-4的语法,目前只支持如下的html-like语法:


  1. label : text
  2. | fonttable
  3. text : textitem
  4. | text textitem
  5. textitem : string
  6. | <BR/>
  7. | <FONT> text </FONT>
  8. | <I> text </I>
  9. | <B> text </B>
  10. | <U> text </U>
  11. | <O> text </O>
  12. | <SUB> text </SUB>
  13. | <SUP> text </SUP>
  14. | <S> text </S>
  15. fonttable : table
  16. | <FONT> table </FONT>
  17. | <I> table </I>
  18. | <B> table </B>
  19. | <U> table </U>
  20. | <O> table </O>
  21. table : <TABLE> rows </TABLE>
  22. rows : row
  23. | rows row
  24. | rows <HR/> row
  25. row : <TR> cells </TR>
  26. cells : cell
  27. | cells cell
  28. | cells <VR/> cell
  29. cell : <TD> label </TD>
  30. | <TD> <IMG/> </TD>

更多的html-like语法见 graphviz官网中对record节点的介绍

style 属性

style 属性用于修改节点的外观,当前,支持8种类型的 style:filled, invisible, diagonals, rounded. dashed, dotted, solid, bold

  • filled : 此值指示应填充节点的内部。使用的颜色是 fillcolor 定义的,若 fillcolor 属性未定义,则使用 color 属性的颜色。对于未填充的节点,节点内部对当前图形或簇背景色的任何颜色都是透明的。请注意,点形状始终是填充的。
  1. digraph G {
  2. rankdir=LR
  3. node [shape=box, color=blue]
  4. node1 [style=filled]
  5. node2 [style=filled, fillcolor=red]
  6. node0 -> node1 -> node2
  7. }

  • invisible : 不可见。设置此样式会导致节点根本不显示。请注意,节点仍用于布局图形。
  • diagonals: 斜线 。“斜线”样式会导致在节点多边形的顶点附近绘制小斜线。
  1. digraph G {
  2. rankdir=LR
  3. node [shape=box, color=blue]
  4. node0 [style=diagonals]
  5. }

  • rounded :圆形的,使节点的边变得圆滑,可以作用在 record 形状上。
  1. digraph R {
  2. rankdir=LR
  3. node [style=rounded]
  4. node1 [shape=box]
  5. node2 [fillcolor=yellow, style="rounded,filled", shape=diamond]
  6. node3 [shape=record, label="{ a | b | c }"]
  7. node1 -> node2 -> node3
  8. }

  • dashed : 使节点的边变为虚线;

  • dotted : 使节点的边变为点线;

  • solid : 使节点的边变为直线,默认属性;

  • bold : 使节点的边线加粗。

port 属性

节点的 port 属性是指节点连接另一个节点的线条端点位置,端口的位置有8种,分别为节点的东、南、西、北、东南、东北、西南、西北,属性的值分别为e, s, w, n, se, ne, sw, nw

有两种类型的 port 属性:

  • 一种使指定源节点的端点位置,使用 tailport 属性,如下脚本指定 a节点的端点位置为东:
  1. digraph G {
  2. a -> b [tailport = e];
  3. }

  • 一种指定目的节点的端点位置,使用:pos语法,如下脚本指定b节点的端点位置为西:
  1. digraph G {
  2. a -> b:w;
  3. }

也可以通过上述语法指定 record 形状的域字段(如f1)的端点位置:

  1. digraph G {
  2. a -> b:f1:w;
  3. }

参考

附录

Graphviz基本组成结构dot代码

  1. digraph gv_basic_structure{
  2. label=<<B>Graphviz基本组成结构</B>>;
  3. node[shape=box];
  4. graphviz[label="Graphviz"];
  5. subgraph{
  6. layout[label="Layouts"];
  7. script[label="Script Files"];
  8. api[label="APIs"]
  9. rank=same;
  10. }
  11. graphviz -> layout;
  12. graphviz -> script;
  13. graphviz -> api;
  14. script ->
  15. subgraph{
  16. element[label="Elements"];
  17. attribute[label="Attributes"];
  18. rank=same;
  19. }
  20. layout ->
  21. subgraph{
  22. layout_dot[label="dot", color="red"];
  23. layout_neato[label="neato"];
  24. layout_etc[label="......"];
  25. }
  26. element ->
  27. subgraph{
  28. ele_graph[label="Graph"];
  29. ele_node[label="Node"];
  30. ele_edge[label="Edge"];
  31. }
  32. }

markdown 绘图利器之granphviz的更多相关文章

  1. Win下必备利器之Cmder

    诚言,对于开发码字者,Mac和Linux果断要比Windows更贴心;但只要折腾下,Windows下也是有不少利器的.之前就有在Windows下效率必备软件一文中对此做了下记载:其虽没oh-my-zs ...

  2. C#编程利器之二:结构与枚举(Structure and enumeration)【转】

    C#编程利器之二:结构与枚举(Structure and enumeration) 在上一篇文章中,介绍了类如何封装程序中的对象.而实际中,出了类可以封装对象外,结构和枚举也可以封装一些对象,本文将着 ...

  3. 大数据并行计算利器之MPI/OpenMP

    大数据集群计算利器之MPI/OpenMP ---以连通域标记算法并行化为例 1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出 ...

  4. php调试利器之phpdbg

    信海龙的博客 php调试利器之phpdbg 简介 PHPDBG是一个PHP的SAPI模块,可以在不用修改代码和不影响性能的情况下控制PHP的运行环境. PHPDBG的目标是成为一个轻量级.强大.易用的 ...

  5. 后台任务利器之Hangfire

    后台任务利器之Hangfire 一.简述 Hangfire作为一款高人气且容易上手的分布式后台执行服务,支持多种数据库.在.net core的环境中,由Core自带的DI管理着生命周期,免去了在NF4 ...

  6. Android开发利器之ActivityTracker

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/113 Android开发利器之ActivityTracke ...

  7. windows管理员利器之用Log Parser Studio分析IIS日志(附逐浪CMS官方命令集)

    原文:windows管理员利器之用Log Parser Studio分析IIS日志(附逐浪CMS官方命令集) Log Parser Studio是一个强大的IIS图形分析工具,值得推荐. 1. 安装L ...

  8. .NET Core开源组件:后台任务利器之Hangfire 转载 https://www.cnblogs.com/chenug/p/6655636.html

    .NET Core开源组件:后台任务利器之Hangfire   一.简述 Hangfire作为一款高人气且容易上手的分布式后台执行服务,支持多种数据库.在.net core的环境中,由Core自带的D ...

  9. Java高并发编程基础三大利器之CountDownLatch

    引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...

随机推荐

  1. Hexo博客美化之蝴蝶(butterfly)主题魔改

      Hexo是轻量级的极客博客,因为它简便,轻巧,扩展性强,搭建部署方便深受广大人们的喜爱.各种琳琅满路的Hexo主题也是被各种大佬开发出来,十分钦佩,向大佬仰望,大声称赞:流批!!! 我在翻看各种主 ...

  2. Unicode 字符串

    Unicode 字符串 Python 中定义一个 Unicode 字符串和定义一个普通字符串一样简单:高佣联盟 www.cgewang.com >>> u'Hello World ! ...

  3. PHP simplexml_load_file() 函数

    实例 转换 XML 文件为 SimpleXMLElement 对象,然后输出对象的键和元素: <?php高佣联盟 www.cgewang.com$xml=simplexml_load_file( ...

  4. PDOStatement::nextRowset

    PDOStatement::nextRowset — 在一个多行集语句句柄中推进到下一个行集(PHP 5 >= 5.1.0, PECL pdo >= 0.2.0)高佣联盟 www.cgew ...

  5. Skill 脚本演示

    https://www.cnblogs.com/yeungchie/ Schematic ycBusNet.il 用于原理图中按照一定格式,批量创建 Bus . ycNetToPin.il 通过选中一 ...

  6. linux之FTP服务搭建 ( ftp文件传输协议 VSFTPd虚拟用户)

    FTP服务搭建 配置实验之前关闭防火墙 iptables -F iptables -X iptables -Z systemctl stop firewalld setenforce 0 1.ftp简 ...

  7. Oracle连接池工具类OJDBCUtils

    Oraclejdbc.properties driverClassName=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@127.0.0. ...

  8. C++虚函数相关内容

    样例代码 class Base{public: Base(){}; virtual ~Base(){    //若没有设置为虚函数:如果有这样的指针Base *p=new Derived();声明,则 ...

  9. Android SQLite轻量级数据库的删除和查找操作

    今天主要是补充昨天的内容,本打算合成一章的,但是毕竟一天一天的内容写习惯了. 就这样继续昨天的,昨天只讲了创建以及增加和查询, 其实用法都差不多,今天学长也是在原有的基础上写的,还顺便融合了Share ...

  10. 牛!Python 也能实现图像姿态识别溺水行为了!

    作者 | 李秋键 责编 | Carol 封图 | CSDN 下载自视觉中国 众所周知随着人工智能智能的发展,人工智能的落地项目也在变得越来越多,尤其是计算机视觉方面. 很多人学习python,不知道从 ...