ruby-graphviz 入门
2009-05-26 14:44
197 查看
自从写了一个关于Graphviz 的教程
以来,我一直觉得它使用起来还不够方便。最近终于找到Graphviz 的Ruby 扩展了——ruby-graphviz
。
首先你得安装Graphviz
,记得装在默认目录下,不然ruby-graphviz 找不到(我还不知道怎么设置PATH,请指教)。
然后,gem 一下:
接下来将见证神奇的一刻。
Run 一下,你会在源文件所在目录下发现一个hello_world.png 文件。
老规矩,下面来解释一下。
可以用new 创建一个graph 对象。new 的时候有这么几个选项:
:output : Output format (Constants::FORMATS) (default : dot)
:file : Output file name (default : none)
:use : Program to use (Constants::PROGRAMS) (default : dot)
:path : Program PATH
:parent : Parent graph (default : none)
:type : Graph type (Constants::GRAPHTYPE) (default : digraph)
用output (有个别名save)生成图像。同样,output 也有几个可选项:
:output : Output format (Constants::FORMATS)
:file : Output file name
:use : Program to use (Constants::PROGRAMS)
:path : Program PATH
点
用add_node 来加点。可以像这样来设置属性:
这样,n 将会是一个用<.7, .3, 1.0> 填充的box。
用node_count 来对点计数。
用[]= 来设置属性值:
边
用add_edge 加边。
用edge_count 来对边计数。
也可以像点那样设置属性:
这样,e 将成为一条带红色标注“an edge” 的蓝线。
Record Nodes
记录是一个盒子,被分割成横的或竖的格子。格子之前可以加标记,只需把标记放在尖括号<> 之间。横格子之间用竖杠| 隔开,竖格子就是外加一对大括号{}。看下面的例子:
子图
代码说明一切(注意add_graph):
高级技巧
同一个图的三种不同写法:
Rubyist 更喜欢的风格:
Ruby geek 的写法:
小结
ruby-graphviz 和graphviz 的原生DOT 文件之间存在一一对应的关系。一个典型的graphviz DOT 文件有三个主要部分:
数据头,用来设置点、边、图的属性
点定义
边定义
所以ruby-graphviz 文件也是由这三部分组成。我们用一个对比例子来结束本教程。
这个graphviz 例子来自Mark A. McBride:
我用Ruby 改写了这个例子:
要想了解更多,请看官方文档。
以来,我一直觉得它使用起来还不够方便。最近终于找到Graphviz 的Ruby 扩展了——ruby-graphviz
。
首先你得安装Graphviz
,记得装在默认目录下,不然ruby-graphviz 找不到(我还不知道怎么设置PATH,请指教)。
然后,gem 一下:
gem install ruby-graphviz
接下来将见证神奇的一刻。
require 'graphviz' # this loads the ruby-graphviz gem # initialize new Graphviz graph g = GraphViz::new( "hello_world", "type" => "graph") hello = g.add_node( "hello" ) world = g.add_node( "world" ) g.add_edge( hello, world ) g.output( "output" => "png", :file => "hello_world.png" )
Run 一下,你会在源文件所在目录下发现一个hello_world.png 文件。
老规矩,下面来解释一下。
可以用new 创建一个graph 对象。new 的时候有这么几个选项:
:output : Output format (Constants::FORMATS) (default : dot)
:file : Output file name (default : none)
:use : Program to use (Constants::PROGRAMS) (default : dot)
:path : Program PATH
:parent : Parent graph (default : none)
:type : Graph type (Constants::GRAPHTYPE) (default : digraph)
用output (有个别名save)生成图像。同样,output 也有几个可选项:
:output : Output format (Constants::FORMATS)
:file : Output file name
:use : Program to use (Constants::PROGRAMS)
:path : Program PATH
点
用add_node 来加点。可以像这样来设置属性:
n = g.add_node( "node" ) n.set { |_n| _n.shape = "box" _n.style = "filled" _n.color = ".7 .3 1.0" }
这样,n 将会是一个用<.7, .3, 1.0> 填充的box。
用node_count 来对点计数。
用[]= 来设置属性值:
g.node["shape"] = "ellipse" g.node["sides"] = "4" g.node["peripheries"] = "" g.node["color"] = "black" g.node["style"] = "" g.node["skew"] = "0.0" g.node["distortion"] = "0.0"
边
用add_edge 加边。
用edge_count 来对边计数。
也可以像点那样设置属性:
e = g.add_edge( n1, n2, "label" => "an edge" ) e.set { |_e| _e.color = "blue" _e.fontcolor = "red" }
这样,e 将成为一条带红色标注“an edge” 的蓝线。
Record Nodes
记录是一个盒子,被分割成横的或竖的格子。格子之前可以加标记,只需把标记放在尖括号<> 之间。横格子之间用竖杠| 隔开,竖格子就是外加一对大括号{}。看下面的例子:
require "graphviz" g = GraphViz::new( "G" ) g.node["shape"] = "record" struct1 = g.add_node( "struct1", "shape" => "record", "label" => "<f0> left|<f1> mid/ dle|<f2> right" ) struct2 = g.add_node( "struct2", "shape" => "record", "label" => "<f0> one|<f1> two" ) struct3 = g.add_node( "struct3", "shape" => "record", "label" => 'hello/nworld |{ b |{c|<here> d|e}| f}| g | h' ) g.add_edge( struct1, struct2 ) g.add_edge( struct1, struct3 ) g.output( :output => "png" , :file => "structs.png" )再来看一个复杂一点的例子:
require "graphviz" GraphViz::options( :output => "png", :use => "dot" ) g = GraphViz::new( "structs", :output => "png", :rankdir => "LR" ) g.node["shape"] = "record" node0 = g.add_node( "node0", :label => "<f0> 0x10ba8| <f1>" ) node1 = g.add_node( "node1", :label => "<f0> 0xf7fc4380| <f1> | <f2> |-1" ) node2 = g.add_node( "node2", :label => "<f0> 0xf7fc44b8| | |2" ) node3 = g.add_node( "node3", :label => "<f0> 3.43322790286038071e-06|44.79998779296875|0" ) node4 = g.add_node( "node4", :label => "<f0> 0xf7fc4380| <f1> | <f2> |2" ) node5 = g.add_node( "node5", :label => "<f0> (nil)| | |-1" ) node6 = g.add_node( "node6", :label => "<f0> 0xf7fc4380| <f1> | <f2> |1" ) node7 = g.add_node( "node7", :label => "<f0> 0xf7fc4380| <f1> | <f2> |2" ) node8 = g.add_node( "node8", :label => "<f0> (nil)| | |-1" ) node9 = g.add_node( "node9", :label => "<f0> (nil)| | |-1" ) node10 = g.add_node( "node10", :label => "<f0> (nil)| <f1> | <f2> |-1" ) node11 = g.add_node( "node11", :label => "<f0> (nil)| <f1> | <f2> |-1" ) node12 = g.add_node( "node12", :label => "<f0> 0xf7fc43e0| | |1" ) g.add_edge( "node0:f0", "node1:f0" ) g.add_edge( "node0:f1", "node2:f0" ) g.add_edge( "node1:f0", "node3:f0" ) g.add_edge( "node1:f1", "node4:f0" ) g.add_edge( "node1:f2", "node5:f0" ) g.add_edge( "node4:f0", "node3:f0" ) g.add_edge( "node4:f1", "node6:f0" ) g.add_edge( "node4:f2", "node10:f0" ) g.add_edge( "node6:f0", "node3:f0" ) g.add_edge( "node6:f1", "node7:f0" ) g.add_edge( "node6:f2", "node9:f0" ) g.add_edge( "node7:f0", "node3:f0" ) g.add_edge( "node7:f1", "node1:f0" ) g.add_edge( "node7:f2", "node8:f0" ) g.add_edge( "node10:f1", "node11:f0" ) g.add_edge( "node10:f2", "node12:f0" ) g.add_edge( "node11:f2", "node1:f0" ) g.output( :file => "complicated_sample.png" )
子图
代码说明一切(注意add_graph):
require "graphviz" graph = GraphViz::new( "G", "output" => "png" ) graph["compound"] = "true" graph.edge["lhead"] = "" graph.edge["ltail"] = "" c0 = graph.add_graph( "cluster0" ) a = c0.add_node( "a" ) b = c0.add_node( "b" ) c = c0.add_node( "c" ) d = c0.add_node( "d" ) c0.add_edge( a, b ) c0.add_edge( a, c ) c0.add_edge( b, d ) c0.add_edge( c, d ) c1 = graph.add_graph( "cluster1" ) e = c1.add_node( "e" ) f = c1.add_node( "f" ) g = c1.add_node( "g" ) c1.add_edge( e, g ) c1.add_edge( e, f ) h = graph.add_node( "h" ) graph.add_edge( b, f, "lhead" => "cluster1" ) graph.add_edge( d, e ) graph.add_edge( c, g, "ltail" => "cluster0", "lhead" => "cluster1" ) graph.add_edge( c, e, "ltail" => "cluster0" ) graph.add_edge( d, h ) graph.output( :file => "subgraph.png" )
高级技巧
同一个图的三种不同写法:
require "graphviz" g = GraphViz::new( "G", "output" => "png" ) g.node["shape"] = "ellipse" g.node["color"] = "black" g["color"] = "black" c0 = g.add_graph( "cluster0" ) c0["label"] = "process #1" c0["style"] = "filled" c0["color"] = "lightgrey" a0 = c0.add_node( "a0", "style" => "filled", "color" => "white" ) a1 = c0.add_node( "a1", "style" => "filled", "color" => "white" ) a2 = c0.add_node( "a2", "style" => "filled", "color" => "white" ) a3 = c0.add_node( "a3", "style" => "filled", "color" => "white" ) c0.add_edge( a0, a1 ) c0.add_edge( a1, a2 ) c0.add_edge( a2, a3 ) c1 = g.add_graph( "cluster1", "label" => "process #2" ) b0 = c1.add_node( "b0", "style" => "filled", "color" => "blue" ) b1 = c1.add_node( "b1", "style" => "filled", "color" => "blue" ) b2 = c1.add_node( "b2", "style" => "filled", "color" => "blue" ) b3 = c1.add_node( "b3", "style" => "filled", "color" => "blue" ) c1.add_edge( b0, b1 ) c1.add_edge( b1, b2 ) c1.add_edge( b2, b3 ) start = g.add_node( "start", "shape" => "Mdiamond" ) endn = g.add_node( "end", "shape" => "Msquare" ) g.add_edge( start, a0 ) g.add_edge( start, b0 ) g.add_edge( a1, b3 ) g.add_edge( b2, a3 ) g.add_edge( a3, a0 ) g.add_edge( a3, endn ) g.add_edge( b3, endn ) g.output( :file => "the_same_sample1.png" )
Rubyist 更喜欢的风格:
require "graphviz" g = GraphViz::new( "G", "output" => "png" ) g.node[:shape] = "ellipse" g.node[:color] = "black" g[:color] = "black" g.cluster0( ) do |cluster| cluster[:label] = "process #1" cluster[:style] = "filled" cluster[:color] = "lightgrey" cluster.a0 :style => "filled", :color => "white" cluster.a1 :style => "filled", :color => "white" cluster.a2 :style => "filled", :color => "white" cluster.a3 :style => "filled", :color => "white" cluster.a0 << cluster.a1 cluster.a1 << cluster.a2 cluster.a2 << cluster.a3 end g.cluster1( :label => "process #2" ) do |cluster| cluster.b0 :style => "filled", :color => "blue" cluster.b1 :style => "filled", :color => "blue" cluster.b2 :style => "filled", :color => "blue" cluster.b3 :style => "filled", :color => "blue" cluster.b0 << cluster.b1 cluster.b1 << cluster.b2 cluster.b2 << cluster.b3 end g.start :shape => "Mdiamond" g.endn :shape => "Msquare", :label => "end" g.start << g.cluster0.a0 g.start << g.cluster1.b0 g.cluster0.a1 << g.cluster1.b3 g.cluster1.b2 << g.cluster0.a3 g.cluster0.a3 << g.cluster0.a0 g.cluster0.a3 << g.endn g.cluster1.b3 << g.endn g.output( :file => "the_same_sample2.png" )
Ruby geek 的写法:
require "graphviz" GraphViz::new( "G", "output" => "png" ) { |graph| graph.node[:shape] = "ellipse" graph.node[:color] = "black" graph[:color] = "black" graph.cluster0( ) do |cluster| cluster[:label] = "process #1" cluster[:style] = "filled" cluster[:color] = "lightgrey" cluster.a0 :style => "filled", :color => "white" cluster.a1 :style => "filled", :color => "white" cluster.a2 :style => "filled", :color => "white" cluster.a3 :style => "filled", :color => "white" cluster.a0 << cluster.a1 cluster.a1 << cluster.a2 cluster.a2 << cluster.a3 end graph.cluster1( :label => "process #2" ) do |cluster| cluster.b0 :style => "filled", :color => "blue" cluster.b1 :style => "filled", :color => "blue" cluster.b2 :style => "filled", :color => "blue" cluster.b3 :style => "filled", :color => "blue" cluster.b0 << cluster.b1 cluster.b1 << cluster.b2 cluster.b2 << cluster.b3 end graph.start :shape => "Mdiamond" graph.endn :shape => "Msquare", :label => "end" graph.start << graph.cluster0.a0 graph.start << graph.cluster1.b0 graph.cluster0.a1 << graph.cluster1.b3 graph.cluster1.b2 << graph.cluster0.a3 graph.cluster0.a3 << graph.cluster0.a0 graph.cluster0.a3 << graph.endn graph.cluster1.b3 << graph.endn }.output( :path => 'C:/Program Files/Graphviz2.20/bin', :file => "the_same_sample3.png" )
小结
ruby-graphviz 和graphviz 的原生DOT 文件之间存在一一对应的关系。一个典型的graphviz DOT 文件有三个主要部分:
数据头,用来设置点、边、图的属性
点定义
边定义
所以ruby-graphviz 文件也是由这三部分组成。我们用一个对比例子来结束本教程。
这个graphviz 例子来自Mark A. McBride:
digraph graph_example { /***** GLOBAL SETTINGS *****/ graph [rotate=0, rankdir="LR"] node [color="#333333", style=filled, shape=box, fontname="Trebuchet MS"] edge [color="#666666", arrowhead="open", fontname="Trebuchet MS", fontsize="11"] node [fillcolor="#294b76", fontcolor="white"] /***** Nodes *****/ a [label="Node A"] b [label="Node B"] c [label="Node C"] d [label="Node D", fillcolor="#116611"] /***** Edges *****/ a -> b b -> c c -> d b -> d a -> d [label="direct path"] }
我用Ruby 改写了这个例子:
require "graphviz" g = GraphViz::new( "G", "output" => "png" ) # ***** GLOBAL SETTINGS ***** g[:rotate] = "0" g[:rankdir] = "LR" g.node[:color] = "#333333" g.node[:style] = "filled" g.node[:shape] = "box" g.node[:fontname] = "Trebuchet MS" g.node[:fillcolor] = "#294b76" g.node[:fontcolor] = "white" g.edge[:color] = "#666666" g.edge[:arrowhead] = "open" g.edge[:fontname] = "Trebuchet MS" g.edge[:fontsize] = "11" # ***** Nodes ***** a = g.add_node( "a", :label => "Node A" ) b = g.add_node( "b", :label => "Node B" ) c = g.add_node( "c", :label => "Node C" ) d = g.add_node( "d", :label => "Node D", :fillcolor => "#116611" ) # ***** Edges ***** g.add_edge( a, b ) g.add_edge( b, c ) g.add_edge( c, d ) g.add_edge( b, d ) g.add_edge( a, d, :label => "direct path" ) g.output( :file => "f:/a.png" )
要想了解更多,请看官方文档。
相关文章推荐
- ruby入门_if
- ruby入门_next
- ruby入门_string
- ruby入门_访问作用域
- Ruby 入门: 正则表达式之反向引用
- Ruby 入门: 方法
- 【Ruby】Ruby(面向对象程序设计的脚本语言)入门
- [入门]Ruby on Rails入门教程及开发工具选用
- [入门]Ruby on Rails入门教程及开发工具选用
- Ruby菜鸟入门指南
- 利用Radrails开发Ruby on Rails程序入门指南
- Ruby中的Socket编程简单入门
- ruby入门_常量
- Ruby 从入门到精通 译者序
- Ruby on Rails 入门 ----respond_to
- Ruby on Rails 入门之:(5) Ruby中基本数据类型
- Ruby on Rails 入门之:(8) Ruby中条件语句
- ruby入门练习之String对象
- Ruby on Rails 入门之:(18) ruby线程控制,线程同步
- windows下Graphviz安装及入门教程