markdown 绘图利器之granphviz
概述
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脚本代码如下:
digraph base_flow {
// 步骤1: 定义digraph的属性
label = <<B>graphviz使用流程</B>>;
// 步骤2: 定义node、edge的属性
node[shape=box];
// 步骤3: 添加node、edge
graph_attr -> node_edge_attr -> node_edge_added -> custom_attr;
// 步骤4: 定义特定node,edge的属性
graph_attr[label="1. 定义digraph的属性"];
node_edge_attr[label="2. 定义node、edge的属性"];
node_edge_added[label="3. 添加node、edge"];
custom_attr[label="4. 定义特定node,edge的属性"];
}
graphviz 脚本语法结构
Graphviz 语法非常简单,主要由代码块、语句、标识符、注释等几部分组成:
- 代码块: 位于
{}
语句中的语句即为代码块; - 语句:以
;
结尾,主要分为代码块,节点,连线,属性四种语句类型; - 实体对象标识符:除了特殊字符外的所有字符都可以用于标识符,如数字,中英文字符串等;
- 注释:
//
表示单行注释,/*...*/
表示多行注释。
图
graphviz 图实体主要分三类:
- graph: 1)
digraph {...}
定义有向图;2)graph {...}
定义无向图; - subgraph:
subgraph {...}
定义子图; - cluster subgraph:
subgraph cluster_xxx {...}
定义的代码块
子图的类型(有向图还是无向图)与父图相同,子图的名称以cluster开头才被当成聚集子图渲染。示例如下:
digraph graph_name{
bgcolor="transparent";//背景透明
subgraph cluster_subgraph_name{//聚集子图
node[shape=box];
cluster_A -> cluster_B;
}
subgraph subgraph_name{//子图
node[shape=none];
sub_A -> sub_B;
}
{//匿名子图
node[shape=octagon];
nest_A -> nest_B;
}
global_A -> global_B;
cluster_B -> global_B;
sub_B -> global_B;
nest_B -> global_B;
}
方向,尺寸,间距
两个重要的属性决定了图的尺寸,分别为 nodesep, ranksep。
nodesep
: 同一个 rank 中的相邻节点的最小距离,单位为英寸(=2.54 cm)。直线的不同端点属于不同的 rank;ranksep
: 相邻 rank 之间的距离;rankdir
: rank的指向,如 LR (left to right) or RL,或者 TB (top to bottom) or BT;
digraph G {
nodesep = 2;
ranksep = 1;
rankdir = LR;
a -> b;
c;
b -> d;
}
节点
graphviz的节点的定义方式如下:
节点标识符[节点属性]
所有的节点属性见官网的节点属性介绍,下面,介绍常用的节点属性。
当想让节点的形状完全由类HTML的标签设置时,一般设置属性 width=0, height=0, margin=0 。
shape 属性
graphviz 主要有三种类型的形状(shape)类型:多边形(polygon), 记录(record)形状, 用户定义(user-defined)形状。基于记录的形状在很大程度上已经被类似HTML的标签所取代。也就是说,可以考虑使用shape=none、margin=0和类HTML标签,而不是使用shape=record。
多边形
所有的多边形的属性值与形状如下,其中 rect/rectangle 与 box 是同义词,none 与 plaintext 是同义词。
当想让节点的形状完全由类HTML的标签设置时,一般设置属性 width 0, height=0, margin=0 。
record-based 的形状
基于 record的形状,是指节点的属性为 record 或者 Mrecord 的节点,其节点的表现形式由 label 属性决定。 record 与 Mrecord 的区别在于 Mrecord 的外围是圆角。
label 属性的语法结构如下:
- 不同的字段使用
|
隔开; - 字段的 portname 使用
<...>
尖括号括起来; - 在
{...}
中的内容,在水平和垂直布局之间翻转,取决于 graph 的 rankdir 属性:1)若graph[rankdir=TB]
,则整体图片垂直布局,{...}
中的内容垂直布局。2)graph[rankdir=LR]
,则整体图片水平布局,{...}
中的内容水平布局;
digraph structs {
node[shape=record];
graph[rankdir=TB];
struct1[label="<f0> left|<f1> mid\ dle|<f2> right"];
struct2[label="<f0> one|<f1> two"];
struct3[label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
struct1:f1 -> struct2:f0;
struct1:f2 -> struct3:here;
}
修改 graph 属性为 LR,则整体水平布局。
digraph structs {
node[shape=record];
graph[rankdir=LR];
struct1[label="<f0> left|<f1> mid\ dle|<f2> right"];
struct2[label="<f0> one|<f1> two"];
struct3[label="hello\nworld |{ b |{c|<here> d|e}| f}| g | h"];
struct1:f1 -> struct2:f0;
struct1:f2 -> struct3:here;
}
用户定制
用户定制图形有几种方式:
- 通过类HTML的 label 使用 IMG 属性加载用户定制的图像;
digraph structs {
node [shape=plaintext];
struct1 [label=<<TABLE>
<TR><TD><IMG SRC="eqn.png"/></TD></TR>
<TR><TD>caption</TD></TR>
</TABLE>>];
}
- 如果使用的是 SVG (-Tsvg),或者 postScript (-Tps, -Tps2) 或者 光栅格式 (-Tgif, -Tpng, 或者-Tjpg),可以通过指定图像文件名加载图片,例如:
graph pic_test {
your_pic[shape=none, label="", imagepath="D:\\cloud_sync\\vnote_book\\效率工具", image="test.png"];
}
关于 image 的路径,参考环境变量的设置
label 属性
基本用法
label 属性的基本用法是设置节点的文本显示,若节点没有显示设置label属性,则文本显示节点的标识符。
graph lebel_demo {
node1;
node2[label="文本显示"];
}
HTML用法
label 属性HTML用法是将节点转换为一个类似于HTML的实体,实体的具体呈现完全由HTML脚本语言控制,其注意事项如下:
- 节点的 shape 属性设置为 record 或 none,建议 none ;
- 节点的 宽、高、边缘属性设置为0:width=0, height=0, margin=0;
- 节点的 label 属性字符串通过尖括号
<...>
包含HTML语法字符串;
示例:使用HTML实现一个表格节点实体(注意:html不区分大小写)。
digraph html_label_Example
{
label = "html_like_label_example";
bgcolor="transparent";//背景透明
html_ex_node[shape=record, margin=0, label=<
<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
<tr>
<td rowspan="2">test</td>
<td>a</td>
<td rowspan="2">HTML-Like<br/>label</td>
</tr>
<tr>
<td>b</td>
</tr>
</table>
>];
}
graphviz不支持所有的html-4的语法,目前只支持如下的html-like语法:
label : text
| fonttable
text : textitem
| text textitem
textitem : string
| <BR/>
| <FONT> text </FONT>
| <I> text </I>
| <B> text </B>
| <U> text </U>
| <O> text </O>
| <SUB> text </SUB>
| <SUP> text </SUP>
| <S> text </S>
fonttable : table
| <FONT> table </FONT>
| <I> table </I>
| <B> table </B>
| <U> table </U>
| <O> table </O>
table : <TABLE> rows </TABLE>
rows : row
| rows row
| rows <HR/> row
row : <TR> cells </TR>
cells : cell
| cells cell
| cells <VR/> cell
cell : <TD> label </TD>
| <TD> <IMG/> </TD>
更多的html-like语法见 graphviz官网中对record节点的介绍
style 属性
style 属性用于修改节点的外观,当前,支持8种类型的 style:filled, invisible, diagonals, rounded. dashed, dotted, solid, bold
filled
: 此值指示应填充节点的内部。使用的颜色是 fillcolor 定义的,若 fillcolor 属性未定义,则使用 color 属性的颜色。对于未填充的节点,节点内部对当前图形或簇背景色的任何颜色都是透明的。请注意,点形状始终是填充的。
digraph G {
rankdir=LR
node [shape=box, color=blue]
node1 [style=filled]
node2 [style=filled, fillcolor=red]
node0 -> node1 -> node2
}
invisible
: 不可见。设置此样式会导致节点根本不显示。请注意,节点仍用于布局图形。diagonals
: 斜线 。“斜线”样式会导致在节点多边形的顶点附近绘制小斜线。
digraph G {
rankdir=LR
node [shape=box, color=blue]
node0 [style=diagonals]
}
rounded
:圆形的,使节点的边变得圆滑,可以作用在 record 形状上。
digraph R {
rankdir=LR
node [style=rounded]
node1 [shape=box]
node2 [fillcolor=yellow, style="rounded,filled", shape=diamond]
node3 [shape=record, label="{ a | b | c }"]
node1 -> node2 -> node3
}
dashed
: 使节点的边变为虚线;dotted
: 使节点的边变为点线;solid
: 使节点的边变为直线,默认属性;bold
: 使节点的边线加粗。
port 属性
节点的 port 属性是指节点连接另一个节点的线条端点位置,端口的位置有8种,分别为节点的东、南、西、北、东南、东北、西南、西北,属性的值分别为e, s, w, n, se, ne, sw, nw
有两种类型的 port 属性:
- 一种使指定源节点的端点位置,使用
tailport
属性,如下脚本指定 a节点的端点位置为东:
digraph G {
a -> b [tailport = e];
}
- 一种指定目的节点的端点位置,使用
:pos
语法,如下脚本指定b节点的端点位置为西:
digraph G {
a -> b:w;
}
也可以通过上述语法指定 record 形状的域字段(如f1)的端点位置:
digraph G {
a -> b:f1:w;
}
参考
附录
Graphviz基本组成结构dot代码
digraph gv_basic_structure{
label=<<B>Graphviz基本组成结构</B>>;
node[shape=box];
graphviz[label="Graphviz"];
subgraph{
layout[label="Layouts"];
script[label="Script Files"];
api[label="APIs"]
rank=same;
}
graphviz -> layout;
graphviz -> script;
graphviz -> api;
script ->
subgraph{
element[label="Elements"];
attribute[label="Attributes"];
rank=same;
}
layout ->
subgraph{
layout_dot[label="dot", color="red"];
layout_neato[label="neato"];
layout_etc[label="......"];
}
element ->
subgraph{
ele_graph[label="Graph"];
ele_node[label="Node"];
ele_edge[label="Edge"];
}
}
markdown 绘图利器之granphviz的更多相关文章
- Win下必备利器之Cmder
诚言,对于开发码字者,Mac和Linux果断要比Windows更贴心;但只要折腾下,Windows下也是有不少利器的.之前就有在Windows下效率必备软件一文中对此做了下记载:其虽没oh-my-zs ...
- C#编程利器之二:结构与枚举(Structure and enumeration)【转】
C#编程利器之二:结构与枚举(Structure and enumeration) 在上一篇文章中,介绍了类如何封装程序中的对象.而实际中,出了类可以封装对象外,结构和枚举也可以封装一些对象,本文将着 ...
- 大数据并行计算利器之MPI/OpenMP
大数据集群计算利器之MPI/OpenMP ---以连通域标记算法并行化为例 1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出 ...
- php调试利器之phpdbg
信海龙的博客 php调试利器之phpdbg 简介 PHPDBG是一个PHP的SAPI模块,可以在不用修改代码和不影响性能的情况下控制PHP的运行环境. PHPDBG的目标是成为一个轻量级.强大.易用的 ...
- 后台任务利器之Hangfire
后台任务利器之Hangfire 一.简述 Hangfire作为一款高人气且容易上手的分布式后台执行服务,支持多种数据库.在.net core的环境中,由Core自带的DI管理着生命周期,免去了在NF4 ...
- Android开发利器之ActivityTracker
版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/113 Android开发利器之ActivityTracke ...
- windows管理员利器之用Log Parser Studio分析IIS日志(附逐浪CMS官方命令集)
原文:windows管理员利器之用Log Parser Studio分析IIS日志(附逐浪CMS官方命令集) Log Parser Studio是一个强大的IIS图形分析工具,值得推荐. 1. 安装L ...
- .NET Core开源组件:后台任务利器之Hangfire 转载 https://www.cnblogs.com/chenug/p/6655636.html
.NET Core开源组件:后台任务利器之Hangfire 一.简述 Hangfire作为一款高人气且容易上手的分布式后台执行服务,支持多种数据库.在.net core的环境中,由Core自带的D ...
- Java高并发编程基础三大利器之CountDownLatch
引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...
随机推荐
- 第十章 函数式接口&Stream流
10.1.函数式接口 10.1.1.概述 有且仅有一个抽象方法的接口,并且可以通过在类上标注@FunctionalInterface注解进行检测,建议自定义的函数式接口都加上这个注解 10.1.2.函 ...
- PHP flock() 函数
定义和用法 flock() 函数锁定或释放文件. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE. 语法 flock(file,lock,block) 参数 描述 file 必需.规定要 ...
- PHP ftp_size() 函数
定义和用法 ftp_size() 函数返回 FTP 服务器上指定文件的大小. 该函数以字节返回指定文件的大小,如果出错则返回 -1. 语法 ftp_size(ftp_connection,file) ...
- PHP exp() 函数
实例 返回 'e' 的不同次方: <?phpecho(exp(0) . "<br>");echo(exp(1) . "<br>") ...
- C/C++编程笔记:C++入门知识丨从结构到类的演变
先来看看本节知识的结构图吧! 接下来我们就逐步来看一下所有的知识点: 结构的演化 C++中的类是从结构演变而来的, 所以我们可以称C++为”带类的C”. 结构发生质的演变 C++结构中可以定义函数, ...
- LeetCode 87,远看是字符串其实是搜索,你能做出来吗?
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题第54篇文章,我们一起来看LeetCode 87题,Scramble String(爬行字符串). 这题的官方难度 ...
- Sharding-JDBC实现垂直拆分
参考资料:猿天地 https://mp.weixin.qq.com/s/wl8h6LIQUHztVuVbjfsU3Q 作者:尹吉欢 当一个项目量增大,数据表数量增多时,就需要对数据表进行垂直拆分, ...
- Linux用C语言模拟‘ls‘命令
原理 在linux下使用C语言,通过调用Linux系统的目录访问API来实现一个类似于ls命令功能的小程序,主要是可以练习程序对命令的解析和目录API函数的使用. 实现代码 #include < ...
- Druid数据源的使用
1 Druid数据源简介 Druid是Java语言中最好的数据库连接池.Druid能够提供强大的监控和扩展功能.通过访问http://localhost:8080(自己的端口)/druid/ 可以查看 ...
- Make Windows 10 Comfortable
在 StartUp 目录中(在当前用户目录下), 创建.bat, 里面可以写希望登录指定的命令(如使用subst进行映射, 将常用的目录映射为磁盘驱动器) 在 %USERPROFILE%(也就是用户家 ...