plotrb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +38 -0
- data/README.rdoc +77 -0
- data/Rakefile +7 -0
- data/examples/arc.rb +31 -0
- data/examples/area.rb +48 -0
- data/examples/bar.rb +44 -0
- data/examples/barley.rb +66 -0
- data/examples/choropleth.rb +48 -0
- data/examples/lifelines.rb +106 -0
- data/examples/scatter.rb +43 -0
- data/lib/plotrb.rb +25 -0
- data/lib/plotrb/axes.rb +208 -0
- data/lib/plotrb/base.rb +193 -0
- data/lib/plotrb/data.rb +232 -0
- data/lib/plotrb/kernel.rb +136 -0
- data/lib/plotrb/legends.rb +168 -0
- data/lib/plotrb/marks.rb +459 -0
- data/lib/plotrb/scales.rb +346 -0
- data/lib/plotrb/simple.rb +197 -0
- data/lib/plotrb/transforms.rb +592 -0
- data/lib/plotrb/version.rb +3 -0
- data/lib/plotrb/visualization.rb +55 -0
- data/plotrb.gemspec +27 -0
- data/spec/plotrb/axes_spec.rb +227 -0
- data/spec/plotrb/base_spec.rb +321 -0
- data/spec/plotrb/data_spec.rb +258 -0
- data/spec/plotrb/kernel_spec.rb +54 -0
- data/spec/plotrb/legends_spec.rb +157 -0
- data/spec/plotrb/marks_spec.rb +46 -0
- data/spec/plotrb/scales_spec.rb +187 -0
- data/spec/plotrb/simple_spec.rb +61 -0
- data/spec/plotrb/transforms_spec.rb +248 -0
- data/spec/plotrb/visualization_spec.rb +93 -0
- data/spec/plotrb_spec.rb +5 -0
- data/spec/spec_helper.rb +12 -0
- metadata +180 -0
@@ -0,0 +1,592 @@
|
|
1
|
+
module Plotrb
|
2
|
+
|
3
|
+
# Data transform performs operations on a data set prior to
|
4
|
+
# visualization.
|
5
|
+
# See {https://github.com/trifacta/vega/wiki/Data-Transforms}
|
6
|
+
class Transform
|
7
|
+
|
8
|
+
include ::Plotrb::Base
|
9
|
+
|
10
|
+
# all available types of transforms defined by Vega
|
11
|
+
TYPES = %i(array copy cross facet filter flatten fold formula slice sort
|
12
|
+
stats truncate unique window zip force geo geopath link pie stack
|
13
|
+
treemap wordcloud)
|
14
|
+
|
15
|
+
TYPES.each do |t|
|
16
|
+
define_singleton_method(t) do |&block|
|
17
|
+
::Plotrb::Transform.new(t, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @!attributes type
|
22
|
+
# @return [Symbol] the transform type
|
23
|
+
add_attributes :type
|
24
|
+
|
25
|
+
def initialize(type, &block)
|
26
|
+
@type = type
|
27
|
+
@extra_fields = [:index, :data]
|
28
|
+
self.send(@type)
|
29
|
+
self.instance_eval(&block) if block_given?
|
30
|
+
::Plotrb::Kernel.transforms << self
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def type
|
35
|
+
@type
|
36
|
+
end
|
37
|
+
|
38
|
+
def extra_fields
|
39
|
+
@extra_fields
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Data Manipulation Transforms
|
45
|
+
|
46
|
+
def array
|
47
|
+
# @!attributes fields
|
48
|
+
# @return [Array<String>] array of field references to copy
|
49
|
+
add_attributes(:fields)
|
50
|
+
define_multi_val_attribute(:fields)
|
51
|
+
self.singleton_class.class_eval { alias_method :take, :fields }
|
52
|
+
end
|
53
|
+
|
54
|
+
def copy
|
55
|
+
# @!attributes from
|
56
|
+
# @return [String] the name of the object to copy values from
|
57
|
+
# @!attributes fields
|
58
|
+
# @return [Array<String>] the fields to copy
|
59
|
+
# @!attributes as
|
60
|
+
# @return [Array<String>] the field names to copy the values to
|
61
|
+
add_attributes(:from, :fields, :as)
|
62
|
+
define_single_val_attribute(:from)
|
63
|
+
define_multi_val_attributes(:fields, :as)
|
64
|
+
self.singleton_class.class_eval { alias_method :take, :fields }
|
65
|
+
end
|
66
|
+
|
67
|
+
def cross
|
68
|
+
# @!attributes with
|
69
|
+
# @return [String] the name of the secondary data to cross with
|
70
|
+
# @!attributes diagonal
|
71
|
+
# @return [Boolean] whether diagonal of cross-product will be included
|
72
|
+
add_attributes(:with, :diagonal)
|
73
|
+
define_single_val_attribute(:with)
|
74
|
+
define_boolean_attribute(:diagonal)
|
75
|
+
self.singleton_class.class_eval {
|
76
|
+
alias_method :include_diagonal, :diagonal
|
77
|
+
alias_method :include_diagonal?, :diagonal?
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def facet
|
82
|
+
# @!attributes keys
|
83
|
+
# @return [Array<String>] the fields to use as keys
|
84
|
+
# @!attributes sort
|
85
|
+
# @return [String, Array<String>] sort criteria
|
86
|
+
add_attributes(:keys, :sort)
|
87
|
+
define_multi_val_attributes(:keys, :sort)
|
88
|
+
self.singleton_class.class_eval { alias_method :group_by, :keys }
|
89
|
+
@extra_fields.concat([:key])
|
90
|
+
end
|
91
|
+
|
92
|
+
def filter
|
93
|
+
# @!attributes test
|
94
|
+
# @return [String] the expression for the filter predicate, which
|
95
|
+
# includes the variable `d`, corresponding to the current data object
|
96
|
+
add_attributes(:test)
|
97
|
+
define_single_val_attribute(:test)
|
98
|
+
end
|
99
|
+
|
100
|
+
def flatten
|
101
|
+
# no parameter needed
|
102
|
+
end
|
103
|
+
|
104
|
+
def fold
|
105
|
+
# @!attributes fields
|
106
|
+
# @return [Array<String>] the field references indicating the data
|
107
|
+
# properties to fold
|
108
|
+
add_attributes(:fields)
|
109
|
+
define_multi_val_attribute(:fields)
|
110
|
+
self.singleton_class.class_eval { alias_method :into, :fields }
|
111
|
+
@extra_fields.concat([:key, :value])
|
112
|
+
end
|
113
|
+
|
114
|
+
def formula
|
115
|
+
# @!attributes field
|
116
|
+
# @return [String] the property name in which to store the value
|
117
|
+
# @!attributes
|
118
|
+
# @return expr [String] the expression for the formula
|
119
|
+
add_attributes(:field, :expr)
|
120
|
+
define_single_val_attributes(:field, :expr)
|
121
|
+
self.singleton_class.class_eval {
|
122
|
+
alias_method :into, :field
|
123
|
+
alias_method :apply, :expr
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
def slice
|
128
|
+
# @!attributes by
|
129
|
+
# @return [Integer, Array<Integer>, Symbol] the sub-array to copy
|
130
|
+
# @!attributes field
|
131
|
+
# @return [String] the data field to copy the max, min or median value
|
132
|
+
add_attributes(:by, :field)
|
133
|
+
define_single_val_attributes(:by, :field)
|
134
|
+
end
|
135
|
+
|
136
|
+
# TODO: allow reverse sort
|
137
|
+
def sort
|
138
|
+
# @!attributes by
|
139
|
+
# @return [String, Array<String>] a list of fields to use as sort
|
140
|
+
# criteria
|
141
|
+
add_attributes(:by)
|
142
|
+
define_multi_val_attribute(:by)
|
143
|
+
end
|
144
|
+
|
145
|
+
def stats
|
146
|
+
# @!attributes value
|
147
|
+
# @return [String] the field for which to computer the statistics
|
148
|
+
# @!attributes median
|
149
|
+
# @return [Boolean] whether median will be computed
|
150
|
+
# @!attributes assign
|
151
|
+
# @return [Boolean] whether add stat property to each data element
|
152
|
+
add_attributes(:value, :median, :assign)
|
153
|
+
define_single_val_attribute(:value)
|
154
|
+
define_boolean_attributes(:median, :assign)
|
155
|
+
self.singleton_class.class_eval {
|
156
|
+
alias_method :from, :value
|
157
|
+
alias_method :include_median, :median
|
158
|
+
alias_method :include_median?, :median?
|
159
|
+
alias_method :store_stats, :assign
|
160
|
+
alias_method :store_stats?, :assign?
|
161
|
+
}
|
162
|
+
@extra_fields.concat([:count, :min, :max, :sum, :mean, :variance, :stdev,
|
163
|
+
:median])
|
164
|
+
end
|
165
|
+
|
166
|
+
def truncate
|
167
|
+
# @!attributes value
|
168
|
+
# @return [String] the field containing values to truncate
|
169
|
+
# @!attributes output
|
170
|
+
# @return [String] the field to store the truncated values
|
171
|
+
# @!attributes limit
|
172
|
+
# @return [Integer] maximum length of truncated string
|
173
|
+
# @!attributes position
|
174
|
+
# @return [Symbol] the position from which to remove text
|
175
|
+
# @!attributes ellipsis
|
176
|
+
# @return [String] the ellipsis for truncated text
|
177
|
+
# @!attributes wordbreak
|
178
|
+
# @return [Boolean] whether to truncate along word boundaries
|
179
|
+
add_attributes(:value, :output, :limit, :position, :ellipsis, :wordbreak)
|
180
|
+
define_single_val_attributes(:value, :output, :limit, :position,
|
181
|
+
:ellipsis)
|
182
|
+
define_boolean_attribute(:wordbreak)
|
183
|
+
self.singleton_class.class_eval {
|
184
|
+
alias_method :from, :value
|
185
|
+
alias_method :to, :output
|
186
|
+
alias_method :max_length, :limit
|
187
|
+
}
|
188
|
+
define_singleton_method :method_missing do |method, *args, &block|
|
189
|
+
if method.to_s =~ /^in_(front|back|middle)$/
|
190
|
+
self.position($1.to_sym, &block)
|
191
|
+
else
|
192
|
+
super
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def unique
|
198
|
+
# @!attributes field
|
199
|
+
# @return [String] the data field for which to compute unique value
|
200
|
+
# @!attributes as
|
201
|
+
# @return [String] the field name to store the unique values
|
202
|
+
add_attributes(:field, :as)
|
203
|
+
define_single_val_attributes(:field, :as)
|
204
|
+
self.singleton_class.class_eval {
|
205
|
+
alias_method :from, :field
|
206
|
+
alias_method :to, :as
|
207
|
+
}
|
208
|
+
end
|
209
|
+
|
210
|
+
def window
|
211
|
+
# @!attributes size
|
212
|
+
# @return [Integer] the size of the sliding window
|
213
|
+
# @!attributes step
|
214
|
+
# @return [Integer] the step size to advance the window per frame
|
215
|
+
add_attributes(:size, :step)
|
216
|
+
define_single_val_attributes(:size, :step)
|
217
|
+
end
|
218
|
+
|
219
|
+
def zip
|
220
|
+
# @!attributes with
|
221
|
+
# @return [String] the name of the secondary data set to zip with the
|
222
|
+
# primary data set
|
223
|
+
# @!attributes as
|
224
|
+
# @return [String] the name of the field to store the secondary data set
|
225
|
+
# values
|
226
|
+
# @!attributes key
|
227
|
+
# @return [String] the field in the primary data set to match against
|
228
|
+
# the secondary data set
|
229
|
+
# @!attributes with_key
|
230
|
+
# @return [String] the field in the secondary data set to match
|
231
|
+
# against the primary data set
|
232
|
+
# @!attributes default
|
233
|
+
# @return [] a default value to use if no matching key value is found
|
234
|
+
add_attributes(:with, :as, :key, :with_key, :default)
|
235
|
+
define_single_val_attributes(:with, :as, :default, :key, :with_key)
|
236
|
+
self.singleton_class.class_eval {
|
237
|
+
alias_method :match, :key
|
238
|
+
alias_method :against, :with_key
|
239
|
+
}
|
240
|
+
end
|
241
|
+
|
242
|
+
# Visual Encoding Transforms
|
243
|
+
|
244
|
+
def force
|
245
|
+
# @!attributes links
|
246
|
+
# @return [String] the name of the link (edge) data set, must have
|
247
|
+
# `source` and `target` attributes
|
248
|
+
# @!attributes size
|
249
|
+
# @return [Array(Integer, Integer)] the dimensions of the layout
|
250
|
+
# @!attributes iterations
|
251
|
+
# @return [Integer] the number of iterations to run
|
252
|
+
# @!attributes charge
|
253
|
+
# @return [Numeric, String] the strength of the charge each node exerts
|
254
|
+
# @!attributes link_distance
|
255
|
+
# @return [Integer, String] the length of edges
|
256
|
+
# @!attributes link_strength
|
257
|
+
# @return [Numeric, String] the tension of edges
|
258
|
+
# @!attributes friction
|
259
|
+
# @return [Numeric] the strength of the friction force used to
|
260
|
+
# stabilize the layout
|
261
|
+
# @!attributes theta
|
262
|
+
# @return [Numeric] the theta parameter for the Barnes-Hut algorithm
|
263
|
+
# used to compute charge forces between nodes
|
264
|
+
# @!attributes gravity
|
265
|
+
# @return [Numeric] the strength of the pseudo-gravity force that pulls
|
266
|
+
# nodes towards the center of the layout area
|
267
|
+
# @!attributes alpha
|
268
|
+
# @return [Numeric] a "temperature" parameter that determines how much
|
269
|
+
# node positions are adjusted at each step
|
270
|
+
attr = [:links, :size, :iterations, :charge, :link_distance,
|
271
|
+
:link_strength, :friction, :theta, :gravity, :alpha]
|
272
|
+
add_attributes(*attr)
|
273
|
+
define_single_val_attributes(*attr)
|
274
|
+
end
|
275
|
+
|
276
|
+
def geo
|
277
|
+
# @!attributes projection
|
278
|
+
# @return [String] the type of cartographic projection to use
|
279
|
+
# @!attributes lon
|
280
|
+
# @return [String] the input longitude values
|
281
|
+
# @!attributes lat
|
282
|
+
# @return [String] the input latitude values
|
283
|
+
# @!attributes center
|
284
|
+
# @return [Array(Integer, Integer)] the center of the projection
|
285
|
+
# @!attributes translate
|
286
|
+
# @return [Array(Integer, Integer)] the translation of the projection
|
287
|
+
# @!attributes scale
|
288
|
+
# @return [Numeric] the scale of the projection
|
289
|
+
# @!attributes rotate
|
290
|
+
# @return [Numeric] the rotation of the projection
|
291
|
+
# @!attributes precision
|
292
|
+
# @return [Numeric] the desired precision of the projection
|
293
|
+
# @!attributes clip_angle
|
294
|
+
# @return [Numeric] the clip angle of the projection
|
295
|
+
attr = [:projection, :lon, :lat, :center, :translate, :scale,
|
296
|
+
:rotate, :precision, :clip_angle]
|
297
|
+
add_attributes(*attr)
|
298
|
+
define_single_val_attributes(*attr)
|
299
|
+
end
|
300
|
+
|
301
|
+
def geopath
|
302
|
+
# @!attributes value
|
303
|
+
# @return [String] the data field containing the GeoJSON feature data
|
304
|
+
# @!attributes (see #geo)
|
305
|
+
attr = [:value, :projection, :center, :translate, :scale, :rotate,
|
306
|
+
:precision, :clip_angle]
|
307
|
+
add_attributes(*attr)
|
308
|
+
define_single_val_attributes(*attr)
|
309
|
+
@value ||= 'data'
|
310
|
+
@extra_fields.concat([:path])
|
311
|
+
end
|
312
|
+
|
313
|
+
def link
|
314
|
+
# @!attributes source
|
315
|
+
# @return [String] the data field that references the source node for
|
316
|
+
# this link
|
317
|
+
# @!attributes target
|
318
|
+
# @return [String] the data field that references the target node for
|
319
|
+
# this link
|
320
|
+
# @!attributes shape
|
321
|
+
# @return [Symbol] the path shape to use
|
322
|
+
# @!attributes tension
|
323
|
+
# @return [Numeric] the tension in the range [0,1] for the "tightness"
|
324
|
+
# of 'curve'-shaped links
|
325
|
+
attr = [:source, :target, :shape, :tension]
|
326
|
+
add_attributes(*attr)
|
327
|
+
define_single_val_attributes(*attr)
|
328
|
+
@extra_fields.concat([:path])
|
329
|
+
end
|
330
|
+
|
331
|
+
def pie
|
332
|
+
# @!attributes sort
|
333
|
+
# @return [Boolean] whether to sort the data prior to computing angles
|
334
|
+
# @!attributes value
|
335
|
+
# @return [String] the data values to encode as angular spans
|
336
|
+
add_attributes(:sort, :value)
|
337
|
+
define_boolean_attribute(:sort)
|
338
|
+
define_single_val_attribute(:value)
|
339
|
+
@extra_fields.concat([:start_angle, :end_angle])
|
340
|
+
end
|
341
|
+
|
342
|
+
def stack
|
343
|
+
# @!attributes point
|
344
|
+
# @return [String] the data field determining the points at which to
|
345
|
+
# stack
|
346
|
+
# @!attributes height
|
347
|
+
# @return [String] the data field determining the height of a stack
|
348
|
+
# @!attributes offset
|
349
|
+
# @return [Symbol] the baseline offset style
|
350
|
+
# @!attributes order
|
351
|
+
# @return [Symbol] the sort order for stack layers
|
352
|
+
attr = [:point, :height, :offset, :order]
|
353
|
+
add_attributes(*attr)
|
354
|
+
define_single_val_attributes(*attr)
|
355
|
+
@extra_fields.concat([:y, :y2])
|
356
|
+
end
|
357
|
+
|
358
|
+
def treemap
|
359
|
+
# @!attributes padding
|
360
|
+
# @return [Integer, Array(Integer, Integer, Integer, Integer)] the
|
361
|
+
# padding to provide around the internal nodes in the treemap
|
362
|
+
# @!attributes ratio
|
363
|
+
# @return [Numeric] the target aspect ratio for the layout to optimize
|
364
|
+
# @!attributes round
|
365
|
+
# @return [Boolean] whether cell dimensions will be rounded to integer
|
366
|
+
# pixels
|
367
|
+
# @!attributes size
|
368
|
+
# @return [Array(Integer, Integer)] the dimensions of the layout
|
369
|
+
# @!attributes sticky
|
370
|
+
# @return [Boolean] whether repeated runs of the treemap will use cached
|
371
|
+
# partition boundaries
|
372
|
+
# @!attributes value
|
373
|
+
# @return [String] the values to use to determine the area of each
|
374
|
+
# leaf-level treemap cell
|
375
|
+
add_attributes(:padding, :ratio, :round, :size, :sticky, :value)
|
376
|
+
define_single_val_attributes(:padding, :ratio, :size, :value)
|
377
|
+
define_boolean_attributes(:round, :sticky)
|
378
|
+
@extra_fields.concat([:x, :y, :width, :height])
|
379
|
+
end
|
380
|
+
|
381
|
+
def wordcloud
|
382
|
+
# @!attributes font
|
383
|
+
# @return [String] the font face to use within the word cloud
|
384
|
+
# @!attributes font_size
|
385
|
+
# @return [String] the font size for a word
|
386
|
+
# @!attributes font_style
|
387
|
+
# @return [String] the font style to use
|
388
|
+
# @!attributes font_weight
|
389
|
+
# @return [String] the font weight to use
|
390
|
+
# @!attributes padding
|
391
|
+
# @return [Integer, Array(Integer, Integer, Integer, Integer)] the
|
392
|
+
# padding to provide around text in the word cloud
|
393
|
+
# @!attributes rotate
|
394
|
+
# @return [String, Hash] the rotation angle for a word
|
395
|
+
# @!attributes size
|
396
|
+
# @return [Array(Integer, Integer)] the dimensions of the layout
|
397
|
+
# @!attributes text
|
398
|
+
# @return [String] the data field containing the text to visualize
|
399
|
+
attr = [:font, :font_size, :font_style, :font_weight, :padding,
|
400
|
+
:rotate, :size, :text]
|
401
|
+
add_attributes(*attr)
|
402
|
+
define_single_val_attribute(*attr)
|
403
|
+
@extra_fields.concat([:x, :y, :font_size, :font, :angle])
|
404
|
+
end
|
405
|
+
|
406
|
+
def attribute_post_processing
|
407
|
+
process_array_fields
|
408
|
+
process_copy_as
|
409
|
+
process_facet_keys
|
410
|
+
process_filter_test
|
411
|
+
process_fold_fields
|
412
|
+
process_slice_field
|
413
|
+
process_stats_value
|
414
|
+
process_unique_field
|
415
|
+
process_truncate_value
|
416
|
+
process_zip_key
|
417
|
+
process_zip_with_key
|
418
|
+
process_zip_as
|
419
|
+
process_geo_lon
|
420
|
+
process_geo_lat
|
421
|
+
process_link_source
|
422
|
+
process_link_target
|
423
|
+
process_pie_value
|
424
|
+
process_stack_order
|
425
|
+
process_stack_point
|
426
|
+
process_stack_height
|
427
|
+
process_treemap_value
|
428
|
+
process_wordcloud_text
|
429
|
+
process_wordcloud_font_size
|
430
|
+
end
|
431
|
+
|
432
|
+
def process_array_fields
|
433
|
+
return unless @type == :array && @fields
|
434
|
+
@fields.collect! { |f| get_full_field_ref(f) }
|
435
|
+
end
|
436
|
+
|
437
|
+
def process_copy_as
|
438
|
+
return unless @type == :copy && @as && @fields
|
439
|
+
if @as.is_a?(Array) && @as.size != @fields.size
|
440
|
+
raise ArgumentError, 'Unmatched number of fields for copy transform'
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def process_cross_with
|
445
|
+
return unless @type == :cross && @with
|
446
|
+
case @with
|
447
|
+
when String
|
448
|
+
unless ::Plotrb::Kernel.find_data(@with)
|
449
|
+
raise ArgumentError, 'Invalid data for cross transform'
|
450
|
+
end
|
451
|
+
when ::Plotrb::Data
|
452
|
+
@with = @with.name
|
453
|
+
else
|
454
|
+
raise ArgumentError, 'Invalid data for cross transform'
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
def process_facet_keys
|
459
|
+
return unless @type == :facet && @keys
|
460
|
+
@keys.collect! { |k| get_full_field_ref(k) }
|
461
|
+
end
|
462
|
+
|
463
|
+
def process_filter_test
|
464
|
+
return unless @type == :filter && @test
|
465
|
+
unless @test =~ /d\./
|
466
|
+
raise ArgumentError, 'Invalid filter test string, prefix with \'d.\''
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
def process_fold_fields
|
471
|
+
return unless @type == :fold && @fields
|
472
|
+
@fields.collect! { |f| get_full_field_ref(f) }
|
473
|
+
end
|
474
|
+
|
475
|
+
def process_slice_field
|
476
|
+
return unless @type == :slice && @field
|
477
|
+
@field = get_full_field_ref(@field)
|
478
|
+
end
|
479
|
+
|
480
|
+
def process_stats_value
|
481
|
+
return unless @type == :stats && @value
|
482
|
+
@value = get_full_field_ref(@value)
|
483
|
+
end
|
484
|
+
|
485
|
+
def process_unique_field
|
486
|
+
return unless @type == :unique && @field
|
487
|
+
@field = get_full_field_ref(@field)
|
488
|
+
end
|
489
|
+
|
490
|
+
def process_truncate_value
|
491
|
+
return unless @type == :truncate && @value
|
492
|
+
@value = get_full_field_ref(@value)
|
493
|
+
end
|
494
|
+
|
495
|
+
def process_zip_key
|
496
|
+
return unless @type == :zip && @key
|
497
|
+
@key = get_full_field_ref(@key)
|
498
|
+
end
|
499
|
+
|
500
|
+
def process_zip_with_key
|
501
|
+
return unless @type == :zip && @with_key
|
502
|
+
@with_key = get_full_field_ref(@with_key)
|
503
|
+
end
|
504
|
+
|
505
|
+
def process_zip_as
|
506
|
+
return unless @type == :zip && @as
|
507
|
+
@extra_fields.concat([@as.to_sym])
|
508
|
+
end
|
509
|
+
|
510
|
+
def process_geo_lon
|
511
|
+
return unless @type == :geo && @lon
|
512
|
+
@lon = get_full_field_ref(@lon)
|
513
|
+
end
|
514
|
+
|
515
|
+
def process_geo_lat
|
516
|
+
return unless @type == :geo && @lat
|
517
|
+
@lat = get_full_field_ref(@lat)
|
518
|
+
end
|
519
|
+
|
520
|
+
def process_link_source
|
521
|
+
return unless @type == :link && @source
|
522
|
+
@source = get_full_field_ref(@source)
|
523
|
+
end
|
524
|
+
|
525
|
+
def process_link_target
|
526
|
+
return unless @type == :link && @target
|
527
|
+
@target = get_full_field_ref(@target)
|
528
|
+
end
|
529
|
+
|
530
|
+
def process_pie_value
|
531
|
+
return unless @type == :pie
|
532
|
+
if @value
|
533
|
+
@value = get_full_field_ref(@value)
|
534
|
+
else
|
535
|
+
@value = 'data'
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
def process_stack_order
|
540
|
+
return unless @order
|
541
|
+
case @order
|
542
|
+
when :default, 'default', :reverse, 'reverse'
|
543
|
+
when :inside_out, 'inside-out', 'inside_out'
|
544
|
+
@order = 'inside-out'
|
545
|
+
else
|
546
|
+
raise ArgumentError, 'Unsupported stack order'
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
def process_stack_point
|
551
|
+
return unless @type == :stack && @point
|
552
|
+
@point = get_full_field_ref(@point)
|
553
|
+
end
|
554
|
+
|
555
|
+
def process_stack_height
|
556
|
+
return unless @type == :stack && @height
|
557
|
+
@height = get_full_field_ref(@height)
|
558
|
+
end
|
559
|
+
|
560
|
+
def process_treemap_value
|
561
|
+
return unless @type == :treemap && @value
|
562
|
+
@value = get_full_field_ref(@value)
|
563
|
+
end
|
564
|
+
|
565
|
+
def process_wordcloud_text
|
566
|
+
return unless @type == :wordcloud && @text
|
567
|
+
@text = get_full_field_ref(@text)
|
568
|
+
end
|
569
|
+
|
570
|
+
def process_wordcloud_font_size
|
571
|
+
return unless @type == :wordcloud && @font_size
|
572
|
+
@font_size = get_full_field_ref(@font_size)
|
573
|
+
end
|
574
|
+
|
575
|
+
def get_full_field_ref(field)
|
576
|
+
case field
|
577
|
+
when String
|
578
|
+
if field.start_with?('data.') || extra_fields.include?(field.to_sym)
|
579
|
+
field
|
580
|
+
else
|
581
|
+
"data.#{field}"
|
582
|
+
end
|
583
|
+
when ::Plotrb::Data
|
584
|
+
'data'
|
585
|
+
else
|
586
|
+
raise ArgumentError, 'Invalid data field'
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
end
|
591
|
+
|
592
|
+
end
|