Class: Graph

Inherits:
Object
  • Object
show all
Defined in:
lib/graph.rb

Overview

Graph models directed graphs and subgraphs and outputs in graphviz’s dot format.

Defined Under Namespace

Classes: Attribute, Edge, Node, Thingy

Constant Summary collapse

VERSION =

:nodoc:

"2.2.0"
LIGHT_COLORS =
%w(gray lightblue lightcyan lightgray lightpink
lightslategray lightsteelblue white)
BOLD_COLORS =

WTF – can’t be %w() because of a bug in rcov

["black", "brown", "mediumblue", "blueviolet",
"orange", "magenta", "darkgreen", "maroon",
"violetred", "purple", "greenyellow", "deeppink",
"midnightblue", "firebrick", "darkturquoise",
"mediumspringgreen", "chartreuse", "navy",
"lightseagreen", "chocolate", "lawngreen", "green",
"indigo", "darkgoldenrod", "darkviolet", "red",
"springgreen", "saddlebrown", "mediumvioletred",
"goldenrod", "tomato", "cyan", "forestgreen",
"darkorchid", "crimson", "coral", "deepskyblue",
"seagreen", "peru", "turquoise", "orangered",
"dodgerblue", "sienna", "limegreen", "royalblue",
"darkorange", "blue"]
COLOR_SCHEME_MAX =

Defines the brewer color schemes and the maximum number of colors in each set.

{
  :accent   => 8,  :blues    => 9,  :brbg     => 11, :bugn     => 9,
  :dark2    => 8,  :gnbu     => 9,  :greens   => 9,  :greys    => 9,
  :oranges  => 9,  :orrd     => 9,  :paired   => 12, :pastel1  => 9,
  :pastel2  => 8,  :piyg     => 11, :prgn     => 11, :pubu     => 9,
  :pubugn   => 9,  :puor     => 11, :purd     => 9,  :purples  => 9,
  :rdbu     => 11, :rdgy     => 11, :rdylbu   => 11, :rdylgn   => 11,
  :reds     => 9,  :set1     => 9,  :set2     => 8,  :set3     => 12,
  :spectral => 11, :ylgn     => 9,  :ylgnbu   => 9,  :ylorbr   => 9,
  :ylorrd   => 9
}
SHAPES =
%w(Mcircle Mdiamond Msquare box box3d circle component
diamond doublecircle doubleoctagon egg ellipse folder
hexagon house invhouse invtrapezium invtriangle none
note octagon parallelogram pentagon plaintext point
polygon rect rectangle septagon square tab trapezium
triangle tripleoctagon)
STYLES =
%w(dashed dotted solid invis bold filled diagonals rounded)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = nil, graph = nil, &block) ⇒ Graph

Creates a new graph object. Optional name and parent graph are available. Also takes an optional block for DSL-like use.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/graph.rb', line 112

def initialize name = nil, graph = nil, &block
  @name = name
  @graph = graph
  graph << self if graph
  @nodes  = Hash.new { |h,k| h[k] = Node.new self, k }
  @edges  = Hash.new { |h,k|
    h[k] = Hash.new { |h2, k2| h2[k2] = Edge.new self, self[k], self[k2] }
  }
  @graph_attribs = []
  @node_attribs  = []
  @edge_attribs  = []
  @subgraphs     = []

  instance_eval(&block) if block
end

Instance Attribute Details

#edge_attribsObject (readonly)

Global attributes for edges in this graph.



81
82
83
# File 'lib/graph.rb', line 81

def edge_attribs
  @edge_attribs
end

#edgesObject (readonly)

The hash of hashes of edges in this graph. Use #[] or #node to create edges.



86
87
88
# File 'lib/graph.rb', line 86

def edges
  @edges
end

#graphObject

A parent graph, if any. Only used for subgraphs.



70
71
72
# File 'lib/graph.rb', line 70

def graph
  @graph
end

#graph_attribsObject (readonly)

Global attributes for this graph.



91
92
93
# File 'lib/graph.rb', line 91

def graph_attribs
  @graph_attribs
end

#nameObject

The name of the graph. Optional for graphs and subgraphs. Prefix the name of a subgraph with “cluster” for subgraph that is boxed.



76
77
78
# File 'lib/graph.rb', line 76

def name
  @name
end

#node_attribsObject (readonly)

Global attributes for nodes in this graph.



96
97
98
# File 'lib/graph.rb', line 96

def node_attribs
  @node_attribs
end

#nodesObject (readonly)

The hash of nodes in this graph. Use #[] or #node to create nodes.



101
102
103
# File 'lib/graph.rb', line 101

def nodes
  @nodes
end

#subgraphsObject (readonly)

An array of subgraphs.



106
107
108
# File 'lib/graph.rb', line 106

def subgraphs
  @subgraphs
end

Instance Method Details

#<<(subgraph) ⇒ Object

Push a subgraph into the current graph. Sets the subgraph’s graph to self.



131
132
133
134
# File 'lib/graph.rb', line 131

def << subgraph
  subgraphs << subgraph
  subgraph.graph = self
end

#[](name) ⇒ Object

Access a node by name



139
140
141
# File 'lib/graph.rb', line 139

def [] name
  nodes[name]
end

#boxesObject

A convenience method to set the global node attributes to use boxes.



146
147
148
# File 'lib/graph.rb', line 146

def boxes
  node_attribs << shape("box")
end

#cluster(name, &block) ⇒ Object

Shortcut method to create a clustered subgraph in the current graph. Use with the top-level digraph method in block form for a graph DSL.



298
299
300
# File 'lib/graph.rb', line 298

def cluster name, &block
  subgraph "cluster_#{name}", &block
end

#color(color) ⇒ Object

Shortcut method to create a new color Attribute instance.



153
154
155
# File 'lib/graph.rb', line 153

def color color
  Attribute.new "color = #{color}"
end

#colorscheme(name, n = nil) ⇒ Object

Shortcut method to create a new colorscheme Attribute instance. If passed n, name must match one of the brewer color scheme names and it will generate accessors for each fillcolor as well as push the colorscheme onto the node_attribs.



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/graph.rb', line 163

def colorscheme name, n = nil
  scheme = Attribute.new "colorscheme = #{name}#{n}"
  max = COLOR_SCHEME_MAX[name.to_sym]

  if max then
    node_attribs << scheme

    mc = (class << self; self; end)

    (1..n).map { |m|
      mc.send :attr_accessor, "c#{m}"
      self.send "c#{m}=", Graph::Attribute.new("fillcolor = #{m}")
    }
  end

  scheme
end

#edge(*names) ⇒ Object

Define one or more edges.

edge "a", "b", "c", ...

is equivalent to:

edge "a", "b"
edge "b", "c"
...


192
193
194
195
196
197
198
# File 'lib/graph.rb', line 192

def edge(*names)
  last = nil
  names.each_cons(2) do |from, to|
    last = self[from][to]
  end
  last
end

#fillcolor(n) ⇒ Object

Shortcut method to create a new fillcolor Attribute instance.



216
217
218
# File 'lib/graph.rb', line 216

def fillcolor n
  Attribute.new "fillcolor = #{n}"
end

#font(name, size = nil) ⇒ Object

Shortcut method to create a new font Attribute instance. You can pass in both the name and an optional font size.



224
225
226
227
# File 'lib/graph.rb', line 224

def font name, size=nil
  Attribute.new "fontname = #{name.inspect}" +
    (size ? ", fontsize = #{size}" : "")
end

#invertObject

Creates a new Graph whose edges point the other direction.



203
204
205
206
207
208
209
210
211
# File 'lib/graph.rb', line 203

def invert
  result = self.class.new
  edges.each do |from, h|
    h.each do |to, edge|
      result[to][from]
    end
  end
  result
end

#label(name) ⇒ Object

Shortcut method to set the graph’s label. Usually used with subgraphs.



232
233
234
# File 'lib/graph.rb', line 232

def label name
  graph_attribs << "label = \"#{name.gsub(/\n/, '\n')}\""
end

#node(name, label = nil) ⇒ Object

Access a node by name, supplying an optional label



239
240
241
242
243
# File 'lib/graph.rb', line 239

def node name, label = nil
  n = nodes[name]
  n.label label if label
  n
end

#orient(dir = "TB") ⇒ Object

Shortcut method to specify the orientation of the graph. Defaults to the graphviz default “TB”.



249
250
251
# File 'lib/graph.rb', line 249

def orient dir = "TB"
  graph_attribs << "rankdir = #{dir}"
end

#rotate(dir = "LR") ⇒ Object

Shortcut method to specify the orientation of the graph. Defaults to “LR”.



256
257
258
# File 'lib/graph.rb', line 256

def rotate dir = "LR"
  orient dir
end

#save(path, type = nil) ⇒ Object

Saves out both a dot file to path and an image for the specified type. Specify type as nil to skip exporting an image.



264
265
266
267
268
269
# File 'lib/graph.rb', line 264

def save path, type = nil
  File.open "#{path}.dot", "w" do |f|
    f.puts self.to_s
  end
  system "dot -T#{type} #{path}.dot > #{path}.#{type}" if type
end

#shape(shape) ⇒ Object

Shortcut method to create a new shape Attribute instance.



274
275
276
# File 'lib/graph.rb', line 274

def shape shape
  Attribute.new "shape = #{shape}"
end

#style(name) ⇒ Object

Shortcut method to create a new style Attribute instance.



281
282
283
# File 'lib/graph.rb', line 281

def style name
  Attribute.new "style = #{name}"
end

#subgraph(name = nil, &block) ⇒ Object

Shortcut method to create a subgraph in the current graph. Use with the top-level digraph method in block form for a graph DSL.



289
290
291
# File 'lib/graph.rb', line 289

def subgraph name = nil, &block
  Graph.new name, self, &block
end

#to_sObject

Outputs a graphviz graph.



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/graph.rb', line 305

def to_s
  result = []

  type = graph ? "subgraph" : "digraph"
  result << "#{type} #{name}"
  result << "  {"

  graph_attribs.each do |line|
    result << "    #{line};"
  end

  unless node_attribs.empty? then
    result << "    node [ #{node_attribs.join(", ")} ];"
  end

  unless edge_attribs.empty? then
    result << "    edge [ #{edge_attribs.join(", ")} ];"
  end

  subgraphs.each do |line|
    result << "    #{line};"
  end

  nodes.each do |name, node|
    result << "    #{node};" if graph or node.attributes? or node.orphan?
  end

  edges.each do |from, deps|
    deps.each do |to, edge|
      result << "    #{edge};"
    end
  end

  result << "  }"
  result.join "\n"
end