使用graphviz绘图

2015年11月10日更新 在实践中,我又发现了一些graphviz的有趣的特性,比如时序图,rank以及图片节点等。在这里一并更新。 ##前言 日常的开发工作中,为代码添加注释是代码可维护性的一个重要方面,但是仅仅提供注释是不够的,特别是当系统功能越来越复杂,涉及到的模块越来越多的时候,仅仅靠代码就很难从宏观的层次去理解。因此我们需要图例的支持,图例不仅仅包含功能之间的交互,也可以包含复杂的数据结构的示意图,数据流向等。 但是,常用的UML建模工具,如Visio等都略显复杂,且体积庞大。对于开发人员,特别是后台开发人员来说,命令行,脚本才是最友好的,而图形界面会很大程度的限制开发效率。相对于鼠标,键盘才是开发人员最好的朋友。 ###graphviz简介 本文介绍一个高效而简洁的绘图工具graphviz。graphviz是贝尔实验室开发的一个开源的工具包,它使用一个特定的DSL(领域特定语言): dot作为脚本语言,然后使用布局引擎来解析此脚本,并完成自动布局。graphviz提供丰富的导出格式,如常用的图片格式,SVG,PDF格式等。 graphviz中包含了众多的布局器: dot 默认布局方式,主要用于有向图 neato 基于spring-model(又称force-based)算法 twopi 径向布局 circo 圆环布局 fdp 用于无向图 graphviz的设计初衷是对有向图/无向图等进行自动布局,开发人员使用dot脚本定义图形元素,然后选择算法进行布局,最终导出结果。 首先,在dot脚本中定义图的顶点和边,顶点和边都具有各自的属性,比如形状,颜色,填充模式,字体,样式等。然后使用合适的布局算法进行布局。布局算法除了绘制各个顶点和边之外,需要尽可能的将顶点均匀的分布在画布上,并且尽可能的减少边的交叉(如果交叉过多,就很难看清楚顶点之间的关系了)。所以使用graphviz的一般流程为: 定义一个图,并向图中添加需要的顶点和边 为顶点和边添加样式 使用布局引擎进行绘制 一旦熟悉这种开发模式,就可以快速的将你的想法绘制出来。配合一个良好的编辑器(vim/emacs)等,可以极大的提高开发效率,与常见的GUI应用的所见即所得模式对应,此模式称为所思即所得。比如在我的机器上,使用Sublime Text 编辑dot脚本,然后将F7/Cmd-B映射为调用dot引擎去绘制当前脚本,并打开一个新的窗口来显示运行结果: 对于开发人员而言,经常会用到的图形绘制可能包括:函数调用关系,一个复杂的数据结构,系统的模块组成,抽象语法树等。 ###基础知识 graphviz包含3中元素,图,顶点和边。每个元素都可以具有各自的属性,用来定义字体,样式,颜色,形状等。下面是一些简单的示例,可以帮助我们快速的了解graphviz的基本用法。 ####第一个graphviz图 比如,要绘制一个有向图,包含4个节点a,b,c,d。其中a指向b,b和c指向d。可以定义下列脚本: digraph abc{ a; b; c; d; a -> b; b -> d; c -> d; } 使用dot布局方式,绘制出来的效果如下: 默认的顶点中的文字为定义顶点变量的名称,形状为椭圆。边的默认样式为黑色实线箭头,我们可以在脚本中做一下修改,将顶点改为方形,边改为虚线。 ####定义顶点和边的样式 在digraph的花括号内,添加顶点和边的新定义: node [shape="record"]; edge [style="dashed"]; 则绘制的效果如下: ####进一步修改顶点和边样式 进一步,我们将顶点a的颜色改为淡绿色,并将c到d的边改为红色,脚本如下: digraph abc{ node [shape="record"]; edge [style="dashed"]; a [style="filled", color="black", fillcolor="chartreuse"]; b; c; d; a -> b; b -> d; c -> d [color="red"]; } 绘制的结果如下:...

November 10, 2015 6 min

使用Yahoo Pipe Service来聚合你关注的博客

ThoughtWorks好声音 ThoughtWorks好声音是一个聚合网站,内容来自众ThoughtWorker的博客,我们每周会汇聚一次,从众多的博客中挑选出一些P2(软件卓越)相关的主题,然后编为一辑,再分享出去。 但是从近100个博客中找P2相关的内容,这件事本身非常繁琐,如果每周都做这个重复劳动的话,那么软件卓越从何谈起呢?作为以解放人类为己任的程序员,我们绝对不能忍受纯体力的劳动。 获取博客地址列表 之前郑晔做了一个金数据的统计,请各位同事把自己的名字和博客地址登记在一个金数据的表单上: 接下来第一步就是把网页上的所有地址取下来,这一步很容易,从金数据的页面上用jQuery找到表格的第二列,然后将其中的文字取出来: $("table tr td:nth-child(2)").map(function(key, item) { return $(item).text().trim(); }); 写到这里突发奇想,能不能用phantomjs去把这个动作自动化? page.open(url, function (status) { if (status !== 'success') { console.log('Unable to access network'); } else { page.injectJs('jquery.js'); var links = page.evaluate(function() { return $("table tr td:nth-child(2)").map(function(key, value) { return $(value).text().trim(); }); }); var results = underscore(links).filter(function(item) { return item.length > 0; }).map(function(item) { if(!new RegExp('^(https|http)').test(item)) { return "http://" + item; } return item; }); } phantom....

January 1, 2014 1 min

Alfred插件开发 - Sinatra

###Alfred简介 Alfred是Mac下的一个小工具,可以极大的提高使用计算机的效率。Alfred提供非常丰富的功能集,比如: 基本的文件/目录查找功能 应用程序加载器 快速的搜索(google,wikipedia) ####powerpack Alfred本身是免费的,但是一些高级的功能,如: 自定义扩展(非常有用) 剪贴板栈/代码片段管理(非常有用) iTunes控制 近期访过的文档 提供在powerpack中,这个功能是要收费的,不过个人觉得绝对的物超所值。这些功能可以极大的提高我对计算机的使用效率,而且剪贴板栈功能可以节省我很多的时间。 ###扩展编写 经常会使用sinatra编写一些简单的Web应用程序,以用作一些showcase和应用程序的原型搭建。但是由于sinatra并不是一个框架,并不会像rails那样自动生成目录结构等,而每个sinatra应用的目录结构和文件依赖都非常相似,因此完全可以考虑将这个过程自动化。 基本思路是: 定义一个目录结构的模板 每次开始一个sinatra工程时,将个模板目录拷贝到新的工程下 一些库依赖的下载(bundle install以及JavaScript库的下载) 在编辑器中打开这个新的目录 ####一个sinatra工程的原型 $ pwd /Users/twer/develop/templates/sinatra $ tree -a . ├── .rvmrc ├── Gemfile ├── app.rb ├── config.ru ├── public │ ├── css │ └── scripts │ ├── app.js │ └── libs └── views ####Extension shell script # create the project folder cd ~/develop/ruby && mkdir -p {query} && cd {query} # cp info to folder cp -R ~/develop/templates/sinatra/ ....

May 18, 2013 1 min

使用Powerline打造漂亮的状态栏

###Powerline powerline会将vim的status line变的非常漂亮,看起来像一个“主流”的编辑器那样,而又不会引入额外的“重量”。基本原理是使用字体将特殊字符展现成特殊形状(如三角形),额外的有一些漂亮的配色。 ####效果 ####安装 有几个额外的点需要确保: #####保证你的vim包含了对python的支持 vim --version | grep python的结果应该包含+python,如: +path_extra -perl +persistent_undo +postscript +printer -profile +python/dyn 如果没有的话,需要将vim重新编译,比如在Mac OS下: brew install macvim --env-std --override-system-vim #####安装powerline 最简单的方式是直接clone到本地,比如: git clone git://github.com/Lokaltog/powerline.git ~/PowerLine/ #####配置.vimrc 为你的vimrc添加下面的配置: set rtp+={path_to_powerline}/powerline/bindings/vim set laststatus=2 set noshowmode 这时,如果你启动vim,应该已经可以看到powerline了,但是有可能有“乱码”的问题,幸运的是,已经有很多的预定义字体。 ###Fonts 这里有许多额外的预定义fonts。选中需要的字体,安装到本地即可(双击字体文件或者拷贝到~/Library/Fonts下)。然后在.vimrc中使用这个字体,比如: set encoding=utf-8 set guifont=Menlo\ for\ Powerline:h14

February 19, 2013 1 min

从Google Code迁移至Github

###一些闲话 虽然对开源社区没有任何杰出的贡献,但是我自己在业余时间开发的很多小东西都是开源的,有部分放在google code上,可是除了一个sTodo有几个用户外,其他的工具几乎都纯属自娱自乐。虽然当时做的时候自己非常投入,会各种YY,假设用户会需要这个功能,会需要那个功能,用户会需要脚本化,自定义插件等等,但是到最后发现只有自己在使用,而再过一段时间,连自己也不会使用了。 我自己托管在google code上的,还算有点用处的项目有三个: sTodo 一个简单的todo管理器 phoc 一个可以用JavaScript脚本化的计算器 utouch 一个使用styledTextCtrl的编辑器 虽然这种事情发生在几乎每一个喜欢写程序的家伙身上,但是整个过程对自我修炼来说,还是非常有现实意义的,首先专业技能得到了锻炼,而最重要的一点是:需求不是想象出来的!在没有和用户真正仔细的讨论之前,我们的假设和推断往往是错的。 Idea到处都是,有很多很酷且很有挑战的idea,但是它们不一定真的在解决人们的问题。这是一个很值得思考的问题,我最近在尝试组织一个活动,主题以及目标已经确定,上周找胡凯帮我把关,结果发现我又一次的进入了“帮助用户想需求”的老路上了。 ###迁移 ####使用svn同步到本地 根据google code的提示,将code从svn中的checkout到本地: svn checkout http://phoc.googlecode.com/svn phoc-read-only ####去除掉.svn隐藏目录 现使用find在当前目录下找到名称为.svn的目录,然后将其删除,这个过程是递归的,即可以清除掉当前目录及所有子目录中的.svn目录: find . -name ".svn" -type d -exec rm -rf {} \; ####初始化git的repo git init git add . git ci -m "migrate of project xxx to github" 然后对应的在github上创建repo,创建之后,需要将本地的remote指向github上的repo: git remote add origin git@github.com:project/project.git 如果本地的master分支没有配置,可以在.git/config中进行配置: [branch "master"] remote = origin merge = refs/heads/master 最后将新的commit push到新的repo上即可: git pull --rebase git push 我已经把这个工具迁移到了github上abruzzi,正式告别了google code。

January 13, 2013 1 min