Class: Rubyvis::Layout::Matrix

Inherits:
Network show all
Defined in:
lib/rubyvis/layout/matrix.rb

Overview

Implements a network visualization using a matrix view. This is, in effect, a visualization of the graph’s adjacency matrix: the cell at row i, column j, corresponds to the link from node i to node j. The fill color of each cell is binary by default, and corresponds to whether a link exists between the two nodes. If the underlying graph has links with variable values, the fillStyle property can be substited to use an appropriate color function, such as pv.ramp.

<p>For undirected networks, the matrix is symmetric around the diagonal. For directed networks, links in opposite directions can be rendered on opposite sides of the diagonal using directed(true). The graph is assumed to be undirected by default.

<p>The mark prototypes for this network layout are slightly different than other implementations:<ul>

<li>node - unsupported; undefined. No mark is needed to visualize nodes directly, as the nodes are implicit in the location (rows and columns) of the links.

<p><li>link - for rendering links; typically a pv.Bar. The link mark is added directly to the layout, with the data property defined as all possible pairs of nodes. Each pair is represented as a pv.Network.Layout.Link, though the linkValue attribute may be 0 if no link exists in the graph.

<p><li>label - for rendering node labels; typically a pv.Label. The label mark is added directly to the layout, with the data property defined via the layout’s nodes property; note, however, that the nodes are duplicated so as to provide a label across the top and down the side. Properties such as strokeStyle and fillStyle can be overridden to compute properties from node data dynamically.

</ul>For more details on how to use this layout, see pv.Layout.Network.

Instance Attribute Summary collapse

Attributes inherited from Network

#_id, #link, #node, #node_label

Attributes inherited from Panel

#_canvas, #children, #root

Attributes inherited from Mark

#_properties, #binds, #child_index, #parent, #proto, #root, #scale, #scene, #target

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Network

#_node, #_node_label, #build_properties, #network_build_implied, #nodes, #reset

Methods inherited from Rubyvis::Layout

Arc, Cluster, Grid, Hierarchy, Horizon, Indent, Matrix, Network, Pack, Partition, Stack, Tree, Treemap, attr_accessor_dsl, #build_properties, #layout_build_implied, #layout_build_properties

Methods inherited from Panel

#add, #anchor, #bind, #build_instance, #children_inspect, #panel_build_implied, #to_svg, #type

Methods inherited from Bar

#type, #width

Methods inherited from Mark

#add, #anchor, #area, attr_accessor_dsl, #bar, #bind, #build, #build_instance, #build_properties, #context, #context_apply, #context_clear, #cousin, #delete_index, #dot, #event, #execute, #first, #image, index, #index, index=, #index=, #index_defined?, #instance, #instances, #label, #last, #layout_arc, #layout_cluster, #layout_grid, #layout_horizon, #layout_indent, #layout_matrix, #layout_pack, #layout_partition, #layout_partition_fill, #layout_stack, #layout_tree, #layout_treemap, #line, #margin, #mark_anchor, #mark_bind, #mark_build_implied, #mark_build_instance, #mark_build_properties, #mark_extend, mark_method, #panel, #properties, properties, property_method, #property_value, #render, #rule, scene, scene=, #sibling, stack, stack=, #type, #wedge

Constructor Details

#initializeMatrix

Returns a new instance of Matrix.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/rubyvis/layout/matrix.rb', line 66

def initialize
  super
  @_n=nil, # cached matrix size
  @_dx=nil, # cached cell width
  @_dy=nil, # cached cell height
  @_labels=nil, # cached labels (array of strings)
  @_pairs=nil, # cached pairs (array of links)
  that=self
  #/* Links are all pairs of nodes. */
  @link.data(lambda  {that._pairs}).
    left(lambda { that._dx * (self.index % that._n) }).
    top(lambda  { that._dy * (self.index / that._n.to_f).floor }).
    width(lambda  { that._dx }).
    height(lambda  { that._dy }).
    line_width(1.5).
    stroke_style("#fff").
  fill_style(lambda {|l| l.link_value!=0 ? "#555" : "#eee" })

  @link.parent = self
  #/* No special add for links! */

  # delete this.link.add;

  #/* Labels are duplicated for top & left. */
  @node_label.
  data(lambda  { that._labels }).
  left(lambda  { (self.index & 1)!=0 ? that._dx * ((self.index >> 1) + 0.5) : 0 }).
  top(lambda  { (self.index & 1)!=0 ? 0 : that._dy * ((self.index >> 1) + 0.5) }).
  text_margin(4).text_align(lambda  { (self.index & 1)!=0 ? "left" : "right"; }).
  text_angle(lambda  { (self.index & 1)!=0 ? -Math::PI / 2.0 : 0; });
  @node=nil
end

Instance Attribute Details

#_dxObject

Returns the value of attribute _dx.



46
47
48
# File 'lib/rubyvis/layout/matrix.rb', line 46

def _dx
  @_dx
end

#_dyObject

Returns the value of attribute _dy.



46
47
48
# File 'lib/rubyvis/layout/matrix.rb', line 46

def _dy
  @_dy
end

#_labelsObject

Returns the value of attribute _labels.



46
47
48
# File 'lib/rubyvis/layout/matrix.rb', line 46

def _labels
  @_labels
end

#_nObject

Returns the value of attribute _n.



46
47
48
# File 'lib/rubyvis/layout/matrix.rb', line 46

def _n
  @_n
end

#_pairsObject

Returns the value of attribute _pairs.



46
47
48
# File 'lib/rubyvis/layout/matrix.rb', line 46

def _pairs
  @_pairs
end

Class Method Details

.defaultsObject



98
99
100
101
# File 'lib/rubyvis/layout/matrix.rb', line 98

def self.defaults
  Matrix.new.mark_extend(Network.defaults).
  directed(true)
end

Instance Method Details

Deletes special add from network



55
56
57
58
59
60
61
62
63
64
# File 'lib/rubyvis/layout/matrix.rb', line 55

def _link # :nodoc:
  #that=self
  l=Mark.new().
  mark_extend(@node).
  data(lambda {|d| [d.source_node, d.target_node] }).
  fill_style(nil).
  line_width(lambda {|d,_p| _p.link_value * 1.5 }).
  stroke_style("rgba(0,0,0,.2)")
  l
end

#build_implied(s) ⇒ Object

:nodoc:



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/rubyvis/layout/matrix.rb', line 138

def build_implied(s) # :nodoc:
  return nil if network_build_implied(s)
  nodes = s.nodes
  links = s.links
  sort = @sort

  n = nodes.size
  index = Rubyvis.range(n)
  labels = []
  pairs = []
  map = {}

  s._matrix = OpenStruct.new({:labels=> labels, :pairs=> pairs})

  #/* Sort the nodes. */
  if sort
    index.sort! {|a,b| sort.call(nodes[a],nodes[b])}
  end
  #/* Create pairs. */
  n.times {|i|
    n.times {|j|
      a = index[i]
      b = index[j]
      _p = OpenStruct.new({
        :row=> i,
        :col=> j,
        :source_node=> nodes[a],
        :target_node=> nodes[b],
      :link_value=> 0})
      map["#{a}.#{b}"] = _p
      pairs.push(map["#{a}.#{b}"])
    }
  }
  #/* Create labels. */
  n.times {|i|
    a = index[i]
    labels.push(nodes[a], nodes[a])
  }
  #/* Accumulate link values. */
  links.each_with_index {|l,i|
    source = l.source_node.index
    target = l.target_node.index
    value = l.link_value
    map["#{source}.#{target}"].link_value += value
    map["#{target}.#{source}"].link_value += value if (!s.directed)
  }
  build_implied_post(s)
end

#build_implied_post(s) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/rubyvis/layout/matrix.rb', line 47

def build_implied_post(s)
  @_n = s.nodes.size
  @_dx = s.width.to_f / @_n
  @_dy = s.height.to_f / @_n
  @_labels = s._matrix.labels
  @_pairs = s._matrix.pairs
end

#directedObject

:attr: directed

Whether this matrix visualization is directed (bidirectional). By default, the graph is assumed to be undirected, such that the visualization is symmetric across the matrix diagonal. If the network is directed, then forward links are drawn above the diagonal, while reverse links are drawn below.

/



115
# File 'lib/rubyvis/layout/matrix.rb', line 115

attr_accessor_dsl :directed

#sort(f = nil, &block) ⇒ Object

Specifies an optional sort function. The sort function follows the same comparator contract required by pv.Dom.Node#sort. Specifying a sort function provides an alternative to sort the nodes as they are specified by the nodes property; the main advantage of doing this is that the comparator function can access implicit fields populated by the network layout, such as the linkDegree.

<p>Note that matrix visualizations are particularly sensitive to order. This is referred to as the seriation problem, and many different techniques exist to find good node orders that emphasize clusters, such as spectral layout and simulated annealing.

/

Parameters:

  • f (function) (defaults to: nil)

    comparator function for nodes.



133
134
135
136
137
# File 'lib/rubyvis/layout/matrix.rb', line 133

def sort(f=nil,&block)
  f||=block
  @sort=f
  self
end