rubyvis 0.1.7 → 0.2.0

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.
@@ -1,14 +1,61 @@
1
1
  module Rubyvis
2
+ #
3
+ # :section: colors/Ramp.js
4
+
5
+
6
+ # Returns a linear color ramp from the specified <tt>start</tt> color to the
7
+ # specified <tt>end</tt> color. The color arguments may be specified either as
8
+ # <tt>string</tt>s or as Rubyvis::Color. This is equivalent to:
9
+ #
10
+ # <pre> pv.Scale.linear().domain(0, 1).range(...)</pre>
11
+ def self.ramp(*arguments)
12
+ start, _end, dummy = arguments
13
+ scale = Rubyvis.Scale.linear
14
+ scale.range(*arguments)
15
+ scale
16
+ end
17
+
18
+ # :section: colors/Colors.js
19
+
2
20
  # Alias for Rubyvis::Colors
3
21
  def self.Colors
4
22
  Rubyvis::Colors
5
23
  end
24
+
25
+ # Returns a new categorical color encoding using the specified colors. The
26
+ # arguments to this method are an array of colors; see Rubyvis.color(). For
27
+ # example, to create a categorical color encoding using the <tt>species</tt>
28
+ # attribute:
29
+ #
30
+ # <pre>Rubyvis.colors("red", "green", "blue").by(lambda{|d| d.species})</pre>
31
+ #
32
+ # The result of this expression can be used as a fill- or stroke-style
33
+ # property. This assumes that the data's <tt>species</tt> attribute is a
34
+ # string.
35
+ #
6
36
  def self.colors(*args)
7
37
  scale=Rubyvis::Scale.ordinal
8
38
  scale.range(*args)
9
39
  scale
10
40
  end
41
+
42
+ # A collection of standard color palettes for categorical encoding.
11
43
  module Colors
44
+
45
+ # Returns a new 10-color scheme. The arguments to this constructor are
46
+ # optional, and equivalent to calling Rubyvis::Scale::Ordinal.domain. The
47
+ # following colors are used:
48
+ #
49
+ # <div style="background:#1f77b4;">#1f77b4</div>
50
+ # <div style="background:#ff7f0e;">#ff7f0e</div>
51
+ # <div style="background:#2ca02c;">#2ca02c</div>
52
+ # <div style="background:#d62728;">#d62728</div>
53
+ # <div style="background:#9467bd;">#9467bd</div>
54
+ # <div style="background:#8c564b;">#8c564b</div>
55
+ # <div style="background:#e377c2;">#e377c2</div>
56
+ # <div style="background:#7f7f7f;">#7f7f7f</div>
57
+ # <div style="background:#bcbd22;">#bcbd22</div>
58
+ # <div style="background:#17becf;">#17becf</div>
12
59
  def self.category10(*arguments)
13
60
  scale = Rubyvis.colors(
14
61
  "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd",
@@ -16,6 +63,30 @@ module Rubyvis
16
63
  scale.domain(*arguments) if arguments.size>0
17
64
  scale
18
65
  end
66
+
67
+ # Returns a new alternative 19-color scheme. The arguments to this constructor
68
+ # are optional, and equivalent to calling
69
+ # Rubyvis::Scale::Ordinal.domain. The following colors are used:
70
+ #
71
+ # <div style="background:#9c9ede;">#9c9ede</div>
72
+ # <div style="background:#7375b5;">#7375b5</div>
73
+ # <div style="background:#4a5584;">#4a5584</div>
74
+ # <div style="background:#cedb9c;">#cedb9c</div>
75
+ # <div style="background:#b5cf6b;">#b5cf6b</div>
76
+ # <div style="background:#8ca252;">#8ca252</div>
77
+ # <div style="background:#637939;">#637939</div>
78
+ # <div style="background:#e7cb94;">#e7cb94</div>
79
+ # <div style="background:#e7ba52;">#e7ba52</div>
80
+ # <div style="background:#bd9e39;">#bd9e39</div>
81
+ # <div style="background:#8c6d31;">#8c6d31</div>
82
+ # <div style="background:#e7969c;">#e7969c</div>
83
+ # <div style="background:#d6616b;">#d6616b</div>
84
+ # <div style="background:#ad494a;">#ad494a</div>
85
+ # <div style="background:#843c39;">#843c39</div>
86
+ # <div style="background:#de9ed6;">#de9ed6</div>
87
+ # <div style="background:#ce6dbd;">#ce6dbd</div>
88
+ # <div style="background:#a55194;">#a55194</div>
89
+ # <div style="background:#7b4173;">#7b4173</div>
19
90
  def self.category19(*arguments)
20
91
  scale = Rubyvis.colors(
21
92
  "#9c9ede", "#7375b5", "#4a5584", "#cedb9c", "#b5cf6b",
@@ -25,6 +96,33 @@ module Rubyvis
25
96
  scale.domain(*arguments) if arguments.size>0
26
97
  scale
27
98
  end
99
+
100
+
101
+ # Returns a new 20-color scheme. The arguments to this constructor are
102
+ # optional, and equivalent to calling Rubyvis::Scale::Ordinal.domain. The
103
+ # following colors are used:
104
+ #
105
+ # <div style="background:#1f77b4;">#1f77b4</div>
106
+ # <div style="background:#aec7e8;">#aec7e8</div>
107
+ # <div style="background:#ff7f0e;">#ff7f0e</div>
108
+ # <div style="background:#ffbb78;">#ffbb78</div>
109
+ # <div style="background:#2ca02c;">#2ca02c</div>
110
+ # <div style="background:#98df8a;">#98df8a</div>
111
+ # <div style="background:#d62728;">#d62728</div>
112
+ # <div style="background:#ff9896;">#ff9896</div>
113
+ # <div style="background:#9467bd;">#9467bd</div>
114
+ # <div style="background:#c5b0d5;">#c5b0d5</div>
115
+ # <div style="background:#8c564b;">#8c564b</div>
116
+ # <div style="background:#c49c94;">#c49c94</div>
117
+ # <div style="background:#e377c2;">#e377c2</div>
118
+ # <div style="background:#f7b6d2;">#f7b6d2</div>
119
+ # <div style="background:#7f7f7f;">#7f7f7f</div>
120
+ # <div style="background:#c7c7c7;">#c7c7c7</div>
121
+ # <div style="background:#bcbd22;">#bcbd22</div>
122
+ # <div style="background:#dbdb8d;">#dbdb8d</div>
123
+ # <div style="background:#17becf;">#17becf</div>
124
+ # <div style="background:#9edae5;">#9edae5</div>
125
+
28
126
  def self.category20(*arguments)
29
127
  scale = Rubyvis.colors(
30
128
  "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c",
@@ -1,225 +1,300 @@
1
1
  module Rubyvis
2
2
  class Layout
3
- def self.Stack
4
- Rubyvis::Layout::Stack
5
- end
6
- class Stack < Rubyvis::Layout
7
- @properties=Panel.properties.dup
8
-
9
- attr_accessor :_x, :_y, :_values, :prop
10
- attr_accessor_dsl :orient,:offset, :order, :layers
11
- def self.defaults
12
- Stack.new.extend(Layout.defaults).orient("bottom-left").offset("zero").layers([[]])
13
- end
14
- def initialize
15
- super
16
- @none=lambda {nil}
17
- @prop = {"t"=> @none, "l"=> @none, "r"=> @none, "b"=> @none, "w"=> @none, "h"=> @none}
18
- @values=nil
19
- @_x=lambda {return 0}
20
- @_y=lambda {return 0}
21
- @_values=Rubyvis.identity
22
- end
23
- def x(f)
24
- @_x=Rubyvis.functor(f)
25
- return self
26
- end
27
- def y(f)
28
- @_y=Rubyvis.functor(f)
29
- return self
3
+ # Alias for Rubyvis::Layout::Stack
4
+ def self.Stack
5
+ Rubyvis::Layout::Stack
30
6
  end
31
- def values(f=nil)
32
- if f.nil?
33
- @values
34
- else
35
- @_values=Rubyvis.functor(f)
36
- return self
37
- end
38
- end
39
-
40
7
 
41
- def proxy(name)
42
- that=self
43
- return lambda {
44
- a=that.prop[name].js_call(self, self.parent.index, self.index);
45
- puts "proxy(#{name}): #{a}" if $DEBUG
46
- a
47
- }
48
- end
49
-
50
- def build_implied(s)
51
- # puts "Build stack" if $DEBUG
52
- panel_build_implied(s)
53
- data = s.layers
54
- n = data.size
55
- m = nil
56
- orient = s.orient
57
- if orient =~/^(top|bottom)\b/
58
- horizontal=true
59
- else
60
- horizontal=false
8
+ # Implements a layout for stacked visualizations, ranging from simple
9
+ # stacked bar charts to more elaborate "streamgraphs" composed of stacked
10
+ # areas. Stack layouts uses length as a visual encoding, as opposed to
11
+ # position, as the layers do not share an aligned axis.
12
+ #
13
+ # <p>Marks can be stacked vertically or horizontally. For example,
14
+ #
15
+ # vis.add(Rubyvis::Layout::Stack)
16
+ # .layers([[1, 1.2, 1.7, 1.5, 1.7],
17
+ # [.5, 1, .8, 1.1, 1.3],
18
+ # [.2, .5, .8, .9, 1]])
19
+ # .x(lambda { index * 35})
20
+ # .y(lambda {|d| d * 40})
21
+ # .layer.add(Rubyvis::Area)
22
+ #
23
+ # specifies a vertically-stacked area chart, using the default "bottom-left"
24
+ # orientation with "zero" offset. This visualization can be easily changed into
25
+ # a streamgraph using the "wiggle" offset, which attempts to minimize change in
26
+ # slope weighted by layer thickness. See the offset property for more
27
+ # supported streamgraph algorithms.
28
+ #
29
+ # <p>In the simplest case, the layer data can be specified as a two-dimensional
30
+ # array of numbers. The <tt>x</tt> and <tt>y</tt> psuedo-properties are used to
31
+ # define the thickness of each layer at the given position, respectively; in
32
+ # the above example of the "bottom-left" orientation, the <tt>x</tt> and
33
+ # <tt>y</tt> psuedo-properties are equivalent to the <tt>left</tt> and
34
+ # <tt>height</tt> properties that you might use if you implemented a stacked
35
+ # area by hand.
36
+ #
37
+ # <p>The advantage of using the stack layout is that the baseline, i.e., the
38
+ # <tt>bottom</tt> property is computed automatically using the specified offset
39
+ # algorithm. In addition, the order of layers can be computed using a built-in
40
+ # algorithm via the <tt>order</tt> property.
41
+ #
42
+ # <p>With the exception of the "expand" <tt>offset</tt>, the stack layout does
43
+ # not perform any automatic scaling of data; the values returned from
44
+ # <tt>x</tt> and <tt>y</tt> specify pixel sizes. To simplify scaling math, use
45
+ # this layout in conjunction with Rubyvis::Scale.linea} or similar.
46
+ #
47
+ # <p>In other cases, the <tt>values</tt> psuedo-property can be used to define
48
+ # the data more flexibly. As with a typical panel &amp; area, the
49
+ # <tt>layers</tt> property corresponds to the data in the enclosing panel,
50
+ # while the <tt>values</tt> psuedo-property corresponds to the data for the
51
+ # area within the panel. For example, given an array of data values:
52
+ #
53
+ # crimea = [
54
+ # { date: "4/1854", wounds: 0, other: 110, disease: 110 },
55
+ # { date: "5/1854", wounds: 0, other: 95, disease: 105 },
56
+ # { date: "6/1854", wounds: 0, other: 40, disease: 95 },
57
+ # ...
58
+ #
59
+ # and a corresponding array of series names:
60
+ #
61
+ # causes = [:wounds, :other, :disease]
62
+ #
63
+ # Separate layers can be defined for each cause like so:
64
+ #
65
+ # vis.add(pv.Layout.Stack)
66
+ # .layers(causes)
67
+ # .values(crimea)
68
+ # .x(lambda {|d| x.scale(d[:date]})
69
+ # .y(lambda {|d,dp| y.scale(d[dp])})
70
+ # .layer.add(pv.Area)
71
+ #
72
+ # As with the panel &amp; area case, the datum that is passed to the
73
+ # psuedo-properties <tt>x</tt> and <tt>y</tt> are the values (an element in
74
+ # <tt>crimea</tt>); the second argument is the layer data (a string in
75
+ # <tt>causes</tt>). Additional arguments specify the data of enclosing panels, if any.
76
+ class Stack < Rubyvis::Layout
77
+ @properties=Panel.properties.dup
78
+
79
+ attr_accessor :_x, :_y, :_values, :prop
80
+ attr_accessor_dsl :orient,:offset, :order, :layers
81
+ def self.defaults
82
+ Stack.new.extend(Layout.defaults).orient("bottom-left").offset("zero").layers([[]])
61
83
  end
62
- h = self.parent.send(horizontal ? "height" : "width")
63
- x = []
64
- y = []
65
- dy = []
66
84
 
67
- #
68
- # Iterate over the data, evaluating the values, x and y functions. The
69
- # context in which the x and y psuedo-properties are evaluated is a
70
- # pseudo-mark that is a grandchild of this layout.
71
- #
72
- stack = Rubyvis::Mark.stack
85
+ # Constructs a new, empty stack layout. Layouts are not typically constructed
86
+ # directly; instead, they are added to an existing panel via
87
+ # Rubyvis::Mark.add
88
+ def initialize
89
+ super
90
+ @none=lambda {nil}
91
+ @prop = {"t"=> @none, "l"=> @none, "r"=> @none, "b"=> @none, "w"=> @none, "h"=> @none}
92
+ @values=nil
93
+ @_x=lambda {return 0}
94
+ @_y=lambda {return 0}
95
+ @_values=Rubyvis.identity
96
+ end
97
+ def x(f)
98
+ @_x=Rubyvis.functor(f)
99
+ return self
100
+ end
101
+ def y(f)
102
+ @_y=Rubyvis.functor(f)
103
+ return self
104
+ end
105
+ def values(f=nil)
106
+ if f.nil?
107
+ @values
108
+ else
109
+ @_values=Rubyvis.functor(f)
110
+ return self
111
+ end
112
+ end
73
113
 
74
- o = OpenStruct.new({:parent=> OpenStruct.new({:parent=> self})})
75
- stack.unshift(nil)
76
- values = []
77
- n.times {|i|
78
- dy[i] = []
79
- y[i] = []
80
- o.parent.index = i
81
- stack[0] = data[i]
82
- values[i] = self._values.js_apply(o.parent, stack);
83
- m = values[i].size if (i==0)
84
- stack.unshift(nil)
85
- m.times {|j|
86
- stack[0] = values[i][j]
87
- o.index = j
88
- x[j] = self._x.js_apply(o, stack) if i==0
89
- dy[i][j] = self._y.js_apply(o, stack)
90
- }
91
- stack.shift()
92
- }
93
- stack.shift()
94
114
 
95
- # order
96
- _index=nil
97
- case (s.order)
98
- when "inside-out"
99
- max = dy.map {|v| Rubyvis.max.index(v) }
100
- map = pv.range(n).sort {|a,b| return max[a] - max[b]}
101
- sums = dy.map {|v| Rubyvis.sum(v)}
102
- top = 0
103
- bottom = 0
104
- tops = []
105
- bottoms = []
106
- n.times {|i|
107
- j = map[i]
108
- if (top < bottom)
109
- top += sums[j];
110
- tops.push(j);
111
- else
112
- bottom += sums[j];
113
- bottoms.push(j);
114
- end
115
+ def proxy(name)
116
+ that=self
117
+ return lambda {
118
+ a=that.prop[name].js_call(self, self.parent.index, self.index);
119
+ puts "proxy(#{name}): #{a}" if $DEBUG
120
+ a
115
121
  }
116
- _index = bottoms.reverse+tops
117
-
118
- when "reverse"
119
- _index = Rubyvis.range(n - 1, -1, -1)
120
- else
121
- _index = Rubyvis.range(n)
122
122
  end
123
123
 
124
- #/* offset */
125
- case (s.offset)
126
- when "silohouette"
124
+ def build_implied(s)
125
+ # puts "Build stack" if $DEBUG
126
+ panel_build_implied(s)
127
+ data = s.layers
128
+ n = data.size
129
+ m = nil
130
+ orient = s.orient
131
+ if orient =~/^(top|bottom)\b/
132
+ horizontal=true
133
+ else
134
+ horizontal=false
135
+ end
136
+ h = self.parent.send(horizontal ? "height" : "width")
137
+ x = []
138
+ y = []
139
+ dy = []
140
+
141
+ #
142
+ # Iterate over the data, evaluating the values, x and y functions. The
143
+ # context in which the x and y psuedo-properties are evaluated is a
144
+ # pseudo-mark that is a grandchild of this layout.
145
+ #
146
+ stack = Rubyvis::Mark.stack
147
+
148
+ o = OpenStruct.new({:parent=> OpenStruct.new({:parent=> self})})
149
+ stack.unshift(nil)
150
+ values = []
151
+ n.times {|i|
152
+ dy[i] = []
153
+ y[i] = []
154
+ o.parent.index = i
155
+ stack[0] = data[i]
156
+ values[i] = self._values.js_apply(o.parent, stack);
157
+ m = values[i].size if (i==0)
158
+ stack.unshift(nil)
127
159
  m.times {|j|
128
- o = 0;
129
- n.times {|i|
130
- o += dy[i][j]
131
- }
132
- y[_index[0]][j] = (h - o) / 2.0;
160
+ stack[0] = values[i][j]
161
+ o.index = j
162
+ x[j] = self._x.js_apply(o, stack) if i==0
163
+ dy[i][j] = self._y.js_apply(o, stack)
133
164
  }
134
-
135
- when "wiggle"
136
- o = 0;
137
- n.times {|i| o += dy[i][0] }
138
-
139
- y[_index[0]][0] = o = (h - o) / 2.0
165
+ stack.shift()
166
+ }
167
+ stack.shift()
140
168
 
141
- (1...m).each {|j|
142
- s1 = 0
143
- s2 = 0
144
- dx = x[j] - x[j - 1]
145
- n.times {|i| s1 += dy[i][j]}
169
+ # order
170
+ _index=nil
171
+ case (s.order)
172
+ when "inside-out"
173
+ max = dy.map {|v| Rubyvis.max.index(v) }
174
+ map = pv.range(n).sort {|a,b| return max[a] - max[b]}
175
+ sums = dy.map {|v| Rubyvis.sum(v)}
176
+ top = 0
177
+ bottom = 0
178
+ tops = []
179
+ bottoms = []
146
180
  n.times {|i|
147
-
148
- s3 = (dy[_index[i]][j] - dy[_index[i]][j - 1]) / (2.0 * dx)
149
- i.times {|k|
150
- s3 += (dy[_index[k]][j] - dy[_index[k]][j - 1]) / dx.to_f
181
+ j = map[i]
182
+ if (top < bottom)
183
+ top += sums[j];
184
+ tops.push(j);
185
+ else
186
+ bottom += sums[j];
187
+ bottoms.push(j);
188
+ end
189
+ }
190
+ _index = bottoms.reverse+tops
191
+
192
+ when "reverse"
193
+ _index = Rubyvis.range(n - 1, -1, -1)
194
+ else
195
+ _index = Rubyvis.range(n)
196
+ end
197
+
198
+ #/* offset */
199
+ case (s.offset)
200
+ when "silohouette"
201
+ m.times {|j|
202
+ o = 0;
203
+ n.times {|i|
204
+ o += dy[i][j]
151
205
  }
152
- s2 += s3 * dy[_index[i]][j]
206
+ y[_index[0]][j] = (h - o) / 2.0;
153
207
  }
154
- o -= (s1!=0) ? s2 / s1.to_f * dx : 0
155
- y[_index[0]][j] = o
208
+
209
+ when "wiggle"
210
+ o = 0;
211
+ n.times {|i| o += dy[i][0] }
156
212
 
157
- }
158
- when "expand"
213
+ y[_index[0]][0] = o = (h - o) / 2.0
214
+
215
+ (1...m).each {|j|
216
+ s1 = 0
217
+ s2 = 0
218
+ dx = x[j] - x[j - 1]
219
+ n.times {|i| s1 += dy[i][j]}
220
+ n.times {|i|
221
+
222
+ s3 = (dy[_index[i]][j] - dy[_index[i]][j - 1]) / (2.0 * dx)
223
+ i.times {|k|
224
+ s3 += (dy[_index[k]][j] - dy[_index[k]][j - 1]) / dx.to_f
225
+ }
226
+ s2 += s3 * dy[_index[i]][j]
227
+ }
228
+ o -= (s1!=0) ? s2 / s1.to_f * dx : 0
229
+ y[_index[0]][j] = o
230
+
231
+ }
232
+ when "expand"
233
+ m.times {|j|
234
+ y[_index[0]][j] = 0
235
+
236
+ k = 0
237
+ n.times {|i|k += dy[i][j]}
238
+ if (k!=0)
239
+ k = h / k.to_f
240
+ n.times {|i| dy[i][j] *= k}
241
+ else
242
+ k = h / n.to_f
243
+ n.times { dy[i][j] = k}
244
+ end
245
+ }
246
+ else
247
+ m.times {|j| y[_index[0]][j] = 0}
248
+ end
249
+
250
+ # Propagate the offset to the other series. */
159
251
  m.times {|j|
160
- y[_index[0]][j] = 0
252
+ o = y[_index[0]][j]
253
+ (1...n).each {|i|
161
254
 
162
- k = 0
163
- n.times {|i|k += dy[i][j]}
164
- if (k!=0)
165
- k = h / k.to_f
166
- n.times {|i| dy[i][j] *= k}
167
- else
168
- k = h / n.to_f
169
- n.times { dy[i][j] = k}
170
- end
255
+ o += dy[_index[i - 1]][j]
256
+ y[_index[i]][j] = o
171
257
  }
172
- else
173
- m.times {|j| y[_index[0]][j] = 0}
258
+ }
259
+
260
+ # /* Find the property definitions for dynamic substitution. */
261
+
262
+ i = orient.index("-")
263
+ pdy = horizontal ? "h" : "w"
264
+ px = i < 0 ? (horizontal ? "l" : "b") : orient[i + 1,1]
265
+ py = orient[0,1]
266
+
267
+ @values=values
268
+
269
+ @prop.each {|k,v|
270
+ @prop[k]=@none
271
+ }
272
+ # puts "stack: x:#{px}, y:#{py}, dy:#{pdy}" if $DEBUG
273
+ @prop[px] =lambda {|i1,j| x[j]}
274
+ @prop[py] =lambda {|i1,j| y[i1][j]}
275
+ @prop[pdy]=lambda {|i1,j| dy[i1][j]}
174
276
  end
175
277
 
176
- # Propagate the offset to the other series. */
177
- m.times {|j|
178
- o = y[_index[0]][j]
179
- (1...n).each {|i|
278
+ def layer
279
+ that=self
280
+ value = Rubyvis::Mark.new().data(lambda { that.values[self.parent.index] }).top(proxy("t")).left(proxy("l")).right(proxy("r")).
281
+ bottom(proxy("b")).
282
+ width(proxy("w")).
283
+ height(proxy("h"))
180
284
 
181
- o += dy[_index[i - 1]][j]
182
- y[_index[i]][j] = o
183
- }
184
- }
185
-
186
- # /* Find the property definitions for dynamic substitution. */
187
-
188
- i = orient.index("-")
189
- pdy = horizontal ? "h" : "w"
190
- px = i < 0 ? (horizontal ? "l" : "b") : orient[i + 1,1]
191
- py = orient[0,1]
192
-
193
- @values=values
194
-
195
- @prop.each {|k,v|
196
- @prop[k]=@none
197
- }
198
- # puts "stack: x:#{px}, y:#{py}, dy:#{pdy}" if $DEBUG
199
- @prop[px] =lambda {|i1,j| x[j]}
200
- @prop[py] =lambda {|i1,j| y[i1][j]}
201
- @prop[pdy]=lambda {|i1,j| dy[i1][j]}
202
- end
203
-
204
- def layer
205
- that=self
206
- value = Rubyvis::Mark.new().data(lambda { that.values[self.parent.index] }).top(proxy("t")).left(proxy("l")).right(proxy("r")).
207
- bottom(proxy("b")).
208
- width(proxy("w")).
209
- height(proxy("h"))
210
-
211
- class << value
212
- def that=(v)
213
- @that = v
214
- end
215
- def add(type)
216
- that = @that
217
- that.add( Rubyvis.Panel ).data(lambda { that.layers() }).add(type).extend( self )
285
+ class << value # :nodoc:
286
+ def that=(v)
287
+ @that = v
288
+ end
289
+ def add(type)
290
+ that = @that
291
+ that.add( Rubyvis.Panel ).data(lambda { that.layers() }).add(type).extend( self )
292
+ end
218
293
  end
294
+
295
+ value.that=self
296
+ return value
219
297
  end
220
- value.that=self
221
- return value
222
298
  end
223
299
  end
224
- end
225
300
  end