rubyvis 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/Manifest.txt +4 -0
- data/README.txt +3 -0
- data/Rakefile +17 -2
- data/examples/6_pv_networks/matrix.rb +34 -0
- data/lib/rubyvis/layout/arc.rb +31 -36
- data/lib/rubyvis/layout/cluster.rb +5 -5
- data/lib/rubyvis/layout/horizon.rb +2 -2
- data/lib/rubyvis/layout/matrix.rb +188 -0
- data/lib/rubyvis/layout/network.rb +8 -11
- data/lib/rubyvis/layout/pack.rb +3 -3
- data/lib/rubyvis/layout/partition.rb +2 -2
- data/lib/rubyvis/layout/tree.rb +1 -1
- data/lib/rubyvis/layout/treemap.rb +8 -7
- data/lib/rubyvis/layout.rb +1 -0
- data/lib/rubyvis/mark/shorcut_methods.rb +14 -0
- data/lib/rubyvis/sceneelement.rb +1 -1
- data/lib/rubyvis.rb +1 -1
- data/spec/layout_arc_spec.rb +87 -0
- data/spec/layout_matrix_spec.rb +80 -0
- data/spec/spec_helper.rb +26 -0
- data.tar.gz.sig +0 -0
- metadata +8 -4
- metadata.gz.sig +0 -0
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -46,6 +46,7 @@ examples/5_pv_hierarchies/node_link_tree.rb
|
|
46
46
|
examples/5_pv_hierarchies/sunburst.rb
|
47
47
|
examples/5_pv_hierarchies/treemap.rb
|
48
48
|
examples/6_pv_networks/arc.rb
|
49
|
+
examples/6_pv_networks/matrix.rb
|
49
50
|
examples/6_pv_networks/miserables_data.rb
|
50
51
|
lib/rubyvis.rb
|
51
52
|
lib/rubyvis/color/color.rb
|
@@ -65,6 +66,7 @@ lib/rubyvis/layout/grid.rb
|
|
65
66
|
lib/rubyvis/layout/hierarchy.rb
|
66
67
|
lib/rubyvis/layout/horizon.rb
|
67
68
|
lib/rubyvis/layout/indent.rb
|
69
|
+
lib/rubyvis/layout/matrix.rb
|
68
70
|
lib/rubyvis/layout/network.rb
|
69
71
|
lib/rubyvis/layout/pack.rb
|
70
72
|
lib/rubyvis/layout/partition.rb
|
@@ -112,7 +114,9 @@ spec/histogram_spec.rb
|
|
112
114
|
spec/internal_spec.rb
|
113
115
|
spec/javascript_behaviour_spec.rb
|
114
116
|
spec/label_spec.rb
|
117
|
+
spec/layout_arc_spec.rb
|
115
118
|
spec/layout_horizon_spec.rb
|
119
|
+
spec/layout_matrix_spec.rb
|
116
120
|
spec/layout_stack_spec.rb
|
117
121
|
spec/line_spec.rb
|
118
122
|
spec/mark_spec.rb
|
data/README.txt
CHANGED
@@ -33,6 +33,8 @@ Using protovis examples[http://vis.stanford.edu/protovis/ex/] as reference
|
|
33
33
|
* Node-Link Tree
|
34
34
|
* Sunburst
|
35
35
|
* Treemap
|
36
|
+
* Networks:
|
37
|
+
* Arc
|
36
38
|
|
37
39
|
|
38
40
|
I try to maintain, when posible, complete compatibility with Javascript API, including camel case naming of functions. Johnson [http://github.com/jbarnette/johnson] - the lovely Javascript wrapper inside Ruby embrace - is our friend to test implementation of basic object.
|
@@ -54,6 +56,7 @@ User could use +pv+ freely, cause is defined as a global method which call Rubyv
|
|
54
56
|
* data/QuantitativeScale.js
|
55
57
|
* data/OrdinalScale.js
|
56
58
|
* data/Scale.js
|
59
|
+
* layout/Arc.js
|
57
60
|
* layout/Layout.js
|
58
61
|
* layout/Cluster.js
|
59
62
|
* layout/Grid.js
|
data/Rakefile
CHANGED
@@ -11,13 +11,28 @@ require 'rspec/core/rake_task'
|
|
11
11
|
|
12
12
|
Hoe.plugin :git
|
13
13
|
|
14
|
-
Hoe.spec 'rubyvis' do
|
14
|
+
h=Hoe.spec 'rubyvis' do
|
15
15
|
self.testlib=:rspec
|
16
|
-
#self.test_globs="spec/*_spec.rb"
|
17
16
|
self.rspec_options << "-c" << "-b"
|
18
17
|
self.developer('Claudio Bustos', 'clbustos_at_gmail.com')
|
19
18
|
self.version=Rubyvis::VERSION
|
20
19
|
self.extra_dev_deps << ["coderay",">=0"] << ["haml",">=0"] << ["nokogiri", ">=0"] << ["rspec",">=2.0"]
|
21
20
|
end
|
22
21
|
|
22
|
+
task :publicar_docs => [:clean, :docs] do
|
23
|
+
#ruby %{agregar_adsense_a_doc.rb}
|
24
|
+
path = File.expand_path("~/.rubyforge/user-config.yml")
|
25
|
+
config = YAML.load(File.read(path))
|
26
|
+
host = "#{config["username"]}@rubyforge.org"
|
27
|
+
|
28
|
+
remote_dir = "/var/www/gforge-projects/#{h.rubyforge_name}/#{h.remote_rdoc_dir
|
29
|
+
}"
|
30
|
+
local_dir = h.local_rdoc_dir
|
31
|
+
Dir.glob(local_dir+"/**/*") {|file|
|
32
|
+
sh %{chmod 755 #{file}}
|
33
|
+
}
|
34
|
+
sh %{rsync #{h.rsync_args} #{local_dir}/ #{host}:#{remote_dir}}
|
35
|
+
end
|
36
|
+
|
37
|
+
|
23
38
|
# vim: syntax=ruby
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# = Matrix Diagrams
|
2
|
+
# A graph can be represented by an adjacency matrix, where each value in row i and column j corresponds to the link from node i to node j. Given this representation, an obvious visualization then is: show the matrix! Using color or saturation instead of text allows patterns to be perceived rapidly. The seriation problem applies just as much to the matrix view as to the arc diagram, so the order of rows and columns is important: here we use a community-detection algorithm to order and color the display.
|
3
|
+
# While path following is harder in a matrix view than in a node-link diagram, matrices have a number of compensating advantages. As networks get large and highly connected, node-link diagrams often devolve into giant hairballs of line crossings. In matrix views, however, line crossings are impossible, and with an effective sorting one quickly can spot clusters and bridges. Allowing interactive grouping and reordering of the matrix facilitates deeper exploration of network structure.
|
4
|
+
# This network represents character co-occurrence in the chapters of Victor Hugo's classic novel, Les Misérables. Node colors depict cluster memberships computed by a community-detection algorithm. Source: Knuth, D. E. 1993. The Stanford GraphBase: A Platform for Combinatorial Computing, Addison-Wesley.
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__)+"/../../lib")
|
7
|
+
require 'rubyvis'
|
8
|
+
load(File.dirname(__FILE__)+"/miserables_data.rb")
|
9
|
+
color=Rubyvis::Colors.category19
|
10
|
+
|
11
|
+
|
12
|
+
vis = Rubyvis::Panel.new() do
|
13
|
+
width 693
|
14
|
+
height 693
|
15
|
+
top 90
|
16
|
+
left 90
|
17
|
+
layout_matrix do
|
18
|
+
nodes $miserables.nodes
|
19
|
+
links $miserables.links
|
20
|
+
sort {|a,b| b.group<=>a.group }
|
21
|
+
directed (false)
|
22
|
+
link.bar do
|
23
|
+
fill_style {|l| l.link_value!=0 ?
|
24
|
+
((l.target_node.group == l.source_node.group) ? color[l.source_node.group] : "#555") : "#eee"}
|
25
|
+
antialias(false)
|
26
|
+
line_width(1)
|
27
|
+
end
|
28
|
+
node_label.label do
|
29
|
+
text_style {|l| color[l.group]}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
vis.render()
|
34
|
+
puts vis.to_svg
|
data/lib/rubyvis/layout/arc.rb
CHANGED
@@ -5,7 +5,7 @@ module Rubyvis
|
|
5
5
|
Rubyvis::Layout::Arc
|
6
6
|
end
|
7
7
|
|
8
|
-
#
|
8
|
+
# Implements a layout for arc diagrams. An arc diagram is a network
|
9
9
|
# visualization with a one-dimensional layout of nodes, using circular arcs to
|
10
10
|
# render links between nodes. For undirected networks, arcs are rendering on a
|
11
11
|
# single side; this makes arc diagrams useful as annotations to other
|
@@ -16,28 +16,27 @@ module Rubyvis
|
|
16
16
|
# <p>Arc layouts are particularly sensitive to node ordering; for best results,
|
17
17
|
# order the nodes such that related nodes are close to each other. A poor
|
18
18
|
# (e.g., random) order may result in large arcs with crossovers that impede
|
19
|
-
# visual processing. A future improvement to this layout may include automatic
|
20
|
-
# reordering using, e.g., spectral graph layout or simulated annealing.
|
19
|
+
# visual processing. A future improvement to this layout may include automatic reordering using, e.g., spectral graph layout or simulated annealing.
|
21
20
|
#
|
22
|
-
#
|
23
|
-
# M. Wattenberg, <a
|
24
|
-
# href="http://www.research.ibm.com/visual/papers/arc-diagrams.pdf">"Arc
|
25
|
-
# Diagrams: Visualizing Structure in Strings"</a> in <i>IEEE InfoVis</i>, 2002.
|
21
|
+
# This visualization technique is related to that developed by M. Wattenberg, {Arc Diagrams: Visualizing Structure in Strings}[http://www.research.ibm.com/visual/papers/arc-diagrams.pdf] in IEEE InfoVis, 2002.
|
26
22
|
# However, this implementation is limited to simple node-link networks, as
|
27
23
|
# opposed to structures with hierarchical self-similarity (such as strings).
|
24
|
+
# As with other network layouts, three mark prototypes are provided:<ul>
|
28
25
|
#
|
29
|
-
# <
|
26
|
+
# <li><tt>node</tt> - for rendering nodes; typically a Rubyvis::Dot
|
27
|
+
# <li><tt>link</tt> - for rendering links; typically a Rubyvis::Line
|
28
|
+
# <li><tt>node_label</tt> - for rendering node labels; typically a Rubyvis::Label
|
30
29
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# </ul>For more details on how this layout is structured and can be customized,
|
36
|
-
# see {@link pv.Layout.Network}.
|
30
|
+
# </ul>
|
31
|
+
# For more details on how this layout is structured and can be customized,
|
32
|
+
# see Rubyvis::Layout::Network
|
37
33
|
|
38
34
|
class Arc < Network
|
39
|
-
@properties=Network.properties.dup
|
40
|
-
|
35
|
+
@properties=Network.properties.dup
|
36
|
+
|
37
|
+
attr_accessor :_interpolate # :nodoc:
|
38
|
+
attr_accessor :_directed # :nodoc:
|
39
|
+
attr_accessor :_reverse # :nodoc:
|
41
40
|
def initialize
|
42
41
|
super
|
43
42
|
@_interpolate=nil # cached interpolate
|
@@ -51,7 +50,7 @@ module Rubyvis
|
|
51
50
|
}).interpolate(lambda{ that._interpolate})
|
52
51
|
end
|
53
52
|
|
54
|
-
def build_implied(s)
|
53
|
+
def build_implied(s) # :nodoc:
|
55
54
|
return true if network_build_implied(s)
|
56
55
|
# Cached
|
57
56
|
|
@@ -87,17 +86,17 @@ module Rubyvis
|
|
87
86
|
|
88
87
|
# /** @private Returns the x-position, given the breadth. */
|
89
88
|
x= lambda do |b|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
89
|
+
case orient
|
90
|
+
when "top"
|
91
|
+
b * w
|
92
|
+
when "bottom"
|
93
|
+
b * w
|
94
|
+
when "left"
|
95
|
+
0;
|
96
|
+
when "right"
|
97
|
+
w;
|
98
|
+
when "radial"
|
99
|
+
w / 2.0 + r * Math.cos(mid_angle.call(b))
|
101
100
|
end
|
102
101
|
end
|
103
102
|
|
@@ -135,8 +134,7 @@ module Rubyvis
|
|
135
134
|
|
136
135
|
##
|
137
136
|
# :attr: orient
|
138
|
-
# The orientation. The default orientation is "
|
139
|
-
# will be positioned from left-to-right in the order they are specified in the
|
137
|
+
# The orientation. The default orientation is "bottom", which means that nodes will be positioned from bottom-to-top in the order they are specified in the
|
140
138
|
# <tt>nodes</tt> property. The following orientations are supported:<ul>
|
141
139
|
#
|
142
140
|
# <li>left - left-to-right.
|
@@ -155,26 +153,23 @@ module Rubyvis
|
|
155
153
|
# respectively), while reverse links are drawn on the opposite side.
|
156
154
|
|
157
155
|
attr_accessor_dsl :orient, :directed
|
158
|
-
|
156
|
+
# Default properties for arc layouts. By default, the orientation is "bottom".
|
159
157
|
def self.defaults
|
160
158
|
Arc.new.mark_extend(Network.defaults).
|
161
159
|
orient("bottom")
|
162
160
|
end
|
163
161
|
|
164
162
|
# Specifies an optional sort function. The sort function follows the same
|
165
|
-
# comparator contract required by
|
163
|
+
# comparator contract required by Rubyvis::Dom::Node.sort(). Specifying a sort
|
166
164
|
# function provides an alternative to sort the nodes as they are specified by
|
167
165
|
# the <tt>nodes</tt> property; the main advantage of doing this is that the
|
168
166
|
# comparator function can access implicit fields populated by the network
|
169
|
-
# layout, such as the <tt>
|
167
|
+
# layout, such as the <tt>link_degree</tt>.
|
170
168
|
#
|
171
169
|
# <p>Note that arc diagrams are particularly sensitive to order. This is
|
172
170
|
# referred to as the seriation problem, and many different techniques exist to
|
173
171
|
# find good node orders that emphasize clusters, such as spectral layout and
|
174
172
|
# simulated annealing.
|
175
|
-
#
|
176
|
-
# @param {function} f comparator function for nodes.
|
177
|
-
# @returns {pv.Layout.Arc} this.
|
178
173
|
def sort(f=nil,&block)
|
179
174
|
f||=block
|
180
175
|
@_sort=f
|
@@ -18,7 +18,7 @@ module Rubyvis
|
|
18
18
|
# sizing for leaf nodes; all leaf nodes are the same size.
|
19
19
|
#
|
20
20
|
# <p>For more details on how to use this layout, see
|
21
|
-
#
|
21
|
+
# Rubyvis::Layout::Hierarchy.
|
22
22
|
#
|
23
23
|
# @see pv.Layout.Cluster.Fill
|
24
24
|
# @extends pv.Layout.Hierarchy
|
@@ -141,9 +141,9 @@ module Rubyvis
|
|
141
141
|
if (n.first_child)
|
142
142
|
n.breadth = Rubyvis.mean(n.child_nodes, lambda {|nn| nn.breadth })
|
143
143
|
else
|
144
|
-
|
145
|
-
|
146
|
-
|
144
|
+
if (group!=0 and (par != n.parent_node))
|
145
|
+
par = n.parent_node
|
146
|
+
leaf_index += group
|
147
147
|
end
|
148
148
|
n.breadth = breadth * leaf_index
|
149
149
|
leaf_index+=1
|
@@ -179,7 +179,7 @@ module Rubyvis
|
|
179
179
|
# in the arrangement of the space-filling nodes.
|
180
180
|
#
|
181
181
|
# <p><li><tt>label</tt> - for rendering node labels; typically a
|
182
|
-
#
|
182
|
+
# Rubyvis::Label.
|
183
183
|
#
|
184
184
|
# </ul>For more details on how to use this layout, see
|
185
185
|
# {@link pv.Layout.Cluster}.
|
@@ -9,9 +9,9 @@ module Rubyvis
|
|
9
9
|
# area chart where the area is folded into multiple bands. Color is used to
|
10
10
|
# encode band, allowing the size of the chart to be reduced significantly
|
11
11
|
# without impeding readability. This layout algorithm is based on the work of
|
12
|
-
# J. Heer, N. Kong and M. Agrawala in
|
12
|
+
# J. Heer, N. Kong and M. Agrawala in {Sizing
|
13
13
|
# the Horizon: The Effects of Chart Size and Layering on the Graphical
|
14
|
-
# Perception of Time Series Visualizations
|
14
|
+
# Perception of Time Series Visualizations}[http://hci.stanford.edu/publications/2009/heer-horizon-chi09.pdf], CHI 2009.
|
15
15
|
#
|
16
16
|
# <p>This layout exports a single <tt>band</tt> mark prototype, which is
|
17
17
|
# intended to be used with an area mark. The band mark is contained in a panel
|
@@ -0,0 +1,188 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
class Layout
|
3
|
+
# Alias for Rubyvis::Layout::Matrix
|
4
|
+
def self.Matrix
|
5
|
+
Rubyvis::Layout::Matrix
|
6
|
+
end
|
7
|
+
|
8
|
+
# Implements a network visualization using a matrix view. This is, in
|
9
|
+
# effect, a visualization of the graph's <i>adjacency matrix</i>: the cell at
|
10
|
+
# row <i>i</i>, column <i>j</i>, corresponds to the link from node <i>i</i> to
|
11
|
+
# node <i>j</i>. The fill color of each cell is binary by default, and
|
12
|
+
# corresponds to whether a link exists between the two nodes. If the underlying
|
13
|
+
# graph has links with variable values, the <tt>fillStyle</tt> property can be
|
14
|
+
# substited to use an appropriate color function, such as {@link pv.ramp}.
|
15
|
+
#
|
16
|
+
# <p>For undirected networks, the matrix is symmetric around the diagonal. For
|
17
|
+
# directed networks, links in opposite directions can be rendered on opposite
|
18
|
+
# sides of the diagonal using <tt>directed(true)</tt>. The graph is assumed to
|
19
|
+
# be undirected by default.
|
20
|
+
#
|
21
|
+
# <p>The mark prototypes for this network layout are slightly different than
|
22
|
+
# other implementations:<ul>
|
23
|
+
#
|
24
|
+
# <li><tt>node</tt> - unsupported; undefined. No mark is needed to visualize
|
25
|
+
# nodes directly, as the nodes are implicit in the location (rows and columns)
|
26
|
+
# of the links.
|
27
|
+
#
|
28
|
+
# <p><li><tt>link</tt> - for rendering links; typically a {@link pv.Bar}. The
|
29
|
+
# link mark is added directly to the layout, with the data property defined as
|
30
|
+
# all possible pairs of nodes. Each pair is represented as a
|
31
|
+
# {@link pv.Network.Layout.Link}, though the <tt>linkValue</tt> attribute may
|
32
|
+
# be 0 if no link exists in the graph.
|
33
|
+
#
|
34
|
+
# <p><li><tt>label</tt> - for rendering node labels; typically a
|
35
|
+
# {@link pv.Label}. The label mark is added directly to the layout, with the
|
36
|
+
# data property defined via the layout's <tt>nodes</tt> property; note,
|
37
|
+
# however, that the nodes are duplicated so as to provide a label across the
|
38
|
+
# top and down the side. Properties such as <tt>strokeStyle</tt> and
|
39
|
+
# <tt>fillStyle</tt> can be overridden to compute properties from node data
|
40
|
+
# dynamically.
|
41
|
+
#
|
42
|
+
# </ul>For more details on how to use this layout, see
|
43
|
+
# {@link pv.Layout.Network}.
|
44
|
+
class Matrix < Network
|
45
|
+
@properties=Network.properties.dup
|
46
|
+
attr_accessor :_n, :_dx, :_dy, :_labels, :_pairs
|
47
|
+
def build_implied_post(s)
|
48
|
+
@_n = s.nodes.size
|
49
|
+
@_dx = s.width.to_f / @_n
|
50
|
+
@_dy = s.height.to_f / @_n
|
51
|
+
@_labels = s._matrix.labels
|
52
|
+
@_pairs = s._matrix.pairs
|
53
|
+
end
|
54
|
+
# Deletes special add from network
|
55
|
+
def _link # :nodoc:
|
56
|
+
that=self
|
57
|
+
l=Mark.new().
|
58
|
+
mark_extend(@node).
|
59
|
+
data(lambda {|d| [d.source_node, d.target_node] }).
|
60
|
+
fill_style(nil).
|
61
|
+
line_width(lambda {|d,_p| _p.link_value * 1.5 }).
|
62
|
+
stroke_style("rgba(0,0,0,.2)")
|
63
|
+
l
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize
|
67
|
+
super
|
68
|
+
@_n=nil, # cached matrix size
|
69
|
+
@_dx=nil, # cached cell width
|
70
|
+
@_dy=nil, # cached cell height
|
71
|
+
@_labels=nil, # cached labels (array of strings)
|
72
|
+
@_pairs=nil, # cached pairs (array of links)
|
73
|
+
that=self
|
74
|
+
#/* Links are all pairs of nodes. */
|
75
|
+
@link.data(lambda {that._pairs})
|
76
|
+
.left(lambda { that._dx * (self.index % that._n) })
|
77
|
+
.top(lambda { that._dy * (self.index / that._n.to_f).floor })
|
78
|
+
.width(lambda { that._dx })
|
79
|
+
.height(lambda { that._dy })
|
80
|
+
.line_width(1.5)
|
81
|
+
.stroke_style("#fff")
|
82
|
+
.fill_style(lambda {|l| l.link_value!=0 ? "#555" : "#eee" })
|
83
|
+
|
84
|
+
@link.parent = self
|
85
|
+
#/* No special add for links! */
|
86
|
+
|
87
|
+
# delete this.link.add;
|
88
|
+
|
89
|
+
#/* Labels are duplicated for top & left. */
|
90
|
+
@node_label.
|
91
|
+
data(lambda { that._labels }).
|
92
|
+
left(lambda { (self.index & 1)!=0 ? that._dx * ((self.index >> 1) + 0.5) : 0 }).
|
93
|
+
top(lambda { (self.index & 1)!=0 ? 0 : that._dy * ((self.index >> 1) + 0.5) }).
|
94
|
+
text_margin(4).text_align(lambda { (self.index & 1)!=0 ? "left" : "right"; }).
|
95
|
+
text_angle(lambda { (self.index & 1)!=0 ? -Math::PI / 2.0 : 0; });
|
96
|
+
@node=nil
|
97
|
+
end
|
98
|
+
def self.defaults
|
99
|
+
Matrix.new.mark_extend(Network.defaults).
|
100
|
+
directed(true)
|
101
|
+
end
|
102
|
+
##
|
103
|
+
# :attr: directed
|
104
|
+
#
|
105
|
+
# Whether this matrix visualization is directed (bidirectional). By default,
|
106
|
+
# the graph is assumed to be undirected, such that the visualization is
|
107
|
+
# symmetric across the matrix diagonal. If the network is directed, then
|
108
|
+
# forward links are drawn above the diagonal, while reverse links are drawn
|
109
|
+
# below.
|
110
|
+
#
|
111
|
+
# @type boolean
|
112
|
+
# @name pv.Layout.Matrix.prototype.directed
|
113
|
+
#/
|
114
|
+
|
115
|
+
attr_accessor_dsl :directed
|
116
|
+
|
117
|
+
|
118
|
+
# Specifies an optional sort function. The sort function follows the same
|
119
|
+
# comparator contract required by {@link pv.Dom.Node#sort}. Specifying a sort
|
120
|
+
# function provides an alternative to sort the nodes as they are specified by
|
121
|
+
# the <tt>nodes</tt> property; the main advantage of doing this is that the
|
122
|
+
# comparator function can access implicit fields populated by the network
|
123
|
+
# layout, such as the <tt>linkDegree</tt>.
|
124
|
+
#
|
125
|
+
# <p>Note that matrix visualizations are particularly sensitive to order. This
|
126
|
+
# is referred to as the seriation problem, and many different techniques exist
|
127
|
+
# to find good node orders that emphasize clusters, such as spectral layout and
|
128
|
+
# simulated annealing.
|
129
|
+
#
|
130
|
+
# @param {function} f comparator function for nodes.
|
131
|
+
# @returns {pv.Layout.Matrix} this.
|
132
|
+
#/
|
133
|
+
def sort(f=nil,&block)
|
134
|
+
f||=block
|
135
|
+
@sort=f
|
136
|
+
self
|
137
|
+
end
|
138
|
+
def build_implied(s) # :nodoc:
|
139
|
+
return nil if network_build_implied(s)
|
140
|
+
nodes = s.nodes
|
141
|
+
links = s.links
|
142
|
+
sort = @sort
|
143
|
+
|
144
|
+
n = nodes.size
|
145
|
+
index = Rubyvis.range(n)
|
146
|
+
labels = []
|
147
|
+
pairs = []
|
148
|
+
map = {}
|
149
|
+
|
150
|
+
s._matrix = OpenStruct.new({:labels=> labels, :pairs=> pairs})
|
151
|
+
|
152
|
+
#/* Sort the nodes. */
|
153
|
+
if sort
|
154
|
+
index.sort! {|a,b| sort.call(nodes[a],nodes[b])}
|
155
|
+
end
|
156
|
+
#/* Create pairs. */
|
157
|
+
n.times {|i|
|
158
|
+
n.times {|j|
|
159
|
+
a = index[i]
|
160
|
+
b = index[j]
|
161
|
+
_p = OpenStruct.new({
|
162
|
+
:row=> i,
|
163
|
+
:col=> j,
|
164
|
+
:source_node=> nodes[a],
|
165
|
+
:target_node=> nodes[b],
|
166
|
+
:link_value=> 0})
|
167
|
+
map["#{a}.#{b}"] = _p
|
168
|
+
pairs.push(map["#{a}.#{b}"])
|
169
|
+
}
|
170
|
+
}
|
171
|
+
#/* Create labels. */
|
172
|
+
n.times {|i|
|
173
|
+
a = index[i]
|
174
|
+
labels.push(nodes[a], nodes[a])
|
175
|
+
}
|
176
|
+
#/* Accumulate link values. */
|
177
|
+
links.each_with_index {|l,i|
|
178
|
+
source = l.source_node.index
|
179
|
+
target = l.target_node.index
|
180
|
+
value = l.link_value
|
181
|
+
map["#{source}.#{target}"].link_value += value
|
182
|
+
map["#{target}.#{source}"].link_value += value if (!s.directed)
|
183
|
+
}
|
184
|
+
build_implied_post(s)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -15,7 +15,7 @@ module Rubyvis
|
|
15
15
|
# Network layouts require the graph data structure to be defined using two
|
16
16
|
# properties:<ul>
|
17
17
|
#
|
18
|
-
# <li><tt>nodes</tt> - an array of objects representing nodes. Objects in this array must conform to the
|
18
|
+
# <li><tt>nodes</tt> - an array of objects representing nodes. Objects in this array must conform to the Rubyvis::Layout::Network::Node interface; which is
|
19
19
|
# to say, be careful to avoid naming collisions with automatic attributes such
|
20
20
|
# as <tt>index</tt> and <tt>link_degree</tt>.
|
21
21
|
# If the nodes property is defined
|
@@ -24,7 +24,7 @@ module Rubyvis
|
|
24
24
|
# attribute points to the original primitive value.
|
25
25
|
#
|
26
26
|
# <p><li><tt>links</tt> - an array of objects representing links. Objects in
|
27
|
-
# this array must conform to the
|
27
|
+
# this array must conform to the Rubyvis::Layout::Network::Link interface; at a minimum, either <tt>source</tt> and <tt>target</tt> indexes or
|
28
28
|
# <tt>source_node</tt> and <tt>target_node</tt> references must be set. Note that
|
29
29
|
# if the links property is defined after the nodes property, the links can be defined in terms of <tt>this.nodes()</tt>.
|
30
30
|
#
|
@@ -32,22 +32,18 @@ module Rubyvis
|
|
32
32
|
#
|
33
33
|
# <p>Three standard mark prototypes are provided:<ul>
|
34
34
|
#
|
35
|
-
# <li><tt>node</tt> - for rendering nodes; typically a
|
36
|
-
# mark is added directly to the layout, with the data property defined via the
|
37
|
-
# layout's <tt>nodes</tt> property. Properties such as <tt>strokeStyle</tt> and
|
38
|
-
# <tt>fillStyle</tt> can be overridden to compute properties from node data
|
39
|
-
# dynamically.
|
35
|
+
# <li><tt>node</tt> - for rendering nodes; typically a Rubyvis::Dot. The node mark is added directly to the layout, with the data property defined via the layout's <tt>nodes</tt> property. Properties such as <tt>stroke_style</tt> and <tt>fillStyle</tt> can be overridden to compute properties from node data dynamically.
|
40
36
|
#
|
41
|
-
# <p><li><tt>link</tt> - for rendering links; typically a
|
37
|
+
# <p><li><tt>link</tt> - for rendering links; typically a Rubyvis::Line. The
|
42
38
|
# link mark is added to a child panel, whose data property is defined as
|
43
39
|
# layout's <tt>links</tt> property. The link's data property is then a
|
44
40
|
# two-element array of the source node and target node. Thus, poperties such as
|
45
|
-
# <tt>
|
41
|
+
# <tt>stroke_style</tt> and <tt>fill_style</tt> can be overridden to compute
|
46
42
|
# properties from either the node data (the first argument) or the link data
|
47
43
|
# (the second argument; the parent panel data) dynamically.
|
48
44
|
#
|
49
|
-
# <p><li><tt>
|
50
|
-
#
|
45
|
+
# <p><li><tt>node_label</tt> - for rendering node labels; typically a
|
46
|
+
# Rubyvis::Label. The label mark is added directly to the layout, with the
|
51
47
|
# data property defined via the layout's <tt>nodes</tt> property. Properties
|
52
48
|
# such as <tt>strokeStyle</tt> and <tt>fillStyle</tt> can be overridden to
|
53
49
|
# compute properties from node data dynamically.
|
@@ -223,6 +219,7 @@ module Rubyvis
|
|
223
219
|
def build_implied(s) # :nodoc:
|
224
220
|
network_build_implied(s)
|
225
221
|
end
|
222
|
+
|
226
223
|
def network_build_implied(s) # :nodoc:
|
227
224
|
layout_build_implied(s)
|
228
225
|
return true if (!s._id.nil? and s._id >= self._id)
|
data/lib/rubyvis/layout/pack.rb
CHANGED
@@ -9,13 +9,13 @@ module Rubyvis
|
|
9
9
|
# the exported mark prototypes changes slightly in the space-filling
|
10
10
|
# implementation:<ul>
|
11
11
|
#
|
12
|
-
# <li><tt>node</tt> - for rendering nodes; typically a
|
12
|
+
# <li><tt>node</tt> - for rendering nodes; typically a Rubyvis::Dot.
|
13
13
|
#
|
14
14
|
# <p><li><tt>link</tt> - unsupported; undefined. Links are encoded implicitly
|
15
15
|
# in the arrangement of the space-filling nodes.
|
16
16
|
#
|
17
17
|
# <p><li><tt>label</tt> - for rendering node labels; typically a
|
18
|
-
#
|
18
|
+
# Rubyvis::Label.
|
19
19
|
#
|
20
20
|
# </ul>The pack layout support dynamic sizing for leaf nodes, if a
|
21
21
|
# {@link #size} psuedo-property is specified. The default size function returns
|
@@ -29,7 +29,7 @@ module Rubyvis
|
|
29
29
|
# operator.
|
30
30
|
#
|
31
31
|
# <p>For more details on how to use this layout, see
|
32
|
-
#
|
32
|
+
# Rubyvis::Layout::Hierarchy.
|
33
33
|
#
|
34
34
|
# @extends pv.Layout.Hierarchy
|
35
35
|
# @see <a href="http://portal.acm.org/citation.cfm?id=1124772.1124851"
|
@@ -22,7 +22,7 @@ module Rubyvis
|
|
22
22
|
# operator.
|
23
23
|
#
|
24
24
|
# <p>For more details on how to use this layout, see
|
25
|
-
#
|
25
|
+
# Rubyvis::Layout::Hierarchy.
|
26
26
|
#
|
27
27
|
# @see pv.Layout.Partition.Fill
|
28
28
|
# @extends pv.Layout.Hierarchy
|
@@ -193,7 +193,7 @@ module Rubyvis
|
|
193
193
|
# in the arrangement of the space-filling nodes.
|
194
194
|
#
|
195
195
|
# <p><li><tt>label</tt> - for rendering node labels; typically a
|
196
|
-
#
|
196
|
+
# Rubyvis::Label.
|
197
197
|
#
|
198
198
|
# </ul>For more details on how to use this layout, see
|
199
199
|
# {@link pv.Layout.Partition}.
|
data/lib/rubyvis/layout/tree.rb
CHANGED
@@ -18,7 +18,7 @@ module Rubyvis
|
|
18
18
|
# dimensions, similar to the indent layout.
|
19
19
|
#
|
20
20
|
# <p>For more details on how to use this layout, see
|
21
|
-
#
|
21
|
+
# Rubyvis::Layout::Hierarchy
|
22
22
|
class Tree < Hierarchy
|
23
23
|
@properties=Hierarchy.properties.dup
|
24
24
|
def initialize
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Rubyvis
|
2
2
|
class Layout
|
3
|
+
# Alias for Rubyvis::Layout::Treemap
|
3
4
|
def self.Treemap
|
4
5
|
Rubyvis::Layout::Treemap
|
5
6
|
end
|
@@ -21,16 +22,16 @@ module Rubyvis
|
|
21
22
|
# the standard <tt>x</tt> and <tt>y</tt> position attributes.
|
22
23
|
#
|
23
24
|
# <p><li><tt>leaf</tt> - for rendering leaf nodes only, with no fill or stroke
|
24
|
-
# style by default; typically a
|
25
|
+
# style by default; typically a Rubyvis::Panel or another layout!
|
25
26
|
#
|
26
27
|
# <p><li><tt>link</tt> - unsupported; undefined. Links are encoded implicitly
|
27
28
|
# in the arrangement of the space-filling nodes.
|
28
29
|
#
|
29
30
|
# <p><li><tt>label</tt> - for rendering node labels; typically a
|
30
|
-
#
|
31
|
+
# Rubyvis::Label.
|
31
32
|
#
|
32
33
|
# </ul>For more details on how to use this layout, see
|
33
|
-
#
|
34
|
+
# Rubyvis::Layout::Hierarchy.
|
34
35
|
#
|
35
36
|
class Treemap < Hierarchy
|
36
37
|
@properties=Hierarchy.properties.dup
|
@@ -265,14 +266,14 @@ module Rubyvis
|
|
265
266
|
|
266
267
|
if (n.size > 0)
|
267
268
|
#/* Scale the sizes to fill the current subregion. */
|
268
|
-
n.visit_before {|
|
269
|
+
n.visit_before {|n1,i1| n1.size *= k }
|
269
270
|
|
270
271
|
#/** @private Position the specified nodes along one dimension. */
|
271
|
-
position=lambda {|
|
272
|
+
position=lambda {|row1|
|
272
273
|
horizontal = w == l
|
273
|
-
sum = Rubyvis.sum(
|
274
|
+
sum = Rubyvis.sum(row1, size)
|
274
275
|
r = l>0 ? round.call(sum / l.to_f) : 0
|
275
|
-
slice.call(
|
276
|
+
slice.call(row1, sum, horizontal, x, y, horizontal ? w : r, horizontal ? r : h)
|
276
277
|
if horizontal
|
277
278
|
y += r
|
278
279
|
h -= r
|
data/lib/rubyvis/layout.rb
CHANGED
@@ -295,5 +295,19 @@ class Rubyvis::Mark
|
|
295
295
|
#
|
296
296
|
# See Mark for examples of use
|
297
297
|
mark_method :layout_arc, Rubyvis::Layout::Arc
|
298
|
+
|
299
|
+
##
|
300
|
+
# :method: layout_matrix(opts,&block)
|
301
|
+
#
|
302
|
+
# Adds a Layout::Matrix to current mark.
|
303
|
+
#
|
304
|
+
# If a block is provided, the context will be defined differently if
|
305
|
+
# parameter is provided
|
306
|
+
# * Without parameter: block executed inside context of new mark
|
307
|
+
# * With paramenter: block executed inside context of current mark.
|
308
|
+
# Paramenter references new mark
|
309
|
+
#
|
310
|
+
# See Mark for examples of use
|
311
|
+
mark_method :layout_matrix, Rubyvis::Layout::Matrix
|
298
312
|
|
299
313
|
end
|
data/lib/rubyvis/sceneelement.rb
CHANGED
@@ -8,7 +8,7 @@ module Rubyvis
|
|
8
8
|
end
|
9
9
|
include Enumerable
|
10
10
|
attr_accessor :visible
|
11
|
-
attr_accessor :mark, :type, :child_index, :parent, :parent_index, :target, :defs, :data, :antialias, :line_width, :fill_style, :overflow, :width, :height, :top, :bottom, :left, :right, :title, :reverse, :stroke_style, :transform, :canvas, :_g, :events, :cursor, :children, :id, :segmented, :interpolate, :tension, :name, :text_baseline, :text_align, :text, :font, :text_angle, :text_style, :text_margin, :text_decoration, :text_shadow, :line_join, :eccentricity, :shape_size, :shape, :shape_angle, :shape_radius, :start_angle, :end_angle, :angle, :inner_radius, :outer_radius, :layers, :orient, :offset, :order,:url, :image_width, :image_height, :image, :_id, :nodes, :round, :links, :padding_left, :padding_right, :padding_top, :padding_bottom, :mode, :group, :depth, :breadth, :spacing, :rows, :cols, :_grid,:bands, :background_style, :positive_style, :negative_style,:directed
|
11
|
+
attr_accessor :mark, :type, :child_index, :parent, :parent_index, :target, :defs, :data, :antialias, :line_width, :fill_style, :overflow, :width, :height, :top, :bottom, :left, :right, :title, :reverse, :stroke_style, :transform, :canvas, :_g, :events, :cursor, :children, :id, :segmented, :interpolate, :tension, :name, :text_baseline, :text_align, :text, :font, :text_angle, :text_style, :text_margin, :text_decoration, :text_shadow, :line_join, :eccentricity, :shape_size, :shape, :shape_angle, :shape_radius, :start_angle, :end_angle, :angle, :inner_radius, :outer_radius, :layers, :orient, :offset, :order,:url, :image_width, :image_height, :image, :_id, :nodes, :round, :links, :padding_left, :padding_right, :padding_top, :padding_bottom, :mode, :group, :depth, :breadth, :spacing, :rows, :cols, :_grid,:bands, :background_style, :positive_style, :negative_style,:directed, :_matrix
|
12
12
|
|
13
13
|
def []=(v,i)
|
14
14
|
if v.is_a? Numeric
|
data/lib/rubyvis.rb
CHANGED
@@ -30,7 +30,7 @@ require 'rubyvis/mark/shorcut_methods'
|
|
30
30
|
module Rubyvis
|
31
31
|
@document=nil
|
32
32
|
# Rubyvis version
|
33
|
-
VERSION = '0.3.
|
33
|
+
VERSION = '0.3.6'
|
34
34
|
# Protovis API on which current Rubyvis is based
|
35
35
|
PROTOVIS_API_VERSION='3.3'
|
36
36
|
# You actually can do it! http://snipplr.com/view/2137/uses-for-infinity-in-ruby/
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb")
|
2
|
+
describe Rubyvis::Layout::Arc do
|
3
|
+
it "should have correct properties" do
|
4
|
+
props=[:antialias, :bottom, :canvas, :cursor, :data, :directed, :events, :fill_style, :height, :id, :left, :line_width, :links, :nodes, :orient, :overflow, :reverse, :right, :stroke_style, :title, :top, :transform, :visible, :width].inject({}) {|ac, v| ac[v]=true; ac}
|
5
|
+
Rubyvis::Layout::Arc.properties.should==props
|
6
|
+
end
|
7
|
+
describe "rendered" do
|
8
|
+
before do
|
9
|
+
|
10
|
+
|
11
|
+
nodes=[
|
12
|
+
OpenStruct.new({:node_value=>'A', :group=>1}),
|
13
|
+
OpenStruct.new({:node_value=>'B', :group=>1}),
|
14
|
+
OpenStruct.new({:node_value=>'C', :group=>2}),
|
15
|
+
OpenStruct.new({:node_value=>'D',:group=>2}),
|
16
|
+
OpenStruct.new({:node_value=>'E',:group=>3}),
|
17
|
+
OpenStruct.new({:node_value=>'F',:group=>3})
|
18
|
+
|
19
|
+
]
|
20
|
+
links=[
|
21
|
+
OpenStruct.new({:source=>0,:target=>1, :value=>1}),
|
22
|
+
OpenStruct.new({:source=>1,:target=>2, :value=>1}),
|
23
|
+
OpenStruct.new({:source=>2,:target=>3, :value=>1}),
|
24
|
+
OpenStruct.new({:source=>3,:target=>4, :value=>1}),
|
25
|
+
OpenStruct.new({:source=>4,:target=>5, :value=>1}),
|
26
|
+
OpenStruct.new({:source=>1,:target=>0, :value=>1}),
|
27
|
+
OpenStruct.new({:source=>2,:target=>1, :value=>1}),
|
28
|
+
OpenStruct.new({:source=>3,:target=>2, :value=>1}),
|
29
|
+
OpenStruct.new({:source=>4,:target=>3, :value=>1}),
|
30
|
+
OpenStruct.new({:source=>5,:target=>4, :value=>1}),
|
31
|
+
]
|
32
|
+
|
33
|
+
|
34
|
+
w = 300
|
35
|
+
h = 100
|
36
|
+
|
37
|
+
color=Rubyvis::Colors.category19
|
38
|
+
|
39
|
+
@vis = Rubyvis::Panel.new()
|
40
|
+
.width(w)
|
41
|
+
.height(h)
|
42
|
+
.bottom(50)
|
43
|
+
.left(0)
|
44
|
+
|
45
|
+
mat=@vis.add(Rubyvis::Layout::Arc)
|
46
|
+
.nodes(nodes).links(links)
|
47
|
+
.sort(lambda {|a,b| a.group<=>b.group})
|
48
|
+
|
49
|
+
mat.link.add(Rubyvis::Line).
|
50
|
+
antialias(false).
|
51
|
+
line_width(1)
|
52
|
+
|
53
|
+
mat.node.add(Rubyvis::Dot).
|
54
|
+
shape_size(10).
|
55
|
+
fill_style(lambda {|l| color[l.group]})
|
56
|
+
|
57
|
+
mat.node_label.add(Rubyvis::Label).
|
58
|
+
text_style(lambda {|l| color[l.group]})
|
59
|
+
|
60
|
+
@vis.render
|
61
|
+
|
62
|
+
html_out=<<EOF
|
63
|
+
<svg font-size="10px" font-family="sans-serif" fill="none" stroke="none" stroke-width="1.5" width="300" height="150"><g><g><g><path shape-rendering="crispEdges" d="M25,100A25,25 0 0,1 75,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M75,100A25,25 0 0,1 125,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M125,100A25,25 0 0,1 175,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M175,100A25,25 0 0,1 225,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M225,100A25,25 0 0,1 275,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M25,100A25,25 0 0,1 75,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M75,100A25,25 0 0,1 125,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M125,100A25,25 0 0,1 175,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M175,100A25,25 0 0,1 225,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g><g><path shape-rendering="crispEdges" d="M225,100A25,25 0 0,1 275,100" stroke="rgb(0,0,0)" stroke-opacity="0.2" stroke-width="1"/></g></g><g><circle fill="rgb(156,158,222)" stroke="rgb(31,119,180)" cx="25" cy="100" r="3.1622776601683795"/><circle fill="rgb(156,158,222)" stroke="rgb(31,119,180)" cx="75" cy="100" r="3.1622776601683795"/><circle fill="rgb(115,117,181)" stroke="rgb(31,119,180)" cx="125" cy="100" r="3.1622776601683795"/><circle fill="rgb(115,117,181)" stroke="rgb(31,119,180)" cx="175" cy="100" r="3.1622776601683795"/><circle fill="rgb(74,85,132)" stroke="rgb(31,119,180)" cx="225" cy="100" r="3.1622776601683795"/><circle fill="rgb(74,85,132)" stroke="rgb(31,119,180)" cx="275" cy="100" r="3.1622776601683795"/></g><g><text pointer-events="none" x="-7" dy="0.35em" transform="translate(25, 100) rotate(270)" fill="rgb(156,158,222)" text-anchor="end">A</text><text pointer-events="none" x="-7" dy="0.35em" transform="translate(75, 100) rotate(270)" fill="rgb(156,158,222)" text-anchor="end">B</text><text pointer-events="none" x="-7" dy="0.35em" transform="translate(125, 100) rotate(270)" fill="rgb(115,117,181)" text-anchor="end">C</text><text pointer-events="none" x="-7" dy="0.35em" transform="translate(175, 100) rotate(270)" fill="rgb(115,117,181)" text-anchor="end">D</text><text pointer-events="none" x="-7" dy="0.35em" transform="translate(225, 100) rotate(270)" fill="rgb(74,85,132)" text-anchor="end">E</text><text pointer-events="none" x="-7" dy="0.35em" transform="translate(275, 100) rotate(270)" fill="rgb(74,85,132)" text-anchor="end">F</text></g></g></svg>
|
64
|
+
EOF
|
65
|
+
@rv_svg=Nokogiri::XML(@vis.to_svg)
|
66
|
+
@pv_svg=Nokogiri::XML(html_out)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should render correct number of clipaths" do
|
70
|
+
|
71
|
+
@rv_svg.xpath("//xmlns:path").size.should eq @pv_svg.xpath("//path").size
|
72
|
+
end
|
73
|
+
it "should render equal paths (links)" do
|
74
|
+
pv_paths=@pv_svg.xpath("//path")
|
75
|
+
@rv_svg.xpath("//xmlns:path").each_with_index {|rv_path,i|
|
76
|
+
rv_path.should have_path_data_close_to pv_paths[i]['d']
|
77
|
+
}
|
78
|
+
end
|
79
|
+
it "should render equal dots (nodes)" do
|
80
|
+
pv_circles=@pv_svg.xpath("//circle")
|
81
|
+
@rv_svg.xpath("//xmlns:circle").each_with_index {|rv_circle,i|
|
82
|
+
rv_circle.should have_same_position pv_circles[i]
|
83
|
+
}
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb")
|
2
|
+
describe Rubyvis::Layout::Matrix do
|
3
|
+
it "should have correct properties" do
|
4
|
+
props=[:antialias, :bottom, :canvas, :cursor, :data, :directed, :events, :fill_style, :height, :id, :left, :line_width, :links, :nodes, :overflow, :reverse, :right, :stroke_style, :title, :top, :transform, :visible, :width].inject({}) {|ac, v| ac[v]=true; ac}
|
5
|
+
Rubyvis::Layout::Matrix.properties.should==props
|
6
|
+
end
|
7
|
+
describe "rendered" do
|
8
|
+
before do
|
9
|
+
|
10
|
+
nodes=[
|
11
|
+
OpenStruct.new({:node_value=>'A', :group=>1}),
|
12
|
+
OpenStruct.new({:node_value=>'B', :group=>1}),
|
13
|
+
OpenStruct.new({:node_value=>'C', :group=>2}),
|
14
|
+
OpenStruct.new({:node_value=>'D',:group=>2}),
|
15
|
+
OpenStruct.new({:node_value=>'E',:group=>3}),
|
16
|
+
OpenStruct.new({:node_value=>'F',:group=>3})
|
17
|
+
|
18
|
+
]
|
19
|
+
links=[
|
20
|
+
OpenStruct.new({:source=>0,:target=>1, :value=>1}),
|
21
|
+
OpenStruct.new({:source=>1,:target=>2, :value=>1}),
|
22
|
+
OpenStruct.new({:source=>2,:target=>3, :value=>1}),
|
23
|
+
OpenStruct.new({:source=>3,:target=>4, :value=>1}),
|
24
|
+
OpenStruct.new({:source=>4,:target=>5, :value=>1}),
|
25
|
+
OpenStruct.new({:source=>1,:target=>0, :value=>1}),
|
26
|
+
OpenStruct.new({:source=>2,:target=>1, :value=>1}),
|
27
|
+
OpenStruct.new({:source=>3,:target=>2, :value=>1}),
|
28
|
+
OpenStruct.new({:source=>4,:target=>3, :value=>1}),
|
29
|
+
OpenStruct.new({:source=>5,:target=>4, :value=>1}),
|
30
|
+
]
|
31
|
+
|
32
|
+
|
33
|
+
w = 700
|
34
|
+
h = 700
|
35
|
+
|
36
|
+
color=Rubyvis::Colors.category19()
|
37
|
+
@vis = Rubyvis::Panel.new()
|
38
|
+
.width(w)
|
39
|
+
.height(h)
|
40
|
+
.top(50)
|
41
|
+
.left(50)
|
42
|
+
|
43
|
+
mat=@vis.add(Rubyvis::Layout.Matrix)
|
44
|
+
.directed(true)
|
45
|
+
.nodes(nodes).links(links)
|
46
|
+
.sort(lambda {|a,b| a.group<=>b.group})
|
47
|
+
|
48
|
+
mat.link.add(pv.Bar).
|
49
|
+
fill_style(lambda {|l| l.link_value!=0 ?
|
50
|
+
((l.target_node.group==l.source_node.group) ? color[l.sourceNode] : "#555") : "#eee"}).
|
51
|
+
antialias(false).
|
52
|
+
line_width(1)
|
53
|
+
mat.node_label.add(Rubyvis::Label).
|
54
|
+
text_style(color)
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
@vis.render
|
59
|
+
|
60
|
+
html_out=<<EOF
|
61
|
+
<svg font-size="10px" font-family="sans-serif" fill="none" stroke="none" stroke-width="1.5" width="750" height="750"><g transform="translate(50, 50)"><g><rect shape-rendering="crispEdges" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="116.66666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(156,158,222)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="233.33333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="350" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="466.6666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="583.3333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" y="116.66666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(156,158,222)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="116.66666666666667" y="116.66666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="233.33333333333334" y="116.66666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(85,85,85)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="350" y="116.66666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="466.6666666666667" y="116.66666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="583.3333333333334" y="116.66666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" y="233.33333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="116.66666666666667" y="233.33333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(85,85,85)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="233.33333333333334" y="233.33333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="350" y="233.33333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(156,158,222)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="466.6666666666667" y="233.33333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="583.3333333333334" y="233.33333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" y="350" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="116.66666666666667" y="350" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="233.33333333333334" y="350" width="116.66666666666667" height="116.66666666666667" fill="rgb(156,158,222)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="350" y="350" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="466.6666666666667" y="350" width="116.66666666666667" height="116.66666666666667" fill="rgb(85,85,85)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="583.3333333333334" y="350" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" y="466.6666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="116.66666666666667" y="466.6666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="233.33333333333334" y="466.6666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="350" y="466.6666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(85,85,85)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="466.6666666666667" y="466.6666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="583.3333333333334" y="466.6666666666667" width="116.66666666666667" height="116.66666666666667" fill="rgb(156,158,222)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" y="583.3333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="116.66666666666667" y="583.3333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="233.33333333333334" y="583.3333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="350" y="583.3333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="466.6666666666667" y="583.3333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(156,158,222)" stroke="rgb(255,255,255)" stroke-width="1"/><rect shape-rendering="crispEdges" x="583.3333333333334" y="583.3333333333334" width="116.66666666666667" height="116.66666666666667" fill="rgb(238,238,238)" stroke="rgb(255,255,255)" stroke-width="1"/></g><g><text pointer-events="none" x="-4" dy="0.35em" transform="translate(0, 58.3333)" fill="rgb(156,158,222)" text-anchor="end">A</text><text pointer-events="none" x="4" dy="0.35em" transform="translate(58.3333) rotate(-90)" fill="rgb(156,158,222)">A</text><text pointer-events="none" x="-4" dy="0.35em" transform="translate(0, 175)" fill="rgb(156,158,222)" text-anchor="end">B</text><text pointer-events="none" x="4" dy="0.35em" transform="translate(175) rotate(-90)" fill="rgb(156,158,222)">B</text><text pointer-events="none" x="-4" dy="0.35em" transform="translate(0, 291.667)" fill="rgb(156,158,222)" text-anchor="end">C</text><text pointer-events="none" x="4" dy="0.35em" transform="translate(291.667) rotate(-90)" fill="rgb(156,158,222)">C</text><text pointer-events="none" x="-4" dy="0.35em" transform="translate(0, 408.333)" fill="rgb(156,158,222)" text-anchor="end">D</text><text pointer-events="none" x="4" dy="0.35em" transform="translate(408.333) rotate(-90)" fill="rgb(156,158,222)">D</text><text pointer-events="none" x="-4" dy="0.35em" transform="translate(0, 525)" fill="rgb(156,158,222)" text-anchor="end">E</text><text pointer-events="none" x="4" dy="0.35em" transform="translate(525) rotate(-90)" fill="rgb(156,158,222)">E</text><text pointer-events="none" x="-4" dy="0.35em" transform="translate(0, 641.667)" fill="rgb(156,158,222)" text-anchor="end">F</text><text pointer-events="none" x="4" dy="0.35em" transform="translate(641.667) rotate(-90)" fill="rgb(156,158,222)">F</text></g></g></svg>
|
62
|
+
EOF
|
63
|
+
@rv_svg=Nokogiri::XML(@vis.to_svg)
|
64
|
+
@pv_svg=Nokogiri::XML(html_out)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should render correct number of rects(links)" do
|
68
|
+
@rv_svg.xpath("//xmlns:rect").size.should eq @pv_svg.xpath("//rect").size
|
69
|
+
end
|
70
|
+
it "should render equal intersections (links)" do
|
71
|
+
pv_rects=@pv_svg.xpath("//rect")
|
72
|
+
@rv_svg.xpath("//xmlns:rect").each_with_index {|rv_rect,i|
|
73
|
+
rv_rect.should have_same_position pv_rects[i]
|
74
|
+
}
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
2
|
+
begin
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start do
|
5
|
+
add_filter "/spec/"
|
6
|
+
add_group "Libraries", "lib"
|
7
|
+
end
|
8
|
+
rescue LoadError
|
9
|
+
end
|
2
10
|
require 'rspec'
|
3
11
|
#require 'spec/autorun'
|
4
12
|
require 'rubyvis'
|
5
13
|
require 'pp'
|
6
14
|
require 'nokogiri'
|
15
|
+
|
16
|
+
|
7
17
|
$PROTOVIS_DIR=File.dirname(__FILE__)+"/../vendor/protovis/src"
|
8
18
|
module Rubyvis
|
9
19
|
class JohnsonLoader
|
@@ -34,6 +44,22 @@ RSpec::Matchers.define :have_svg_attributes do |exp|
|
|
34
44
|
}
|
35
45
|
end
|
36
46
|
end
|
47
|
+
Rspec::Matchers.define :have_same_position do |exp|
|
48
|
+
match do |obs|
|
49
|
+
correct=true
|
50
|
+
attrs={
|
51
|
+
"circle"=>['cx','cy','r'],
|
52
|
+
"rect"=>["x","y","width","height"]
|
53
|
+
}
|
54
|
+
attrs[exp.name].each do |attr|
|
55
|
+
if (obs[attr].to_f - exp[attr].to_f)>0.0001
|
56
|
+
correct=false
|
57
|
+
break
|
58
|
+
end
|
59
|
+
end
|
60
|
+
correct
|
61
|
+
end
|
62
|
+
end
|
37
63
|
RSpec::Matchers.define :have_path_data_close_to do |exp|
|
38
64
|
def path_scan(path)
|
39
65
|
path.scan(/([MmCcZzLlHhVvSsQqTtAa, ])(\d+(?:\.\d+)?)/).map {|v|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyvis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 6
|
10
|
+
version: 0.3.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Claudio Bustos
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
36
36
|
rpP0jjs0
|
37
37
|
-----END CERTIFICATE-----
|
38
38
|
|
39
|
-
date: 2010-12-
|
39
|
+
date: 2010-12-28 00:00:00 -03:00
|
40
40
|
default_executable:
|
41
41
|
dependencies:
|
42
42
|
- !ruby/object:Gem::Dependency
|
@@ -172,6 +172,7 @@ files:
|
|
172
172
|
- examples/5_pv_hierarchies/sunburst.rb
|
173
173
|
- examples/5_pv_hierarchies/treemap.rb
|
174
174
|
- examples/6_pv_networks/arc.rb
|
175
|
+
- examples/6_pv_networks/matrix.rb
|
175
176
|
- examples/6_pv_networks/miserables_data.rb
|
176
177
|
- lib/rubyvis.rb
|
177
178
|
- lib/rubyvis/color/color.rb
|
@@ -191,6 +192,7 @@ files:
|
|
191
192
|
- lib/rubyvis/layout/hierarchy.rb
|
192
193
|
- lib/rubyvis/layout/horizon.rb
|
193
194
|
- lib/rubyvis/layout/indent.rb
|
195
|
+
- lib/rubyvis/layout/matrix.rb
|
194
196
|
- lib/rubyvis/layout/network.rb
|
195
197
|
- lib/rubyvis/layout/pack.rb
|
196
198
|
- lib/rubyvis/layout/partition.rb
|
@@ -238,7 +240,9 @@ files:
|
|
238
240
|
- spec/internal_spec.rb
|
239
241
|
- spec/javascript_behaviour_spec.rb
|
240
242
|
- spec/label_spec.rb
|
243
|
+
- spec/layout_arc_spec.rb
|
241
244
|
- spec/layout_horizon_spec.rb
|
245
|
+
- spec/layout_matrix_spec.rb
|
242
246
|
- spec/layout_stack_spec.rb
|
243
247
|
- spec/line_spec.rb
|
244
248
|
- spec/mark_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|