rubyvis 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +13 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +37 -0
- data/History.txt +6 -0
- data/LICENSE.txt +23 -0
- data/{README.txt → README.md} +15 -12
- data/Rakefile +4 -11
- data/lib/rubyvis.rb +1 -1
- data/lib/rubyvis/scale/quantitative.rb +14 -18
- data/lib/rubyvis/scene/svg_label.rb +1 -1
- data/rubyvis.gemspec +21 -0
- data/spec/anchor_spec.rb +2 -1
- data/spec/line_spec.rb +2 -2
- data/spec/scale_linear_datetime_spec.rb +23 -8
- data/spec/spec_helper.rb +2 -1
- metadata +31 -214
- data/.gemtest +0 -0
- data/vendor/protovis/protovis-r3.3.js +0 -287
- data/vendor/protovis/src/behavior/Behavior.js +0 -32
- data/vendor/protovis/src/behavior/Drag.js +0 -112
- data/vendor/protovis/src/behavior/Pan.js +0 -110
- data/vendor/protovis/src/behavior/Point.js +0 -157
- data/vendor/protovis/src/behavior/Resize.js +0 -104
- data/vendor/protovis/src/behavior/Select.js +0 -100
- data/vendor/protovis/src/behavior/Zoom.js +0 -85
- data/vendor/protovis/src/color/Color.js +0 -598
- data/vendor/protovis/src/color/Colors.js +0 -135
- data/vendor/protovis/src/color/Ramp.js +0 -17
- data/vendor/protovis/src/data/Arrays.js +0 -277
- data/vendor/protovis/src/data/Dom.js +0 -380
- data/vendor/protovis/src/data/Flatten.js +0 -146
- data/vendor/protovis/src/data/Histogram.js +0 -120
- data/vendor/protovis/src/data/LinearScale.js +0 -54
- data/vendor/protovis/src/data/LogScale.js +0 -142
- data/vendor/protovis/src/data/Nest.js +0 -257
- data/vendor/protovis/src/data/Numbers.js +0 -313
- data/vendor/protovis/src/data/Objects.js +0 -78
- data/vendor/protovis/src/data/OrdinalScale.js +0 -267
- data/vendor/protovis/src/data/QuantileScale.js +0 -180
- data/vendor/protovis/src/data/QuantitativeScale.js +0 -440
- data/vendor/protovis/src/data/RootScale.js +0 -55
- data/vendor/protovis/src/data/Scale.js +0 -86
- data/vendor/protovis/src/data/Transform.js +0 -109
- data/vendor/protovis/src/data/Tree.js +0 -124
- data/vendor/protovis/src/data/Vector.js +0 -118
- data/vendor/protovis/src/geo/Geo.js +0 -5
- data/vendor/protovis/src/geo/GeoScale.js +0 -307
- data/vendor/protovis/src/geo/LatLng.js +0 -23
- data/vendor/protovis/src/geo/Projection.js +0 -43
- data/vendor/protovis/src/geo/Projections.js +0 -117
- data/vendor/protovis/src/lang/Array.js +0 -112
- data/vendor/protovis/src/lang/init.js +0 -26
- data/vendor/protovis/src/layout/Arc.js +0 -178
- data/vendor/protovis/src/layout/Bullet.js +0 -164
- data/vendor/protovis/src/layout/Cluster.js +0 -205
- data/vendor/protovis/src/layout/Force.js +0 -309
- data/vendor/protovis/src/layout/Grid.js +0 -119
- data/vendor/protovis/src/layout/Hierarchy.js +0 -249
- data/vendor/protovis/src/layout/Horizon.js +0 -159
- data/vendor/protovis/src/layout/Indent.js +0 -83
- data/vendor/protovis/src/layout/Layout.js +0 -56
- data/vendor/protovis/src/layout/Matrix.js +0 -177
- data/vendor/protovis/src/layout/Network.js +0 -302
- data/vendor/protovis/src/layout/Pack.js +0 -323
- data/vendor/protovis/src/layout/Partition.js +0 -203
- data/vendor/protovis/src/layout/Rollup.js +0 -203
- data/vendor/protovis/src/layout/Stack.js +0 -391
- data/vendor/protovis/src/layout/Tree.js +0 -282
- data/vendor/protovis/src/layout/Treemap.js +0 -347
- data/vendor/protovis/src/mark/Anchor.js +0 -81
- data/vendor/protovis/src/mark/Area.js +0 -268
- data/vendor/protovis/src/mark/Bar.js +0 -93
- data/vendor/protovis/src/mark/Dot.js +0 -212
- data/vendor/protovis/src/mark/Ease.js +0 -150
- data/vendor/protovis/src/mark/Image.js +0 -154
- data/vendor/protovis/src/mark/Label.js +0 -155
- data/vendor/protovis/src/mark/Line.js +0 -195
- data/vendor/protovis/src/mark/Mark.js +0 -1237
- data/vendor/protovis/src/mark/Panel.js +0 -273
- data/vendor/protovis/src/mark/Rule.js +0 -143
- data/vendor/protovis/src/mark/Transient.js +0 -7
- data/vendor/protovis/src/mark/Transition.js +0 -195
- data/vendor/protovis/src/mark/Wedge.js +0 -244
- data/vendor/protovis/src/physics/BoundConstraint.js +0 -75
- data/vendor/protovis/src/physics/ChargeForce.js +0 -184
- data/vendor/protovis/src/physics/CollisionConstraint.js +0 -113
- data/vendor/protovis/src/physics/Constraint.js +0 -26
- data/vendor/protovis/src/physics/DragForce.js +0 -49
- data/vendor/protovis/src/physics/Force.js +0 -25
- data/vendor/protovis/src/physics/Particle.js +0 -81
- data/vendor/protovis/src/physics/PositionConstraint.js +0 -72
- data/vendor/protovis/src/physics/Quadtree.js +0 -195
- data/vendor/protovis/src/physics/Simulation.js +0 -159
- data/vendor/protovis/src/physics/SpringForce.js +0 -141
- data/vendor/protovis/src/pv-internals.js +0 -154
- data/vendor/protovis/src/pv.js +0 -95
- data/vendor/protovis/src/scene/SvgArea.js +0 -172
- data/vendor/protovis/src/scene/SvgBar.js +0 -28
- data/vendor/protovis/src/scene/SvgCurve.js +0 -354
- data/vendor/protovis/src/scene/SvgDot.js +0 -81
- data/vendor/protovis/src/scene/SvgImage.js +0 -45
- data/vendor/protovis/src/scene/SvgLabel.js +0 -46
- data/vendor/protovis/src/scene/SvgLine.js +0 -159
- data/vendor/protovis/src/scene/SvgPanel.js +0 -126
- data/vendor/protovis/src/scene/SvgRule.js +0 -26
- data/vendor/protovis/src/scene/SvgScene.js +0 -185
- data/vendor/protovis/src/scene/SvgWedge.js +0 -66
- data/vendor/protovis/src/text/DateFormat.js +0 -262
- data/vendor/protovis/src/text/Format.js +0 -78
- data/vendor/protovis/src/text/NumberFormat.js +0 -227
- data/vendor/protovis/src/text/TimeFormat.js +0 -115
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Constructs a new, empty rollup network layout. Layouts are not typically
|
|
3
|
-
* constructed directly; instead, they are added to an existing panel via
|
|
4
|
-
* {@link pv.Mark#add}.
|
|
5
|
-
*
|
|
6
|
-
* @class Implements a network visualization using a node-link diagram where
|
|
7
|
-
* nodes are rolled up along two dimensions. This implementation is based on the
|
|
8
|
-
* "PivotGraph" designed by Martin Wattenberg:
|
|
9
|
-
*
|
|
10
|
-
* <blockquote>The method is designed for graphs that are "multivariate", i.e.,
|
|
11
|
-
* where each node is associated with several attributes. Unlike visualizations
|
|
12
|
-
* which emphasize global graph topology, PivotGraph uses a simple grid-based
|
|
13
|
-
* approach to focus on the relationship between node attributes &
|
|
14
|
-
* connections.</blockquote>
|
|
15
|
-
*
|
|
16
|
-
* This layout requires two psuedo-properties to be specified, which assign node
|
|
17
|
-
* positions along the two dimensions {@link #x} and {@link #y}, corresponding
|
|
18
|
-
* to the left and top properties, respectively. Typically, these functions are
|
|
19
|
-
* specified using an {@link pv.Scale.ordinal}. Nodes that share the same
|
|
20
|
-
* position in <i>x</i> and <i>y</i> are "rolled up" into a meta-node, and
|
|
21
|
-
* similarly links are aggregated between meta-nodes. For example, to construct
|
|
22
|
-
* a rollup to analyze links by gender and affiliation, first define two ordinal
|
|
23
|
-
* scales:
|
|
24
|
-
*
|
|
25
|
-
* <pre>var x = pv.Scale.ordinal(nodes, function(d) d.gender).split(0, w),
|
|
26
|
-
* y = pv.Scale.ordinal(nodes, function(d) d.aff).split(0, h);</pre>
|
|
27
|
-
*
|
|
28
|
-
* Next, define the position psuedo-properties:
|
|
29
|
-
*
|
|
30
|
-
* <pre> .x(function(d) x(d.gender))
|
|
31
|
-
* .y(function(d) y(d.aff))</pre>
|
|
32
|
-
*
|
|
33
|
-
* Linear and other quantitative scales can alternatively be used to position
|
|
34
|
-
* the nodes along either dimension. Note, however, that the rollup requires
|
|
35
|
-
* that the positions match exactly, and thus ordinal scales are recommended to
|
|
36
|
-
* avoid precision errors.
|
|
37
|
-
*
|
|
38
|
-
* <p>Note that because this layout provides a visualization of the rolled up
|
|
39
|
-
* graph, the data properties for the mark prototypes (<tt>node</tt>,
|
|
40
|
-
* <tt>link</tt> and <tt>label</tt>) are different from most other network
|
|
41
|
-
* layouts: they reference the rolled-up nodes and links, rather than the nodes
|
|
42
|
-
* and links of the full network. The underlying nodes and links for each
|
|
43
|
-
* rolled-up node and link can be accessed via the <tt>nodes</tt> and
|
|
44
|
-
* <tt>links</tt> attributes, respectively. The aggregated link values for
|
|
45
|
-
* rolled-up links can similarly be accessed via the <tt>linkValue</tt>
|
|
46
|
-
* attribute.
|
|
47
|
-
*
|
|
48
|
-
* <p>For undirected networks, links are duplicated in both directions. For
|
|
49
|
-
* directed networks, use <tt>directed(true)</tt>. The graph is assumed to be
|
|
50
|
-
* undirected by default.
|
|
51
|
-
*
|
|
52
|
-
* @extends pv.Layout.Network
|
|
53
|
-
* @see <a href="http://www.research.ibm.com/visual/papers/pivotgraph.pdf"
|
|
54
|
-
* >"Visual Exploration of Multivariate Graphs"</a> by M. Wattenberg, CHI 2006.
|
|
55
|
-
*/
|
|
56
|
-
pv.Layout.Rollup = function() {
|
|
57
|
-
pv.Layout.Network.call(this);
|
|
58
|
-
var that = this,
|
|
59
|
-
nodes, // cached rollup nodes
|
|
60
|
-
links, // cached rollup links
|
|
61
|
-
buildImplied = that.buildImplied;
|
|
62
|
-
|
|
63
|
-
/** @private Cache layout state to optimize properties. */
|
|
64
|
-
this.buildImplied = function(s) {
|
|
65
|
-
buildImplied.call(this, s);
|
|
66
|
-
nodes = s.$rollup.nodes;
|
|
67
|
-
links = s.$rollup.links;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
/* Render rollup nodes. */
|
|
71
|
-
this.node
|
|
72
|
-
.data(function() { return nodes; })
|
|
73
|
-
.shapeSize(function(d) { return d.nodes.length * 20; });
|
|
74
|
-
|
|
75
|
-
/* Render rollup links. */
|
|
76
|
-
this.link
|
|
77
|
-
.interpolate("polar")
|
|
78
|
-
.eccentricity(.8);
|
|
79
|
-
|
|
80
|
-
this.link.add = function(type) {
|
|
81
|
-
return that.add(pv.Panel)
|
|
82
|
-
.data(function() { return links; })
|
|
83
|
-
.add(type)
|
|
84
|
-
.extend(this);
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
pv.Layout.Rollup.prototype = pv.extend(pv.Layout.Network)
|
|
89
|
-
.property("directed", Boolean);
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Whether the underlying network is directed. By default, the graph is assumed
|
|
93
|
-
* to be undirected, and links are rendered in both directions. If the network
|
|
94
|
-
* is directed, then forward links are drawn above the diagonal, while reverse
|
|
95
|
-
* links are drawn below.
|
|
96
|
-
*
|
|
97
|
-
* @type boolean
|
|
98
|
-
* @name pv.Layout.Rollup.prototype.directed
|
|
99
|
-
*/
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Specifies the <i>x</i>-position function used to rollup nodes. The rolled up
|
|
103
|
-
* nodes are positioned horizontally using the return values from the given
|
|
104
|
-
* function. Typically the function is specified as an ordinal scale. For
|
|
105
|
-
* single-dimension rollups, a constant value can be specified.
|
|
106
|
-
*
|
|
107
|
-
* @param {function} f the <i>x</i>-position function.
|
|
108
|
-
* @returns {pv.Layout.Rollup} this.
|
|
109
|
-
* @see pv.Scale.ordinal
|
|
110
|
-
*/
|
|
111
|
-
pv.Layout.Rollup.prototype.x = function(f) {
|
|
112
|
-
this.$x = pv.functor(f);
|
|
113
|
-
return this;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Specifies the <i>y</i>-position function used to rollup nodes. The rolled up
|
|
118
|
-
* nodes are positioned vertically using the return values from the given
|
|
119
|
-
* function. Typically the function is specified as an ordinal scale. For
|
|
120
|
-
* single-dimension rollups, a constant value can be specified.
|
|
121
|
-
*
|
|
122
|
-
* @param {function} f the <i>y</i>-position function.
|
|
123
|
-
* @returns {pv.Layout.Rollup} this.
|
|
124
|
-
* @see pv.Scale.ordinal
|
|
125
|
-
*/
|
|
126
|
-
pv.Layout.Rollup.prototype.y = function(f) {
|
|
127
|
-
this.$y = pv.functor(f);
|
|
128
|
-
return this;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
/** @private */
|
|
132
|
-
pv.Layout.Rollup.prototype.buildImplied = function(s) {
|
|
133
|
-
if (pv.Layout.Network.prototype.buildImplied.call(this, s)) return;
|
|
134
|
-
|
|
135
|
-
var nodes = s.nodes,
|
|
136
|
-
links = s.links,
|
|
137
|
-
directed = s.directed,
|
|
138
|
-
n = nodes.length,
|
|
139
|
-
x = [],
|
|
140
|
-
y = [],
|
|
141
|
-
rnindex = 0,
|
|
142
|
-
rnodes = {},
|
|
143
|
-
rlinks = {};
|
|
144
|
-
|
|
145
|
-
/** @private */
|
|
146
|
-
function id(i) {
|
|
147
|
-
return x[i] + "," + y[i];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/* Iterate over the data, evaluating the x and y functions. */
|
|
151
|
-
var stack = pv.Mark.stack, o = {parent: this};
|
|
152
|
-
stack.unshift(null);
|
|
153
|
-
for (var i = 0; i < n; i++) {
|
|
154
|
-
o.index = i;
|
|
155
|
-
stack[0] = nodes[i];
|
|
156
|
-
x[i] = this.$x.apply(o, stack);
|
|
157
|
-
y[i] = this.$y.apply(o, stack);
|
|
158
|
-
}
|
|
159
|
-
stack.shift();
|
|
160
|
-
|
|
161
|
-
/* Compute rollup nodes. */
|
|
162
|
-
for (var i = 0; i < nodes.length; i++) {
|
|
163
|
-
var nodeId = id(i),
|
|
164
|
-
rn = rnodes[nodeId];
|
|
165
|
-
if (!rn) {
|
|
166
|
-
rn = rnodes[nodeId] = pv.extend(nodes[i]);
|
|
167
|
-
rn.index = rnindex++;
|
|
168
|
-
rn.x = x[i];
|
|
169
|
-
rn.y = y[i];
|
|
170
|
-
rn.nodes = [];
|
|
171
|
-
}
|
|
172
|
-
rn.nodes.push(nodes[i]);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/* Compute rollup links. */
|
|
176
|
-
for (var i = 0; i < links.length; i++) {
|
|
177
|
-
var source = links[i].sourceNode,
|
|
178
|
-
target = links[i].targetNode,
|
|
179
|
-
rsource = rnodes[id(source.index)],
|
|
180
|
-
rtarget = rnodes[id(target.index)],
|
|
181
|
-
reverse = !directed && rsource.index > rtarget.index,
|
|
182
|
-
linkId = reverse
|
|
183
|
-
? rtarget.index + "," + rsource.index
|
|
184
|
-
: rsource.index + "," + rtarget.index,
|
|
185
|
-
rl = rlinks[linkId];
|
|
186
|
-
if (!rl) {
|
|
187
|
-
rl = rlinks[linkId] = {
|
|
188
|
-
sourceNode: rsource,
|
|
189
|
-
targetNode: rtarget,
|
|
190
|
-
linkValue: 0,
|
|
191
|
-
links: []
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
rl.links.push(links[i]);
|
|
195
|
-
rl.linkValue += links[i].linkValue;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/* Export the rolled up nodes and links to the scene. */
|
|
199
|
-
s.$rollup = {
|
|
200
|
-
nodes: pv.values(rnodes),
|
|
201
|
-
links: pv.values(rlinks)
|
|
202
|
-
};
|
|
203
|
-
};
|
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Constructs a new, empty stack layout. Layouts are not typically constructed
|
|
3
|
-
* directly; instead, they are added to an existing panel via
|
|
4
|
-
* {@link pv.Mark#add}.
|
|
5
|
-
*
|
|
6
|
-
* @class Implements a layout for stacked visualizations, ranging from simple
|
|
7
|
-
* stacked bar charts to more elaborate "streamgraphs" composed of stacked
|
|
8
|
-
* areas. Stack layouts uses length as a visual encoding, as opposed to
|
|
9
|
-
* position, as the layers do not share an aligned axis.
|
|
10
|
-
*
|
|
11
|
-
* <p>Marks can be stacked vertically or horizontally. For example,
|
|
12
|
-
*
|
|
13
|
-
* <pre>vis.add(pv.Layout.Stack)
|
|
14
|
-
* .layers([[1, 1.2, 1.7, 1.5, 1.7],
|
|
15
|
-
* [.5, 1, .8, 1.1, 1.3],
|
|
16
|
-
* [.2, .5, .8, .9, 1]])
|
|
17
|
-
* .x(function() this.index * 35)
|
|
18
|
-
* .y(function(d) d * 40)
|
|
19
|
-
* .layer.add(pv.Area);</pre>
|
|
20
|
-
*
|
|
21
|
-
* specifies a vertically-stacked area chart, using the default "bottom-left"
|
|
22
|
-
* orientation with "zero" offset. This visualization can be easily changed into
|
|
23
|
-
* a streamgraph using the "wiggle" offset, which attempts to minimize change in
|
|
24
|
-
* slope weighted by layer thickness. See the {@link #offset} property for more
|
|
25
|
-
* supported streamgraph algorithms.
|
|
26
|
-
*
|
|
27
|
-
* <p>In the simplest case, the layer data can be specified as a two-dimensional
|
|
28
|
-
* array of numbers. The <tt>x</tt> and <tt>y</tt> psuedo-properties are used to
|
|
29
|
-
* define the thickness of each layer at the given position, respectively; in
|
|
30
|
-
* the above example of the "bottom-left" orientation, the <tt>x</tt> and
|
|
31
|
-
* <tt>y</tt> psuedo-properties are equivalent to the <tt>left</tt> and
|
|
32
|
-
* <tt>height</tt> properties that you might use if you implemented a stacked
|
|
33
|
-
* area by hand.
|
|
34
|
-
*
|
|
35
|
-
* <p>The advantage of using the stack layout is that the baseline, i.e., the
|
|
36
|
-
* <tt>bottom</tt> property is computed automatically using the specified offset
|
|
37
|
-
* algorithm. In addition, the order of layers can be computed using a built-in
|
|
38
|
-
* algorithm via the <tt>order</tt> property.
|
|
39
|
-
*
|
|
40
|
-
* <p>With the exception of the "expand" <tt>offset</tt>, the stack layout does
|
|
41
|
-
* not perform any automatic scaling of data; the values returned from
|
|
42
|
-
* <tt>x</tt> and <tt>y</tt> specify pixel sizes. To simplify scaling math, use
|
|
43
|
-
* this layout in conjunction with {@link pv.Scale.linear} or similar.
|
|
44
|
-
*
|
|
45
|
-
* <p>In other cases, the <tt>values</tt> psuedo-property can be used to define
|
|
46
|
-
* the data more flexibly. As with a typical panel & area, the
|
|
47
|
-
* <tt>layers</tt> property corresponds to the data in the enclosing panel,
|
|
48
|
-
* while the <tt>values</tt> psuedo-property corresponds to the data for the
|
|
49
|
-
* area within the panel. For example, given an array of data values:
|
|
50
|
-
*
|
|
51
|
-
* <pre>var crimea = [
|
|
52
|
-
* { date: "4/1854", wounds: 0, other: 110, disease: 110 },
|
|
53
|
-
* { date: "5/1854", wounds: 0, other: 95, disease: 105 },
|
|
54
|
-
* { date: "6/1854", wounds: 0, other: 40, disease: 95 },
|
|
55
|
-
* ...</pre>
|
|
56
|
-
*
|
|
57
|
-
* and a corresponding array of series names:
|
|
58
|
-
*
|
|
59
|
-
* <pre>var causes = ["wounds", "other", "disease"];</pre>
|
|
60
|
-
*
|
|
61
|
-
* Separate layers can be defined for each cause like so:
|
|
62
|
-
*
|
|
63
|
-
* <pre>vis.add(pv.Layout.Stack)
|
|
64
|
-
* .layers(causes)
|
|
65
|
-
* .values(crimea)
|
|
66
|
-
* .x(function(d) x(d.date))
|
|
67
|
-
* .y(function(d, p) y(d[p]))
|
|
68
|
-
* .layer.add(pv.Area)
|
|
69
|
-
* ...</pre>
|
|
70
|
-
*
|
|
71
|
-
* As with the panel & area case, the datum that is passed to the
|
|
72
|
-
* psuedo-properties <tt>x</tt> and <tt>y</tt> are the values (an element in
|
|
73
|
-
* <tt>crimea</tt>); the second argument is the layer data (a string in
|
|
74
|
-
* <tt>causes</tt>). Additional arguments specify the data of enclosing panels,
|
|
75
|
-
* if any.
|
|
76
|
-
*
|
|
77
|
-
* @extends pv.Layout
|
|
78
|
-
*/
|
|
79
|
-
pv.Layout.Stack = function() {
|
|
80
|
-
pv.Layout.call(this);
|
|
81
|
-
var that = this,
|
|
82
|
-
/** @ignore */ none = function() { return null; },
|
|
83
|
-
prop = {t: none, l: none, r: none, b: none, w: none, h: none},
|
|
84
|
-
values,
|
|
85
|
-
buildImplied = that.buildImplied;
|
|
86
|
-
|
|
87
|
-
/** @private Proxy the given property on the layer. */
|
|
88
|
-
function proxy(name) {
|
|
89
|
-
return function() {
|
|
90
|
-
return prop[name](this.parent.index, this.index);
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** @private Compute the layout! */
|
|
95
|
-
this.buildImplied = function(s) {
|
|
96
|
-
buildImplied.call(this, s);
|
|
97
|
-
|
|
98
|
-
var data = s.layers,
|
|
99
|
-
n = data.length,
|
|
100
|
-
m,
|
|
101
|
-
orient = s.orient,
|
|
102
|
-
horizontal = /^(top|bottom)\b/.test(orient),
|
|
103
|
-
h = this.parent[horizontal ? "height" : "width"](),
|
|
104
|
-
x = [],
|
|
105
|
-
y = [],
|
|
106
|
-
dy = [];
|
|
107
|
-
|
|
108
|
-
/*
|
|
109
|
-
* Iterate over the data, evaluating the values, x and y functions. The
|
|
110
|
-
* context in which the x and y psuedo-properties are evaluated is a
|
|
111
|
-
* pseudo-mark that is a grandchild of this layout.
|
|
112
|
-
*/
|
|
113
|
-
var stack = pv.Mark.stack, o = {parent: {parent: this}};
|
|
114
|
-
stack.unshift(null);
|
|
115
|
-
values = [];
|
|
116
|
-
for (var i = 0; i < n; i++) {
|
|
117
|
-
dy[i] = [];
|
|
118
|
-
y[i] = [];
|
|
119
|
-
o.parent.index = i;
|
|
120
|
-
stack[0] = data[i];
|
|
121
|
-
values[i] = this.$values.apply(o.parent, stack);
|
|
122
|
-
if (!i) m = values[i].length;
|
|
123
|
-
stack.unshift(null);
|
|
124
|
-
for (var j = 0; j < m; j++) {
|
|
125
|
-
stack[0] = values[i][j];
|
|
126
|
-
o.index = j;
|
|
127
|
-
if (!i) x[j] = this.$x.apply(o, stack);
|
|
128
|
-
dy[i][j] = this.$y.apply(o, stack);
|
|
129
|
-
}
|
|
130
|
-
stack.shift();
|
|
131
|
-
}
|
|
132
|
-
stack.shift();
|
|
133
|
-
|
|
134
|
-
/* order */
|
|
135
|
-
var index;
|
|
136
|
-
switch (s.order) {
|
|
137
|
-
case "inside-out": {
|
|
138
|
-
var max = dy.map(function(v) { return pv.max.index(v); }),
|
|
139
|
-
map = pv.range(n).sort(function(a, b) { return max[a] - max[b]; }),
|
|
140
|
-
sums = dy.map(function(v) { return pv.sum(v); }),
|
|
141
|
-
top = 0,
|
|
142
|
-
bottom = 0,
|
|
143
|
-
tops = [],
|
|
144
|
-
bottoms = [];
|
|
145
|
-
for (var i = 0; i < n; i++) {
|
|
146
|
-
var j = map[i];
|
|
147
|
-
if (top < bottom) {
|
|
148
|
-
top += sums[j];
|
|
149
|
-
tops.push(j);
|
|
150
|
-
} else {
|
|
151
|
-
bottom += sums[j];
|
|
152
|
-
bottoms.push(j);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
index = bottoms.reverse().concat(tops);
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
case "reverse": index = pv.range(n - 1, -1, -1); break;
|
|
159
|
-
default: index = pv.range(n); break;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/* offset */
|
|
163
|
-
switch (s.offset) {
|
|
164
|
-
case "silohouette": {
|
|
165
|
-
for (var j = 0; j < m; j++) {
|
|
166
|
-
var o = 0;
|
|
167
|
-
for (var i = 0; i < n; i++) o += dy[i][j];
|
|
168
|
-
y[index[0]][j] = (h - o) / 2;
|
|
169
|
-
}
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
case "wiggle": {
|
|
173
|
-
var o = 0;
|
|
174
|
-
for (var i = 0; i < n; i++) o += dy[i][0];
|
|
175
|
-
y[index[0]][0] = o = (h - o) / 2;
|
|
176
|
-
for (var j = 1; j < m; j++) {
|
|
177
|
-
var s1 = 0, s2 = 0, dx = x[j] - x[j - 1];
|
|
178
|
-
for (var i = 0; i < n; i++) s1 += dy[i][j];
|
|
179
|
-
for (var i = 0; i < n; i++) {
|
|
180
|
-
var s3 = (dy[index[i]][j] - dy[index[i]][j - 1]) / (2 * dx);
|
|
181
|
-
for (var k = 0; k < i; k++) {
|
|
182
|
-
s3 += (dy[index[k]][j] - dy[index[k]][j - 1]) / dx;
|
|
183
|
-
}
|
|
184
|
-
s2 += s3 * dy[index[i]][j];
|
|
185
|
-
}
|
|
186
|
-
y[index[0]][j] = o -= s1 ? s2 / s1 * dx : 0;
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
case "expand": {
|
|
191
|
-
for (var j = 0; j < m; j++) {
|
|
192
|
-
y[index[0]][j] = 0;
|
|
193
|
-
var k = 0;
|
|
194
|
-
for (var i = 0; i < n; i++) k += dy[i][j];
|
|
195
|
-
if (k) {
|
|
196
|
-
k = h / k;
|
|
197
|
-
for (var i = 0; i < n; i++) dy[i][j] *= k;
|
|
198
|
-
} else {
|
|
199
|
-
k = h / n;
|
|
200
|
-
for (var i = 0; i < n; i++) dy[i][j] = k;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
default: {
|
|
206
|
-
for (var j = 0; j < m; j++) y[index[0]][j] = 0;
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/* Propagate the offset to the other series. */
|
|
212
|
-
for (var j = 0; j < m; j++) {
|
|
213
|
-
var o = y[index[0]][j];
|
|
214
|
-
for (var i = 1; i < n; i++) {
|
|
215
|
-
o += dy[index[i - 1]][j];
|
|
216
|
-
y[index[i]][j] = o;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/* Find the property definitions for dynamic substitution. */
|
|
221
|
-
var i = orient.indexOf("-"),
|
|
222
|
-
pdy = horizontal ? "h" : "w",
|
|
223
|
-
px = i < 0 ? (horizontal ? "l" : "b") : orient.charAt(i + 1),
|
|
224
|
-
py = orient.charAt(0);
|
|
225
|
-
for (var p in prop) prop[p] = none;
|
|
226
|
-
prop[px] = function(i, j) { return x[j]; };
|
|
227
|
-
prop[py] = function(i, j) { return y[i][j]; };
|
|
228
|
-
prop[pdy] = function(i, j) { return dy[i][j]; };
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* The layer prototype. This prototype is intended to be used with an area,
|
|
233
|
-
* bar or panel mark (or subclass thereof). Other mark types may be possible,
|
|
234
|
-
* though note that the stack layout is not currently designed to support
|
|
235
|
-
* radial stacked visualizations using wedges.
|
|
236
|
-
*
|
|
237
|
-
* <p>The layer is not a direct child of the stack layout; a hidden panel is
|
|
238
|
-
* used to replicate layers.
|
|
239
|
-
*
|
|
240
|
-
* @type pv.Mark
|
|
241
|
-
* @name pv.Layout.Stack.prototype.layer
|
|
242
|
-
*/
|
|
243
|
-
this.layer = new pv.Mark()
|
|
244
|
-
.data(function() { return values[this.parent.index]; })
|
|
245
|
-
.top(proxy("t"))
|
|
246
|
-
.left(proxy("l"))
|
|
247
|
-
.right(proxy("r"))
|
|
248
|
-
.bottom(proxy("b"))
|
|
249
|
-
.width(proxy("w"))
|
|
250
|
-
.height(proxy("h"));
|
|
251
|
-
|
|
252
|
-
this.layer.add = function(type) {
|
|
253
|
-
return that.add(pv.Panel)
|
|
254
|
-
.data(function() { return that.layers(); })
|
|
255
|
-
.add(type)
|
|
256
|
-
.extend(this);
|
|
257
|
-
};
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
pv.Layout.Stack.prototype = pv.extend(pv.Layout)
|
|
261
|
-
.property("orient", String)
|
|
262
|
-
.property("offset", String)
|
|
263
|
-
.property("order", String)
|
|
264
|
-
.property("layers");
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Default properties for stack layouts. The default orientation is
|
|
268
|
-
* "bottom-left", the default offset is "zero", and the default layers is
|
|
269
|
-
* <tt>[[]]</tt>.
|
|
270
|
-
*
|
|
271
|
-
* @type pv.Layout.Stack
|
|
272
|
-
*/
|
|
273
|
-
pv.Layout.Stack.prototype.defaults = new pv.Layout.Stack()
|
|
274
|
-
.extend(pv.Layout.prototype.defaults)
|
|
275
|
-
.orient("bottom-left")
|
|
276
|
-
.offset("zero")
|
|
277
|
-
.layers([[]]);
|
|
278
|
-
|
|
279
|
-
/** @private */
|
|
280
|
-
pv.Layout.Stack.prototype.$x
|
|
281
|
-
= /** @private */ pv.Layout.Stack.prototype.$y
|
|
282
|
-
= function() { return 0; };
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* The x psuedo-property; determines the position of the value within the layer.
|
|
286
|
-
* This typically corresponds to the independent variable. For example, with the
|
|
287
|
-
* default "bottom-left" orientation, this function defines the "left" property.
|
|
288
|
-
*
|
|
289
|
-
* @param {function} f the x function.
|
|
290
|
-
* @returns {pv.Layout.Stack} this.
|
|
291
|
-
*/
|
|
292
|
-
pv.Layout.Stack.prototype.x = function(f) {
|
|
293
|
-
/** @private */ this.$x = pv.functor(f);
|
|
294
|
-
return this;
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* The y psuedo-property; determines the thickness of the layer at the given
|
|
299
|
-
* value. This typically corresponds to the dependent variable. For example,
|
|
300
|
-
* with the default "bottom-left" orientation, this function defines the
|
|
301
|
-
* "height" property.
|
|
302
|
-
*
|
|
303
|
-
* @param {function} f the y function.
|
|
304
|
-
* @returns {pv.Layout.Stack} this.
|
|
305
|
-
*/
|
|
306
|
-
pv.Layout.Stack.prototype.y = function(f) {
|
|
307
|
-
/** @private */ this.$y = pv.functor(f);
|
|
308
|
-
return this;
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
/** @private The default value function; identity. */
|
|
312
|
-
pv.Layout.Stack.prototype.$values = pv.identity;
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* The values function; determines the values for a given layer. The default
|
|
316
|
-
* value is the identity function, which assumes that the layers property is
|
|
317
|
-
* specified as a two-dimensional (i.e., nested) array.
|
|
318
|
-
*
|
|
319
|
-
* @param {function} f the values function.
|
|
320
|
-
* @returns {pv.Layout.Stack} this.
|
|
321
|
-
*/
|
|
322
|
-
pv.Layout.Stack.prototype.values = function(f) {
|
|
323
|
-
this.$values = pv.functor(f);
|
|
324
|
-
return this;
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* The layer data in row-major order. The value of this property is typically a
|
|
329
|
-
* two-dimensional (i.e., nested) array, but any array can be used, provided the
|
|
330
|
-
* values psuedo-property is defined accordingly.
|
|
331
|
-
*
|
|
332
|
-
* @type array[]
|
|
333
|
-
* @name pv.Layout.Stack.prototype.layers
|
|
334
|
-
*/
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* The layer orientation. The following values are supported:<ul>
|
|
338
|
-
*
|
|
339
|
-
* <li>bottom-left == bottom
|
|
340
|
-
* <li>bottom-right
|
|
341
|
-
* <li>top-left == top
|
|
342
|
-
* <li>top-right
|
|
343
|
-
* <li>left-top
|
|
344
|
-
* <li>left-bottom == left
|
|
345
|
-
* <li>right-top
|
|
346
|
-
* <li>right-bottom == right
|
|
347
|
-
*
|
|
348
|
-
* </ul>. The default value is "bottom-left", which means that the layers will
|
|
349
|
-
* be built from the bottom-up, and the values within layers will be laid out
|
|
350
|
-
* from left-to-right.
|
|
351
|
-
*
|
|
352
|
-
* <p>Note that with non-zero baselines, some orientations may give similar
|
|
353
|
-
* results. For example, offset("silohouette") centers the layers, resulting in
|
|
354
|
-
* a streamgraph. Thus, the orientations "bottom-left" and "top-left" will
|
|
355
|
-
* produce similar results, differing only in the layer order.
|
|
356
|
-
*
|
|
357
|
-
* @type string
|
|
358
|
-
* @name pv.Layout.Stack.prototype.orient
|
|
359
|
-
*/
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* The layer order. The following values are supported:<ul>
|
|
363
|
-
*
|
|
364
|
-
* <li><i>null</i> - use given layer order.
|
|
365
|
-
* <li>inside-out - sort by maximum value, with balanced order.
|
|
366
|
-
* <li>reverse - use reverse of given layer order.
|
|
367
|
-
*
|
|
368
|
-
* </ul>For details on the inside-out order algorithm, refer to "Stacked Graphs
|
|
369
|
-
* -- Geometry & Aesthetics" by L. Byron and M. Wattenberg, IEEE TVCG
|
|
370
|
-
* November/December 2008.
|
|
371
|
-
*
|
|
372
|
-
* @type string
|
|
373
|
-
* @name pv.Layout.Stack.prototype.order
|
|
374
|
-
*/
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* The layer offset; the y-position of the bottom of the lowest layer. The
|
|
378
|
-
* following values are supported:<ul>
|
|
379
|
-
*
|
|
380
|
-
* <li>zero - use a zero baseline, i.e., the y-axis.
|
|
381
|
-
* <li>silohouette - center the stream, i.e., ThemeRiver.
|
|
382
|
-
* <li>wiggle - minimize weighted change in slope.
|
|
383
|
-
* <li>expand - expand layers to fill the enclosing layout dimensions.
|
|
384
|
-
*
|
|
385
|
-
* </ul>For details on these offset algorithms, refer to "Stacked Graphs --
|
|
386
|
-
* Geometry & Aesthetics" by L. Byron and M. Wattenberg, IEEE TVCG
|
|
387
|
-
* November/December 2008.
|
|
388
|
-
*
|
|
389
|
-
* @type string
|
|
390
|
-
* @name pv.Layout.Stack.prototype.offset
|
|
391
|
-
*/
|