charty 0.1.4.dev → 0.2.4
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 +4 -4
- data/.github/workflows/ci.yml +71 -0
- data/.github/workflows/nmatrix.yml +67 -0
- data/.github/workflows/pycall.yml +86 -0
- data/Dockerfile.dev +9 -1
- data/Gemfile +18 -0
- data/README.md +128 -9
- data/Rakefile +4 -5
- data/charty.gemspec +7 -2
- data/examples/Gemfile +1 -0
- data/examples/active_record.ipynb +34 -34
- data/examples/daru.ipynb +71 -29
- data/examples/iris_dataset.ipynb +12 -5
- data/examples/nmatrix.ipynb +30 -30
- data/examples/numo_narray.ipynb +245 -0
- data/examples/palette.rb +71 -0
- data/examples/sample.png +0 -0
- data/examples/sample_bokeh.ipynb +156 -0
- data/examples/sample_google_chart.ipynb +229 -68
- data/examples/sample_gruff.ipynb +148 -133
- data/examples/sample_images/bar_bokeh.html +85 -0
- data/examples/sample_images/barh_bokeh.html +85 -0
- data/examples/sample_images/barh_gruff.png +0 -0
- data/examples/sample_images/box_plot_bokeh.html +85 -0
- data/examples/sample_images/{boxplot_pyplot.png → box_plot_pyplot.png} +0 -0
- data/examples/sample_images/curve_bokeh.html +85 -0
- data/examples/sample_images/curve_with_function_bokeh.html +85 -0
- data/examples/sample_images/{errorbar_pyplot.png → error_bar_pyplot.png} +0 -0
- data/examples/sample_images/hist_gruff.png +0 -0
- data/examples/sample_images/scatter_bokeh.html +85 -0
- data/examples/sample_pyplot.ipynb +37 -35
- data/images/penguins_body_mass_g_flipper_length_mm_scatter_plot.png +0 -0
- data/images/penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png +0 -0
- data/images/penguins_body_mass_g_flipper_length_mm_species_sex_scatter_plot.png +0 -0
- data/images/penguins_species_body_mass_g_bar_plot_h.png +0 -0
- data/images/penguins_species_body_mass_g_bar_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_box_plot_h.png +0 -0
- data/images/penguins_species_body_mass_g_box_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_sex_bar_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_sex_box_plot_v.png +0 -0
- data/lib/charty.rb +13 -7
- data/lib/charty/backend_methods.rb +8 -0
- data/lib/charty/backends.rb +80 -0
- data/lib/charty/backends/bokeh.rb +80 -0
- data/lib/charty/backends/google_charts.rb +267 -0
- data/lib/charty/backends/gruff.rb +104 -67
- data/lib/charty/backends/plotly.rb +549 -0
- data/lib/charty/backends/pyplot.rb +584 -86
- data/lib/charty/backends/rubyplot.rb +82 -74
- data/lib/charty/backends/unicode_plot.rb +79 -0
- data/lib/charty/index.rb +213 -0
- data/lib/charty/linspace.rb +1 -1
- data/lib/charty/missing_value_support.rb +14 -0
- data/lib/charty/plot_methods.rb +184 -0
- data/lib/charty/plotter.rb +57 -41
- data/lib/charty/plotters.rb +11 -0
- data/lib/charty/plotters/abstract_plotter.rb +156 -0
- data/lib/charty/plotters/bar_plotter.rb +216 -0
- data/lib/charty/plotters/box_plotter.rb +94 -0
- data/lib/charty/plotters/categorical_plotter.rb +380 -0
- data/lib/charty/plotters/count_plotter.rb +7 -0
- data/lib/charty/plotters/estimation_support.rb +84 -0
- data/lib/charty/plotters/random_support.rb +25 -0
- data/lib/charty/plotters/relational_plotter.rb +518 -0
- data/lib/charty/plotters/scatter_plotter.rb +115 -0
- data/lib/charty/plotters/vector_plotter.rb +6 -0
- data/lib/charty/statistics.rb +114 -0
- data/lib/charty/table.rb +82 -3
- data/lib/charty/table_adapters.rb +25 -0
- data/lib/charty/table_adapters/active_record_adapter.rb +63 -0
- data/lib/charty/table_adapters/base_adapter.rb +69 -0
- data/lib/charty/table_adapters/daru_adapter.rb +70 -0
- data/lib/charty/table_adapters/datasets_adapter.rb +49 -0
- data/lib/charty/table_adapters/hash_adapter.rb +224 -0
- data/lib/charty/table_adapters/narray_adapter.rb +76 -0
- data/lib/charty/table_adapters/nmatrix_adapter.rb +67 -0
- data/lib/charty/table_adapters/pandas_adapter.rb +81 -0
- data/lib/charty/vector.rb +69 -0
- data/lib/charty/vector_adapters.rb +183 -0
- data/lib/charty/vector_adapters/array_adapter.rb +109 -0
- data/lib/charty/vector_adapters/daru_adapter.rb +171 -0
- data/lib/charty/vector_adapters/narray_adapter.rb +187 -0
- data/lib/charty/vector_adapters/nmatrix_adapter.rb +37 -0
- data/lib/charty/vector_adapters/numpy_adapter.rb +168 -0
- data/lib/charty/vector_adapters/pandas_adapter.rb +200 -0
- data/lib/charty/version.rb +1 -1
- metadata +127 -13
- data/.travis.yml +0 -11
- data/examples/numo-narray.ipynb +0 -234
- data/lib/charty/backends/google_chart.rb +0 -167
- data/lib/charty/plotter_adapter.rb +0 -17
@@ -0,0 +1,25 @@
|
|
1
|
+
module Charty
|
2
|
+
module Plotters
|
3
|
+
module RandomSupport
|
4
|
+
attr_reader :random
|
5
|
+
|
6
|
+
def random=(random)
|
7
|
+
@random = check_random(random)
|
8
|
+
end
|
9
|
+
|
10
|
+
module_function def check_random(random)
|
11
|
+
case random
|
12
|
+
when nil
|
13
|
+
Random.new
|
14
|
+
when Integer
|
15
|
+
Random.new(random)
|
16
|
+
when Random
|
17
|
+
random
|
18
|
+
else
|
19
|
+
raise ArgumentError,
|
20
|
+
"invalid value for random (%p for a generator or a seed value)" % value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,518 @@
|
|
1
|
+
module Charty
|
2
|
+
module Plotters
|
3
|
+
class BaseMapper
|
4
|
+
def initialize(plotter, *params)
|
5
|
+
@plotter = plotter
|
6
|
+
initialize_mapping(*params)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :plotter
|
10
|
+
|
11
|
+
def [](key, *args)
|
12
|
+
case key
|
13
|
+
when Array, Charty::Vector
|
14
|
+
key.map {|k| lookup_single_value(k, *args) }
|
15
|
+
else
|
16
|
+
lookup_single_value(key, *args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class ColorMapper < BaseMapper
|
22
|
+
private def initialize_mapping(palette, order, norm)
|
23
|
+
@palette = palette
|
24
|
+
@order = order
|
25
|
+
@norm = norm
|
26
|
+
|
27
|
+
if plotter.variables.key?(:color)
|
28
|
+
data = plotter.plot_data[:color]
|
29
|
+
end
|
30
|
+
|
31
|
+
if data && data.notnull.any?
|
32
|
+
@map_type = infer_map_type(@palette, @norm, @plotter.input_format, @plotter.var_types[:color])
|
33
|
+
|
34
|
+
case @map_type
|
35
|
+
when :numeric
|
36
|
+
raise NotImplementedError,
|
37
|
+
"numeric color mapping is not supported"
|
38
|
+
when :categorical
|
39
|
+
@cmap = nil
|
40
|
+
@norm = nil
|
41
|
+
@levels, @lookup_table = categorical_mapping(data, @palette, @order)
|
42
|
+
else
|
43
|
+
raise NotImplementedError,
|
44
|
+
"datetime color mapping is not supported"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private def categorical_mapping(data, palette, order)
|
50
|
+
levels = data.categorical_order(order)
|
51
|
+
n_colors = levels.length
|
52
|
+
|
53
|
+
case palette
|
54
|
+
when Hash
|
55
|
+
missing_keys = levels - palette.keys
|
56
|
+
unless missing_keys.empty?
|
57
|
+
raise ArgumentError,
|
58
|
+
"The palette hash is missing keys: %p" % missing_keys
|
59
|
+
end
|
60
|
+
return levels, palette
|
61
|
+
|
62
|
+
when nil
|
63
|
+
current_palette = Palette.default
|
64
|
+
if n_colors <= current_palette.n_colors
|
65
|
+
colors = Palette.new(current_palette.colors, n_colors).colors
|
66
|
+
else
|
67
|
+
colors = Palette.husl_colors(n_colors)
|
68
|
+
end
|
69
|
+
when Array
|
70
|
+
if palette.length != n_colors
|
71
|
+
raise ArgumentError,
|
72
|
+
"The palette list has the wrong number of colors"
|
73
|
+
end
|
74
|
+
colors = palette
|
75
|
+
else
|
76
|
+
colors = Palette.new(palette, n_colors).colors
|
77
|
+
end
|
78
|
+
lookup_table = levels.zip(colors).to_h
|
79
|
+
|
80
|
+
return levels, lookup_table
|
81
|
+
end
|
82
|
+
|
83
|
+
private def infer_map_type(palette, norm, input_format, var_type)
|
84
|
+
case
|
85
|
+
when false # palette is qualitative_palette
|
86
|
+
:categorical
|
87
|
+
when ! norm.nil?
|
88
|
+
:numeric
|
89
|
+
when palette.is_a?(Array),
|
90
|
+
palette.is_a?(Hash)
|
91
|
+
:categorical
|
92
|
+
when input_format == :wide
|
93
|
+
:categorical
|
94
|
+
else
|
95
|
+
var_type
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
attr_reader :palette, :order, :norm, :levels, :lookup_table, :map_type
|
100
|
+
|
101
|
+
def inverse_lookup_table
|
102
|
+
lookup_table.invert
|
103
|
+
end
|
104
|
+
|
105
|
+
def lookup_single_value(key)
|
106
|
+
if @lookup_table.key?(key)
|
107
|
+
@lookup_table[key]
|
108
|
+
elsif @norm
|
109
|
+
# Use the colormap to interpolate between existing datapoints
|
110
|
+
raise NotImplementedError,
|
111
|
+
"Palette interpolation is not implemented yet"
|
112
|
+
# begin
|
113
|
+
# normed = @norm.(key)
|
114
|
+
# rescue ArgumentError, TypeError => err
|
115
|
+
# if key.respond_to?(:nan?) && key.nan?
|
116
|
+
# return "#000000"
|
117
|
+
# else
|
118
|
+
# raise err
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class SizeMapper < BaseMapper
|
126
|
+
# TODO: This should be replaced with red-colors's Normalize feature
|
127
|
+
class SimpleNormalizer
|
128
|
+
def initialize(vmin=nil, vmax=nil)
|
129
|
+
@vmin = vmin
|
130
|
+
@vmax = vmax
|
131
|
+
end
|
132
|
+
|
133
|
+
attr_accessor :vmin, :vmax
|
134
|
+
|
135
|
+
def call(value, clip=nil)
|
136
|
+
scalar_p = false
|
137
|
+
vector_p = false
|
138
|
+
case value
|
139
|
+
when Charty::Vector
|
140
|
+
vector_p = true
|
141
|
+
value = value.to_a
|
142
|
+
when Array
|
143
|
+
# do nothing
|
144
|
+
else
|
145
|
+
scalar_p = true
|
146
|
+
value = [value]
|
147
|
+
end
|
148
|
+
|
149
|
+
@vmin = value.min if vmin.nil?
|
150
|
+
@vmax = value.max if vmax.nil?
|
151
|
+
|
152
|
+
result = value.map {|x| (x - vmin) / (vmax - vmin).to_f }
|
153
|
+
|
154
|
+
case
|
155
|
+
when scalar_p
|
156
|
+
result[0]
|
157
|
+
when vector_p
|
158
|
+
Charty::Vector.new(result, index: value.index)
|
159
|
+
else
|
160
|
+
result
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
private def initialize_mapping(sizes, order, norm)
|
166
|
+
@sizes = sizes
|
167
|
+
@order = order
|
168
|
+
@norm = norm
|
169
|
+
|
170
|
+
return unless plotter.variables.key?(:size)
|
171
|
+
|
172
|
+
data = plotter.plot_data[:size]
|
173
|
+
return unless data.notnull.any?
|
174
|
+
|
175
|
+
@map_type = infer_map_type(sizes, norm, @plotter.var_types[:size])
|
176
|
+
case @map_type
|
177
|
+
when :numeric
|
178
|
+
@levels, @lookup_table, @norm = numeric_mapping(data, sizes, norm)
|
179
|
+
when :categorical
|
180
|
+
@levels, @lookup_table = categorical_mapping(data, sizes, order)
|
181
|
+
else
|
182
|
+
raise NotImplementedError,
|
183
|
+
"datetime color mapping is not supported"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
private def infer_map_type(sizes, norm, var_type)
|
188
|
+
case
|
189
|
+
when ! norm.nil?
|
190
|
+
:numeric
|
191
|
+
when sizes.is_a?(Hash),
|
192
|
+
sizes.is_a?(Array)
|
193
|
+
:categorical
|
194
|
+
else
|
195
|
+
var_type
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
private def numeric_mapping(data, sizes, norm)
|
200
|
+
case sizes
|
201
|
+
when Hash
|
202
|
+
# The presence of a norm object overrides a dictionary of sizes
|
203
|
+
# in specifying a numeric mapping, so we need to process the
|
204
|
+
# dictionary here
|
205
|
+
levels = sizes.keys.sort
|
206
|
+
size_values = sizes.values
|
207
|
+
size_range = [size_values.min, size_values.max]
|
208
|
+
else
|
209
|
+
levels = Charty::Vector.new(data.unique_values).drop_na.to_a
|
210
|
+
levels.sort!
|
211
|
+
|
212
|
+
case sizes
|
213
|
+
when Range
|
214
|
+
size_range = [sizes.begin, sizes.end]
|
215
|
+
when nil
|
216
|
+
size_range = [0r, 1r]
|
217
|
+
else
|
218
|
+
raise ArgumentError,
|
219
|
+
"Unable to recognize the value for `sizes`: %p" % sizes
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Now we have the minimum and the maximum values of sizes
|
224
|
+
case norm
|
225
|
+
when nil
|
226
|
+
norm = SimpleNormalizer.new
|
227
|
+
sizes_scaled = norm.(levels)
|
228
|
+
# when Colors::Normalize
|
229
|
+
# TODO: Must support red-color's Normalize feature
|
230
|
+
else
|
231
|
+
raise ArgumentError,
|
232
|
+
"Unable to recognize the value for `norm`: %p" % norm
|
233
|
+
end
|
234
|
+
|
235
|
+
case sizes
|
236
|
+
when Hash
|
237
|
+
# do nothing
|
238
|
+
else
|
239
|
+
lo, hi = size_range
|
240
|
+
sizes = sizes_scaled.map {|x| lo + x * (hi - lo) }
|
241
|
+
lookup_table = levels.zip(sizes).to_h
|
242
|
+
end
|
243
|
+
|
244
|
+
return levels, lookup_table, norm
|
245
|
+
end
|
246
|
+
|
247
|
+
private def categorical_mapping(data, sizes, order)
|
248
|
+
raise NotImplementedError,
|
249
|
+
"A categorical variable for size is not supported"
|
250
|
+
end
|
251
|
+
|
252
|
+
attr_reader :palette, :order, :norm, :levels
|
253
|
+
|
254
|
+
def lookup_single_value(key)
|
255
|
+
if @lookup_table.key?(key)
|
256
|
+
@lookup_table[key]
|
257
|
+
else
|
258
|
+
normed = @norm.(key) || Float::NAN
|
259
|
+
size_values = @lookup_table.values
|
260
|
+
min, max = size_values.min, size_values.max
|
261
|
+
min + normed * (max - min)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# TODO
|
266
|
+
end
|
267
|
+
|
268
|
+
class StyleMapper < BaseMapper
|
269
|
+
private def initialize_mapping(markers, dashes, order)
|
270
|
+
@markers = markers
|
271
|
+
@dashes = dashes
|
272
|
+
@order = order
|
273
|
+
|
274
|
+
return unless plotter.variables.key?(:style)
|
275
|
+
|
276
|
+
data = plotter.plot_data[:style]
|
277
|
+
return unless data.notnull.any?
|
278
|
+
|
279
|
+
@levels = data.categorical_order(order)
|
280
|
+
|
281
|
+
markers = map_attributes(markers, @levels, unique_markers(@levels.length), :markers)
|
282
|
+
|
283
|
+
# TODO: dashes support
|
284
|
+
|
285
|
+
@lookup_table = @levels.map {|key|
|
286
|
+
record = {
|
287
|
+
marker: markers[key]
|
288
|
+
}
|
289
|
+
[key, record]
|
290
|
+
}.to_h
|
291
|
+
end
|
292
|
+
|
293
|
+
MARKER_NAMES = [
|
294
|
+
:circle, :x, :square, :cross, :diamond, :star_diamond,
|
295
|
+
:triangle_up, :star_square, :triangle_down, :hexagon, :star, :pentagon,
|
296
|
+
].freeze
|
297
|
+
|
298
|
+
private def unique_markers(n)
|
299
|
+
if n > MARKER_NAMES.length
|
300
|
+
raise ArgumentError,
|
301
|
+
"Too many markers are required (%p for %p)" % [n, MARKER_NAMES.length]
|
302
|
+
end
|
303
|
+
MARKER_NAMES[0, n]
|
304
|
+
end
|
305
|
+
|
306
|
+
private def map_attributes(vals, levels, defaults, attr)
|
307
|
+
case vals
|
308
|
+
when true
|
309
|
+
return levels.zip(defaults).to_h
|
310
|
+
when Hash
|
311
|
+
missing_keys = lavels - vals.keys
|
312
|
+
unless missing_keys.empty?
|
313
|
+
raise ArgumentError,
|
314
|
+
"The `%s` levels are missing values: %p" % [attr, missing_keys]
|
315
|
+
end
|
316
|
+
return vals
|
317
|
+
when Array, Enumerable
|
318
|
+
if levels.length != vals.length
|
319
|
+
raise ArgumentError,
|
320
|
+
"%he `%s` argument has the wrong number of values" % attr
|
321
|
+
end
|
322
|
+
return levels.zip(vals).to_h
|
323
|
+
when nil
|
324
|
+
return {}
|
325
|
+
else
|
326
|
+
raise ArgumentError,
|
327
|
+
"Unable to recognize the value for `%s`: %p" % [attr, vals]
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
attr_reader :palette, :order, :norm, :lookup_table, :levels
|
332
|
+
|
333
|
+
def inverse_lookup_table(attr)
|
334
|
+
lookup_table.map { |k, v| [v[attr], k] }.to_h
|
335
|
+
end
|
336
|
+
|
337
|
+
def lookup_single_value(key, attr=nil)
|
338
|
+
case attr
|
339
|
+
when nil
|
340
|
+
@lookup_table[key]
|
341
|
+
else
|
342
|
+
@lookup_table[key][attr]
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
class RelationalPlotter < AbstractPlotter
|
348
|
+
def initialize(x, y, color, style, size, data: nil, **options, &block)
|
349
|
+
super(x, y, color, data: data, **options, &block)
|
350
|
+
|
351
|
+
self.style = style
|
352
|
+
self.size = size
|
353
|
+
|
354
|
+
setup_variables
|
355
|
+
end
|
356
|
+
|
357
|
+
attr_reader :style, :size
|
358
|
+
|
359
|
+
attr_reader :color_norm
|
360
|
+
|
361
|
+
attr_reader :sizes, :size_order, :size_norm
|
362
|
+
|
363
|
+
attr_reader :markers, :marker_order
|
364
|
+
|
365
|
+
def style=(val)
|
366
|
+
@style = check_dimension(val, :style)
|
367
|
+
end
|
368
|
+
|
369
|
+
def size=(val)
|
370
|
+
@size = check_dimension(val, :size)
|
371
|
+
end
|
372
|
+
|
373
|
+
def color_norm=(val)
|
374
|
+
unless val.nil?
|
375
|
+
raise NotImplementedError,
|
376
|
+
"Specifying color_norm is not supported yet"
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def sizes=(val)
|
381
|
+
unless val.nil?
|
382
|
+
raise NotImplementedError,
|
383
|
+
"Specifying sizes is not supported yet"
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def size_order=(val)
|
388
|
+
unless val.nil?
|
389
|
+
raise NotImplementedError,
|
390
|
+
"Specifying size_order is not supported yet"
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def size_norm=(val)
|
395
|
+
unless val.nil?
|
396
|
+
raise NotImplementedError,
|
397
|
+
"Specifying size_order is not supported yet"
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def markers=(val)
|
402
|
+
@markers = check_markers(val)
|
403
|
+
end
|
404
|
+
|
405
|
+
private def check_markers(val)
|
406
|
+
# TODO
|
407
|
+
val
|
408
|
+
end
|
409
|
+
|
410
|
+
def marker_order=(val)
|
411
|
+
unless val.nil?
|
412
|
+
raise NotImplementedError,
|
413
|
+
"Specifying marker_order is not supported yet"
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
attr_reader :input_format, :plot_data, :variables, :var_types
|
418
|
+
|
419
|
+
private def setup_variables
|
420
|
+
if x.nil? && y.nl?
|
421
|
+
@input_format = :wide
|
422
|
+
setup_variables_with_wide_form_dataset
|
423
|
+
else
|
424
|
+
@input_format = :long
|
425
|
+
setup_variables_with_long_form_dataset
|
426
|
+
end
|
427
|
+
|
428
|
+
@var_types = @plot_data.columns.map { |k|
|
429
|
+
[k, variable_type(@plot_data[k], :categorical)]
|
430
|
+
}.to_h
|
431
|
+
end
|
432
|
+
|
433
|
+
private def setup_variables_with_wide_form_dataset
|
434
|
+
unless color.nil? && style.nil? && size.nil?
|
435
|
+
vars = []
|
436
|
+
vars << "color" unless color.nil?
|
437
|
+
vars << "style" unless style.nil?
|
438
|
+
vars << "size" unless size.nil?
|
439
|
+
raise ArgumentError,
|
440
|
+
"Unable to assign the following variables in wide-form data: " +
|
441
|
+
vars.join(", ")
|
442
|
+
end
|
443
|
+
|
444
|
+
if data.nil? || data.empty?
|
445
|
+
@plot_data = Charty::Table.new({})
|
446
|
+
@variables = {}
|
447
|
+
return
|
448
|
+
end
|
449
|
+
|
450
|
+
# TODO: detect flat data
|
451
|
+
flat = false
|
452
|
+
|
453
|
+
if flat
|
454
|
+
# TODO: Support flat data
|
455
|
+
else
|
456
|
+
raise NotImplementedError,
|
457
|
+
"wide-form input is not supported"
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
private def setup_variables_with_long_form_dataset
|
462
|
+
if data.nil? || data.empty?
|
463
|
+
@plot_data = Charty::Table.new({})
|
464
|
+
@variables = {}
|
465
|
+
return
|
466
|
+
end
|
467
|
+
|
468
|
+
plot_data = {}
|
469
|
+
variables = {}
|
470
|
+
|
471
|
+
{
|
472
|
+
x: self.x,
|
473
|
+
y: self.y,
|
474
|
+
color: self.color,
|
475
|
+
style: self.style,
|
476
|
+
size: self.size
|
477
|
+
}.each do |key, val|
|
478
|
+
next if val.nil?
|
479
|
+
|
480
|
+
if data.column_names.include?(val)
|
481
|
+
plot_data[key] = data[val]
|
482
|
+
variables[key] = val
|
483
|
+
else
|
484
|
+
case val
|
485
|
+
when Charty::Vector
|
486
|
+
plot_data[key] = val
|
487
|
+
variables[key] = val.name
|
488
|
+
else
|
489
|
+
raise ArgumentError,
|
490
|
+
"Could not interpret value %p for parameter %p" % [val, key]
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
@plot_data = Charty::Table.new(plot_data)
|
496
|
+
@variables = variables.select do |var, name|
|
497
|
+
@plot_data[var].notnull.any?
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
private def annotate_axes(backend)
|
502
|
+
# TODO
|
503
|
+
end
|
504
|
+
|
505
|
+
private def map_color(palette: nil, order: nil, norm: nil)
|
506
|
+
@color_mapper = ColorMapper.new(self, palette, order, norm)
|
507
|
+
end
|
508
|
+
|
509
|
+
private def map_size(sizes: nil, order: nil, norm: nil)
|
510
|
+
@size_mapper = SizeMapper.new(self, sizes, order, norm)
|
511
|
+
end
|
512
|
+
|
513
|
+
private def map_style(markers: nil, dashes: nil, order: nil)
|
514
|
+
@style_mapper = StyleMapper.new(self, markers, dashes, order)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|