微信邦 发表于 2018-8-6 22:12:01

教你用代码画一颗树

| 导语 一直以来自己都是通过Visio在画流程图和架构图,原来通过写代码的方式也可以画图,这种方式简洁而高效,完美搭配vim,并且可以轻松实现脚本化,于是就入坑了。

写在前面
优点自动布局和连线易于实现脚本化
缺点无法绘制需要自定义或固定布局的图下面我们就来画一棵Merkle树吧:)
代码的分割线


等等,Merkle树是神马?
Merkle树,也叫哈希树,是一种用做快速归纳和校验大规模数据完整性的树形数据结构。
下图就是《精通比特币》一书中的Merkle树示意图,图中每个叶子节点即一笔交易,两两组合,逐层Hash到根节点。通过Merkle树可以在只知道部分节点的Hash的情况下,就能验证某笔交易是否存在或正确,而无需获取所有交易节点的Hash值。要知道一般这个代价是很大的,以比特币区块为例,目前整个区块链账本大小接近200G。
所以,Merkle树也是SPV(简单的支付认证,即Simple Payment Verification)的基础。🔻
Merkle树应用
快速比较大量数据:当两个Merkle树的根哈希值相同时,说明所代表的的数据都相同快速定位修改:如上图,如果交易K发生改变,那么就会导致HK、HKL、HIJKL、HIJKLMNOP和Merkle Root发生改变。所以,我们想要快速定位,只需要沿着Root => HIJKLMNOP => HIJKL => HKL => HK,就可以定位到交易K发生改变零知识证明:例如,想要证明一组交易中包含某个交易K,但又不想让对方知道交易K的具体内容,那么就可以构建Merkle树,向对方公布HK、HL、HKL、HIJKL、HIJKLMNOP和Merkle Root,对方就可以确认交易K的存在,但无法知道交易K的具体内容。
开始画图/写代码🔻怎样画节点?最简单的节点
寥寥四行代码就画出了3个节点
<font color="rgb(102, 217, 239)">digraph</font> G1 {    <font color="rgb(102, 217, 239)">A</font>       B       C   }


装饰节点
<div class="quote"><blockquote><span style="color: rgb(248, 248, 242); font-family: Consolas, Monaco, monospace; font-size: 14px; letter-spacing: 2px; text-align: justify; white-space: pre; background-color: rgb(35, 36, 31);">digraph G2 {
    //对节点进行全局设置
    node ;

    HA
    HK                                                                        
    HKL
}</span>



节点属性

属性名默认值说明
labelnode name节点显示内容
colorblacknode边框颜色
fontcolorblack字体颜色
fillcolor
背景色
fontnameTimes-Roman字体
fontsize14字体大小
shapeellipse形状:box、ellipse、circle、diamond、
plaintext、point、triangle、invtriangle
style
图形样式: bold、dashed、dotted、filled
image
背景图片地址

怎样画连线?最简单的连线通过->很形象的建立了节点间的有向连线
<font size="4"><span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(166, 226, 46);">digraph</span> <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">G3</span> {    <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">A</span>      
    <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">B</span>      
    <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">C</span>      

    <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">A</span> -> <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">C</span>
    <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">B</span> -> <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">C</span>                                                       }</font>

装饰连线
<font size="4">digraph G4 {
    //边全局设置                                             
    edge ;
    A                     
    B                     
    C                     

    A -> C
    B -> C
}</font>


连线属性

属性名默认值说明
label
描述关系
colorblack箭头颜色
fontcolorblack关系文字颜色
dirforward设置方向:forward、back、both、none
arrowheadnormal箭头头部形状:box、crow、diamond、dot、none、normal、vee
arrowtailnone箭头尾部形状
arrowsize1.0箭头大小
style
图形样式: bold、dashed、dotted、filled
仿制Merkle树完整代码<font size="4">$ cat MerkleTree.dot
digraph MerkleTree {
    rankdir = BT;
    label=<span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">"MerkleTree draw by jasonruan"</span>

    node ;
    edge ;

    HA         
    HB         
    HAB         
    HC         
    HD         
    HCD         
    HABCD      
    HE         
    HF         
    HEF         
    HG         
    HH         
    HGH         
    HEFGH      
    HABCDEFGH   

    HI         
    HJ         
    HIJ         
    HK         
    HL         
    HKL         
    HIJKL      
    HM         
    HN         
    HMN         
    HO         
    HP         
    HOP         
    HMNOP      
    HIJKLMNOP   


    {HA,HB}    -> HAB
    {HC,HD}    -> HCD
    {HAB,HCD}   -> HABCD
    {HE,HF}    -> HEF
    {HG,HH}    -> HGH
    {HEF,HGH}   -> HEFGH
    {HABCD,HEFGH} -> HABCDEFGH

    {HI,HJ}    -> HIJ
    {HK,HL}    -> HKL
    {HIJ,HKL}   -> HIJKL
    {HM,HN}    -> HMN
    {HO,HP}    -> HOP
    {HMN,HOP}   -> HMNOP
    {HIJKL,HMNOP} -> HIJKLMNOP

    HABCDEFGHIJKLMNOP
    {HABCDEFGH,HIJKLMNOP} -> HABCDEFGHIJKLMNOP</font>
Merkle树仿制图
工具安装最后再来介绍下画图工具和vim插件安装。软件安装官网:https://graphviz.gitlab .io/当前版本:graphviz-2.40.1.tar.gz这里采用源码方式安装:<font size="4">$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz
$ tar -zxf graphviz.tar.gz
$ <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">cd</span> graphviz-2.40.1
$ ./configure --prefix=/home/rzexin/Software/ALL
$ make -j2 && make install</font>
vim整合(1)插件安装.vimrc新增<font size="4">Plugin <span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">'wannesm/wmgraphviz.vim'</span></font>
执行安装命令<font size="4">:PluginInstall</font>
(2)vim配置<font size="4"><span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(249, 38, 114);">function</span> HeaderDot()
    call append (1,<span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">"digraph G {"</span>)         
    call append (2,<span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">""</span>)
    call append (3,<span class="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; color: rgb(230, 219, 116);">"}"</span>)
    normal 3G         
endfunction         
autocmd bufnewfile *.dot call HeaderDot()

nmap <Leader>ln :w<CR>:! dot -Tpng -o %<.png %<CR>:! eog %<.png <CR>
nmap <Leader>ls :w<CR>:! dot -Tsvg -o %<.svg %<CR>:! eog %<.svg <CR></font>
配置说明:
[*]

打开.dot后缀文件,自动执行HeaderDot函数创建dot文件框架
vim normal模式下执行,ln将自动保存png格式文件并自动预览,同样,使用,ls将保存为svg格式文件并自动预览
%<表示去掉后缀的当前文件名
写在最后
graphviz的功能也确实强大,自己只是初步入门,但感觉这点入门知识也已经大大提升了自己的工作效率。之前通过Visio画图要不断的去调整样式、配色,是件很繁琐的事情,特别是当要修改时,可能要不断调整已有图形的布局,很是费时。现在,通过graphviz一切都自动的帮你完成好了,而且图形还挺美观。自己能不入坑吗:)end

页: [1]
查看完整版本: 教你用代码画一颗树