class GraphViz
Constants for ruby-graphviz
GraphViz::Constants::FORMATS: the possible output formats
"bmp", "canon", "dot", "xdot", "cmap", "dia", "eps", "fig", "gd", "gd2", "gif", "gtk", "hpgl", "ico", "imap", "cmapx", "imap_np", "cmapx_np", "ismap", "jpeg", "jpg", "jpe", "mif", "mp", "pcl", "pdf", "pic", "plain", "plain-ext", "png", "ps", "ps2", "svg", "svgz", "tga", "tiff", "tif", "vml", "vmlz", "vrml", "vtx", "wbmp", "xlib", "none"
GraphViz::Constants::PROGRAMS: The possible programs
"dot", "neato", "twopi", "fdp", "circo"
GraphViz::Constants::GRAPHTYPE The possible types of graph
"digraph", "graph"
The single letter codes used in constructors map as follows:
G => The root graph, with GRAPHATTRS E => Edge, with EDGESATTRS N => Node, with NODESATTRS S => subgraph C => cluster
>> x = “hellont\l"world"”
> “hellont\l"world"”¶ ↑
>> puts x.inspect.gsub( “\\”, “\” ) “hellontl"world"”
OR
>> x = 'hellontl“world”'
> “hello\n\t\l"world"”¶ ↑
>> puts x.inspect.gsub( “\\”, “\” ) “hellontl"world"”
bool
For the bool type,
-
TRUE values are represented by “true” or “yes” (case-insensitive), true and any non-zero integer
-
FALSE values by “false”, “no” or empty string (case-insensitive), false and zero.
Example
graph[:center] = "true"
or
graph[:center] = true
or
graph[:center] = 23
TODO: Remove
spliteType or point
spline ( ';' spline )* where spline = (endp)? (startp)? point (triple)+ and triple = point point point and endp = “e,%f,%f” and startp = “s,%f,%f”
If a spline has points p1 p2 p3 … pn, (n = 1 (mod 3)), the points correspond to the control points of a B-spline from p1 to pn. If startp is given, it touches one node of the edge, and the arrowhead goes from p1 to startp. If startp is not given, p1 touches a node. Similarly for pn and endp.
Attributes
This accessor allow you to set global edges attributes
This accessor allow you to set global edges attributes
This accessor allow you to set global graph attributes
This accessor allow you to set global graph attributes
This accessor allow you to set global nodes attributes
This accessor allow you to set global nodes attributes
Public Class Methods
Change default options (:use, :path, :errors and :output)
# File lib/graphviz.rb, line 718 def self.default( hOpts ) hOpts.each do |k, v| case k.to_s when "use" @@prog = v when "path" @@path = v.split( "," ).map{ |x| x.strip } when "errors" @@errors = v when "extlibs" @@extlibs = v.split( "," ).map{ |x| x.strip } else warn "Invalid option #{k}!" end end end
# File lib/graphviz/nothugly.rb, line 54 def self.libxslt_transform(xml, xsl) LibXML::XML.default_load_external_dtd = false LibXML::XML.default_substitute_entities = false stylesheet_doc = LibXML::XML::Document.file(xsl) stylesheet = LibXSLT::XSLT::Stylesheet.new(stylesheet_doc) xml_doc = LibXML::XML::Document.file(xml) stylesheet.apply(xml_doc).to_s end
Create a new graph object
Options :
-
:output : Output format (GraphViz::Constants::FORMATS) (default : dot)
-
:file : Output file name (default : nil)
-
:use : Program to use (GraphViz::Constants::PROGRAMS) (default : dot)
-
:path : Program PATH
-
:parent : Parent graph (default : nil)
-
:type : Graph type (GraphViz::Constants::GRAPHTYPE) (default : digraph)
-
:errors : DOT error level (default 1)
-
0 = Error + Warning
-
1 = Error
-
2 = none
-
# File lib/graphviz.rb, line 818 def initialize( xGraphName, hOpts = {}, &block ) @filename = nil @name = xGraphName.to_s @format = @@format @prog = @@prog @path = @@path @errors = @@errors @extlibs = @@extlibs @output = {} @nothugly = false @strict = false @scale = nil @inverty = nil @no_layout = nil @reduce_graph = nil @Lg = nil @LO = nil @Ln = nil @LU = nil @LC = nil @LT = nil @elements_order = GraphViz::Elements::new() @oParentGraph = nil @oGraphType = "digraph" @hoNodes = Hash::new() @loEdges = Array::new() @hoGraphs = Hash::new() @node = GraphViz::Attrs::new( self, "node", NODESATTRS ) @edge = GraphViz::Attrs::new( self, "edge", EDGESATTRS ) @graph = GraphViz::Attrs::new( self, "graph", GRAPHSATTRS ) hOpts.each do |xKey, xValue| case xKey.to_s when "use" if PROGRAMS.index( xValue.to_s ).nil? raise ArgumentError, "can't use '#{xValue}'" end @prog = xValue.to_s when "parent" @oParentGraph = xValue when "type" if GRAPHTYPE.index( xValue.to_s ).nil? raise ArgumentError, "graph type '#{xValue}' unknow" end @oGraphType = xValue.to_s when "path" @path = xValue.split( "," ).map{ |x| x.strip } when "strict" @strict = (xValue ? true : false) when "errors" @errors = xValue when "extlibs" @extlibs = xValue.split( "," ).map{ |x| x.strip } else self[xKey.to_s] = xValue.to_s end end yield( self ) if( block ) end
Transform to pretty up the SVG output
For more information, see www.hokstad.com/making-graphviz-output-pretty-with-xsl.html and www.hokstad.com/making-graphviz-output-pretty-with-xsl-updated.html
You can use the :nothugly option to #output :
graph.output( :svg => "myGraph.svg", :nothugly => true )
Or directly on an SVG output graph :
GraphViz.nothugly( "myGraph.svg" )
# File lib/graphviz/nothugly.rb, line 33 def self.nothugly( file, save = true ) xsl = File.join( File.dirname(File.expand_path(__FILE__)), "nothugly", "nothugly.xsl" ) out = self.send(XSLT_METHOD, file, xsl) if save fname = File.join( File.dirname(File.expand_path(file)), File.basename(file)) File.open( fname, "w" ) { |io| io.print out } else return out end end
# File lib/graphviz.rb, line 735 def self.options( hOpts ) GraphViz::default( hOpts ) end
Create a new graph from a GraphViz File
Options :
-
:output : Output format (GraphViz::Constants::FORMATS) (default : dot)
-
:file : Output file name (default : none)
-
:use : Program to use (GraphViz::Constants::PROGRAMS) (default : dot)
-
:path : Program PATH
# File lib/graphviz.rb, line 749 def self.parse( xFile, hOpts = {}, &block ) graph = Dot2Ruby::new( hOpts[:path], nil, nil ).eval( xFile ) yield( graph ) if( block and graph ) return graph end
Create a new graph from a GraphViz File
Options :
-
:output : Output format (GraphViz::Constants::FORMATS) (default : dot)
-
:file : Output file name (default : none)
-
:use : Program to use (GraphViz::Constants::PROGRAMS) (default : dot)
-
:path : Program PATH
# File lib/graphviz.rb, line 763 def self.parse_string( str, hOpts = {}, &block ) graph = Dot2Ruby::new(hOpts[:path], nil, nil).eval_string(str) yield(graph) if(block and graph) return graph end
# File lib/graphviz/nothugly.rb, line 47 def self.xml_xslt_transform(xml, xsl) xslt = XML::XSLT.new() xslt.xml = xml xslt.xsl = xsl xslt.serve() end
Private Class Methods
Create a new directed graph
See also ::new
# File lib/graphviz.rb, line 911 def self.digraph( xGraphName, hOpts = {}, &block ) new( xGraphName, hOpts.symbolize_keys.merge( {:type => "digraph"} ), &block ) end
Create a random graph.
# File lib/graphviz.rb, line 923 def self.generate(num_nodes, num_edges, directed = false, weight_range = (1..1)) g = nil if directed g = GraphViz.digraph(:G) else g = GraphViz.graph(:G) end nodes = (1..num_nodes).map{ |e| e.to_s } g.add_nodes(nodes) edges = [] nodes.each do |head| nodes.each do |tail| if (directed and head != tail) or (head < tail) edges << {:head => head, :tail => tail, :weight => weight_range.to_a.shuffle[0]} end end end edges.shuffle! (num_edges - 1).times do |i| g.add_edges(edges[i][:head], edges[i][:tail], :label => edges[i][:weight].to_s, :weight => edges[i][:weight]) end return g end
Create a new undirected graph
See also ::new
# File lib/graphviz.rb, line 902 def self.graph( xGraphName, hOpts = {}, &block ) new( xGraphName, hOpts.symbolize_keys.merge( {:type => "graph"} ), &block ) end
Create a new strict directed graph
See also ::new
# File lib/graphviz.rb, line 918 def self.strict_digraph( xGraphName, hOpts = {}, &block ) new( xGraphName, hOpts.symbolize_keys.merge( {:type => "digraph", :strict => true} ), &block ) end
Public Instance Methods
Create an edge between the current cluster and the node or cluster
oNode
# File lib/graphviz.rb, line 664 def <<( oNode ) raise( ArgumentError, "Edge between root graph and node or cluster not allowed!" ) if self.pg.nil? if( oNode.class == Array ) oNode.each do |no| self << no end else return GraphViz::commonGraph( oNode, self ).add_edges( self, oNode ) end end
Get the value of the graph attribute xAttrName
# File lib/graphviz.rb, line 388 def []( xAttrName ) if Hash === xAttrName xAttrName.each do |key, value| self[key] = value end else attr = @graph[xAttrName] if attr.nil? return nil else return( @graph[xAttrName].clone ) end end end
Set value xValue
to the graph attribute xAttrName
# File lib/graphviz.rb, line 380 def []=( xAttrName, xValue ) xValue = xValue.to_s if xValue.class == Symbol @graph[xAttrName] = xValue end
Add nodes and edges defined by a Hash
# File lib/graphviz.rb, line 326 def add(h) if h.kind_of? Hash h.each do |node, data| add_hash_edge(node, data) end end end
# File lib/graphviz.rb, line 185 def add_edge( oNodeOne, oNodeTwo, hOpts = {} ) if oNodeTwo.kind_of? Array or oNodeOne.kind_of? Array raise ArgumentError, "use `add_edges' to add several edges at the same time" end add_edges(oNodeOne, oNodeTwo, hOpts) end
Create a new edge
In:
-
node_one : First node (or node list)
-
node_two : Second Node (or node list)
-
options : Edge attributes
# File lib/graphviz.rb, line 198 def add_edges( node_one, node_two, options = {} ) if( node_one.class == Array ) node_one.each do |no| add_edges( no, node_two, options ) end else if( node_two.class == Array ) node_two.each do |nt| add_edges( node_one, nt, options ) end else edge = GraphViz::Edge::new( node_one, node_two, self ) edge.index = @elements_order.size_of( "edge" ) options.each do |xKey, xValue| edge[xKey.to_s] = xValue end @elements_order.push( { "type" => "edge", "value" => edge } ) @loEdges.push( edge ) return( edge ) end end end
Create a new graph
In:
-
xGraphName : Graph name
-
hOpts : Graph attributes
# File lib/graphviz.rb, line 263 def add_graph( xGraphName = nil, hOpts = {}, &block ) if xGraphName.kind_of?(GraphViz) xGraphID = xGraphName.id @hoGraphs[xGraphID] = xGraphName.clone @hoGraphs[xGraphID].type = @oGraphType @hoGraphs[xGraphID].pg = self xGraphName = xGraphID else if xGraphName.kind_of?(Hash) hOpts = xGraphName xGraphName = nil end if xGraphName.nil? xGraphID = String.random(11) xGraphName = "" else xGraphID = xGraphName end @hoGraphs[xGraphID] = GraphViz::new( xGraphName, {:parent => self, :type => @oGraphType}, &block ) hOpts.each do |xKey, xValue| @hoGraphs[xGraphID][xKey.to_s] = xValue end end @elements_order.push( { "type" => "graph", "name" => xGraphName, "value" => @hoGraphs[xGraphID] } ) return( @hoGraphs[xGraphID] ) end
# File lib/graphviz.rb, line 88 def add_node( xNodeName, hOpts = {} ) if xNodeName.kind_of? Array raise ArgumentError, "use `add_nodes' to add several nodes at the same time" end return add_nodes(xNodeName, hOpts) end
Create a new node
In:
-
xNodeName : Name of the new node
-
hOpts : Node attributes
Return the GraphViz::Node object created
# File lib/graphviz.rb, line 102 def add_nodes(node_name, options = {}) if node_name.kind_of? Array node_name.each { |n| add_nodes(n, options.clone) } else node = @hoNodes[node_name] if node.nil? @hoNodes[node_name] = GraphViz::Node::new( node_name, self ) @hoNodes[node_name].index = @elements_order.size_of( "node" ) unless options.keys.include?(:label) or options.keys.include?("label") options[:label] = node_name end @elements_order.push( { "type" => "node", "name" => node_name, "value" => @hoNodes[node_name] } ) node = @hoNodes[node_name] end options.each do |xKey, xValue| @hoNodes[node_name][xKey.to_s] = xValue end return node end end
# File lib/graphviz.rb, line 621 def append_attributes_and_types(script) script_data = DOTScriptData.new @elements_order.each { |kElement| is_new_type = script_data.type != kElement["type"] if is_new_type script << script_data unless script_data.type.nil? or script_data.empty? script_data = DOTScriptData.new(kElement["type"]) end # Modified by Brandon Coleman verify value is NOT NULL kElement["value"] or raise ArgumentError, "#{kElement["name"]} is nil!" case kElement["type"] when "graph_attr", "node_attr", "edge_attr" script_data.add_attribute(kElement["name"], kElement["value"].to_gv) when "node", "graph" script << kElement["value"].output() when "edge" script << " " + kElement["value"].output( @oGraphType ) else raise ArgumentError, "Don't know what to do with element type '#{kElement['type']}'" end } script << script_data unless script_data.type.nil? or script_data.empty? end
Return a new completed graph
# File lib/graphviz.rb, line 770 def complete GraphViz.parse_string( root_graph.output( :dot => String ) ) end
Complete the current graph
# File lib/graphviz.rb, line 775 def complete! # TODO: Keep options complete end
Return true if the graph is directed.
# File lib/graphviz.rb, line 781 def directed? not((/digraph/ =~ "bla digraph bla").nil?) end
# File lib/graphviz.rb, line 412 def each_attribut(&b) warn "`GraphViz#each_attribut` is deprecated, please use `GraphViz#each_attribute`" each_attribute(&b) end
Calls block once for each attribute of the graph, passing the name and value to the block as a two-element array.
# File lib/graphviz.rb, line 407 def each_attribute(&b) @graph.each do |k,v| yield(k,v) end end
Allow you to traverse edges
# File lib/graphviz.rb, line 231 def each_edge( &block ) if block_given? @loEdges.each do |edge| yield(edge) end else return @loEdges end end
Allow you to traverse graphs
# File lib/graphviz.rb, line 313 def each_graph( &block ) if block_given? @hoGraphs.each do |name, graph| yield( name, graph ) end else return @hoGraphs end end
Allow you to traverse nodes
# File lib/graphviz.rb, line 170 def each_node( &block ) if block_given? @hoNodes.each do |name, node| yield( name, node ) end else return( @hoNodes ) end end
Get the number of edges
# File lib/graphviz.rb, line 244 def edge_count @loEdges.size end
Returns the first node found in the entire graph, starting from the root graph
# File lib/graphviz.rb, line 143 def find_node(name) root = root_graph return root.search_node(name) end
Return the edge object for the given index
# File lib/graphviz.rb, line 251 def get_edge_at_index( index ) element = @elements_order[index, "edge"] (element.nil?) ? nil : element["value"] end
Return the graph object for the given name (or nil)
# File lib/graphviz.rb, line 302 def get_graph( xGraphName, &block ) graph = @hoGraphs[xGraphName] || nil yield( graph ) if( block and graph ) return graph end
Return the node object for the given name (or nil) in the current graph
# File lib/graphviz.rb, line 134 def get_node( xNodeName, &block ) node = @hoNodes[xNodeName] || nil yield( node ) if( block and node ) return node end
Return the node object for the given index
# File lib/graphviz.rb, line 162 def get_node_at_index( index ) element = @elements_order[index, "node"] (element.nil?) ? nil : element["value"] end
Get the number of graphs
# File lib/graphviz.rb, line 347 def graph_count @hoGraphs.size end
# File lib/graphviz.rb, line 785 def has_parent_graph? not @oParentGraph.nil? end
Get the graph name
# File lib/graphviz.rb, line 656 def name @name.clone end
Get the number of nodes
# File lib/graphviz.rb, line 181 def node_count @hoNodes.size end
Generate the graph
Options :
-
:output : Output format (GraphViz::Constants::FORMATS)
-
:file : Output file name
-
:use : Program to use (GraphViz::Constants::PROGRAMS)
-
:path : Program PATH
-
:<format> => <file> : <file> can be
-
:errors : DOT error level (default 1)
-
0 = Error + Warning
-
1 = Error
-
2 = none
-
# File lib/graphviz.rb, line 441 def output( hOpts = {} ) xDOTScript = DOTScript.new lNotHugly = [] append_attributes_and_types(xDOTScript) xDOTScript << "}" if has_parent_graph? xDOTScript.make_subgraph("#{GraphViz.escape(@name, :unquote_empty => true)}") else hOutput = {} hOpts.each do |xKey, xValue| xValue = xValue.to_s unless xValue.nil? or [Class, TrueClass, FalseClass].include?(xValue.class) case xKey.to_s when "use" if PROGRAMS.index( xValue ).nil? raise ArgumentError, "can't use '#{xValue}'" end @prog = xValue when "path" @path = xValue && xValue.split( "," ).map{ |x| x.strip } when "errors" @errors = xValue when "extlib" @extlibs = xValue.split( "," ).map{ |x| x.strip } when "scale" # Scale input by 'v' (=72) @scale = xValue when "inverty" # Invert y coordinate in output @inverty = xValue when "no_layout" # No layout mode 'v' (=1) @no_layout = xValue when "reduce" # Reduce graph @reduce_graph = xValue when "Lg" # Don't use grid @Lg = xValue when "LO" # Use old attractive force @LO = xValue when "Ln" # Set number of iterations to i @Ln = xValue when "LU" # Set unscaled factor to i @LU = xValue when "LC" # Set overlap expansion factor to v @LC = xValue when "LT" # Set temperature (temperature factor) to v @LT = xValue when "nothugly" begin require 'graphviz/nothugly' @nothugly = true rescue LoadError warn "You must install ruby-xslt or libxslt-ruby to use nothugly option!" @nothugly = false end else if FORMATS.index( xKey.to_s ).nil? raise ArgumentError, "output format '#{xValue}' invalid" end hOutput[xKey.to_s] = xValue end end @output = hOutput if hOutput.size > 0 xStict = ((@strict && @oGraphType == "digraph") ? "strict " : "") xDOTScript.prepend( "#{xStict}#{@oGraphType} #{GraphViz.escape(@name, :unquote_empty => true)} {" ) xOutputString = (@filename == String || @output.any? {|format, file| file == String }) xOutput = "" if @format.to_s == "none" or @output.any? {|fmt, fn| fmt.to_s == "none"} if xOutputString xOutput << xDOTScript else xFileName = @output["none"] || @filename open( xFileName, "w" ) do |h| h.puts xDOTScript end end end if (@format.to_s != "none" and not @format.nil?) or (@output.any? {|format, file| format != "none" } and @output.size > 0) ## Act: Save script and send it to dot t = Tempfile::open( File.basename(__FILE__) ) t.print( xDOTScript ) t.close cmd = find_executable( @prog, @path ) if cmd == nil raise StandardError, "GraphViz not installed or #{@prog} not in PATH. Install GraphViz or use the 'path' option" end xOutputWithFile = [] xOutputWithoutFile = [] unless @format.nil? or @format == "none" lNotHugly << @filename if @format.to_s == "svg" and @nothugly if @filename.nil? or @filename == String xOutputWithoutFile = ["-T#{@format}"] else xOutputWithFile = ["-T#{@format}", "-o#{@filename}"] end end @output.each_except( :key => ["none"] ) do |format, file| lNotHugly << file if format.to_s == "svg" and @nothugly if file.nil? or file == String xOutputWithoutFile += ["-T#{format}"] else xOutputWithFile += ["-T#{format}", "-o#{file}"] end end xExternalLibraries = @extlibs.map { |lib| "-l#{lib}" } xOtherOptions = [] xOtherOptions << "-s#{@scale}" if @scale xOtherOptions << "-y" if @inverty xOtherOptions << "-n#{@no_layout}" if @no_layout xOtherOptions << "-x" if @reduce_graph xOtherOptions << "-Lg" if @Lg xOtherOptions << "-LO" if @LO xOtherOptions << "-Ln#{@Ln}" if @Ln xOtherOptions << "-LU#{@LU}" if @LU xOtherOptions << "-LC#{@LC}" if @LC xOtherOptions << "-LT#{@LT}" if @LT tmpPath = if IS_JRUBY t.path elsif IS_CYGWIN begin IO.popen("cygpath", "-w", t.path).chomp rescue warn "cygpath is not installed!" t.path end else t.path end xCmd = [cmd, "-q#{@errors}"] + xExternalLibraries + xOtherOptions + xOutputWithFile + xOutputWithoutFile + [tmpPath] xOutput << output_from_command( xCmd ) end # Not Hugly lNotHugly.each do |f| if f.nil? or f == String xOutput = GraphViz.nothugly( xOutput, false ) else GraphViz.nothugly( f, true ) end end if xOutputString xOutput else print xOutput end end end
Return the root graph
# File lib/graphviz.rb, line 689 def root_graph return( (self.pg.nil?) ? self : self.pg.root_graph ) end
Return the first node found in the current graph, and it subgraphs
# File lib/graphviz.rb, line 149 def search_node(name) n = get_node(name) return n unless n.nil? each_graph { |_, g| n = g.search_node(name) return n unless n.nil? } return nil end
Create a new graph from the current subgraph
# File lib/graphviz.rb, line 418 def to_graph graph = self.clone graph.pg = nil return graph end
# File lib/graphviz.rb, line 649 def to_s self.output(:none => String) end
Return the graph type (graph digraph)
# File lib/graphviz.rb, line 337 def type @oGraphType end