charty 0.2.4 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +64 -15
- data/charty.gemspec +10 -3
- data/lib/charty.rb +5 -2
- data/lib/charty/backends/bokeh.rb +2 -2
- data/lib/charty/backends/google_charts.rb +1 -1
- data/lib/charty/backends/gruff.rb +1 -1
- data/lib/charty/backends/plotly.rb +434 -32
- data/lib/charty/backends/plotly_helpers/html_renderer.rb +203 -0
- data/lib/charty/backends/plotly_helpers/notebook_renderer.rb +87 -0
- data/lib/charty/backends/plotly_helpers/plotly_renderer.rb +121 -0
- data/lib/charty/backends/pyplot.rb +187 -48
- data/lib/charty/backends/rubyplot.rb +1 -1
- data/lib/charty/cache_dir.rb +27 -0
- data/lib/charty/dash_pattern_generator.rb +57 -0
- data/lib/charty/index.rb +1 -1
- data/lib/charty/iruby_helper.rb +18 -0
- data/lib/charty/plot_methods.rb +115 -3
- data/lib/charty/plotter.rb +2 -2
- data/lib/charty/plotters.rb +4 -0
- data/lib/charty/plotters/abstract_plotter.rb +106 -11
- data/lib/charty/plotters/bar_plotter.rb +1 -16
- data/lib/charty/plotters/box_plotter.rb +1 -16
- data/lib/charty/plotters/distribution_plotter.rb +150 -0
- data/lib/charty/plotters/histogram_plotter.rb +242 -0
- data/lib/charty/plotters/line_plotter.rb +300 -0
- data/lib/charty/plotters/relational_plotter.rb +213 -96
- data/lib/charty/plotters/scatter_plotter.rb +8 -43
- data/lib/charty/statistics.rb +11 -2
- data/lib/charty/table.rb +124 -14
- data/lib/charty/table_adapters/base_adapter.rb +97 -0
- data/lib/charty/table_adapters/daru_adapter.rb +2 -0
- data/lib/charty/table_adapters/datasets_adapter.rb +7 -0
- data/lib/charty/table_adapters/hash_adapter.rb +19 -3
- data/lib/charty/table_adapters/pandas_adapter.rb +82 -0
- data/lib/charty/util.rb +28 -0
- data/lib/charty/vector_adapters.rb +5 -1
- data/lib/charty/vector_adapters/array_adapter.rb +2 -10
- data/lib/charty/vector_adapters/daru_adapter.rb +3 -11
- data/lib/charty/vector_adapters/narray_adapter.rb +1 -6
- data/lib/charty/vector_adapters/numpy_adapter.rb +1 -1
- data/lib/charty/vector_adapters/pandas_adapter.rb +0 -1
- data/lib/charty/version.rb +1 -1
- metadata +104 -11
- data/lib/charty/missing_value_support.rb +0 -14
@@ -0,0 +1,27 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Charty
|
4
|
+
module CacheDir
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def cache_dir_path
|
8
|
+
platform_cache_dir_path + "charty"
|
9
|
+
end
|
10
|
+
|
11
|
+
def platform_cache_dir_path
|
12
|
+
base_dir = case RUBY_PLATFORM
|
13
|
+
when /mswin/, /mingw/
|
14
|
+
ENV.fetch("LOCALAPPDATA", "~/AppData/Local")
|
15
|
+
when /darwin/
|
16
|
+
"~/Library/Caches"
|
17
|
+
else
|
18
|
+
ENV.fetch("XDG_CACHE_HOME", "~/.cache")
|
19
|
+
end
|
20
|
+
Pathname(base_dir).expand_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def path(*path_components)
|
24
|
+
cache_dir_path.join(*path_components)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Charty
|
2
|
+
module DashPatternGenerator
|
3
|
+
NAMED_PATTERNS = {
|
4
|
+
solid: "",
|
5
|
+
dash: [4, 1.5],
|
6
|
+
dot: [1, 1],
|
7
|
+
dashdot: [3, 1.25, 1.5, 1.25],
|
8
|
+
longdashdot: [5, 1, 1, 1],
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
def self.valid_name?(name)
|
12
|
+
name = case name
|
13
|
+
when Symbol, String
|
14
|
+
name.to_sym
|
15
|
+
else
|
16
|
+
name.to_str.to_sym
|
17
|
+
end
|
18
|
+
NAMED_PATTERNS.key?(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.pattern_to_name(pattern)
|
22
|
+
NAMED_PATTERNS.each do |key, val|
|
23
|
+
return key if pattern == val
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.each
|
29
|
+
return enum_for(__method__) unless block_given?
|
30
|
+
|
31
|
+
NAMED_PATTERNS.each_value do |pattern|
|
32
|
+
yield pattern
|
33
|
+
end
|
34
|
+
|
35
|
+
m = 3
|
36
|
+
while true
|
37
|
+
# Long and short dash combinations
|
38
|
+
a = [3, 1.25].repeated_combination(m).to_a[1..-2].reverse
|
39
|
+
b = [4, 1].repeated_combination(m).to_a[1..-2]
|
40
|
+
|
41
|
+
# Interleave these combinations
|
42
|
+
segment_list = a.zip(b).flatten(1)
|
43
|
+
|
44
|
+
# Insert the gaps
|
45
|
+
segment_list.each do |segment|
|
46
|
+
gap = segment.min
|
47
|
+
pattern = segment.map {|seg| [seg, gap] }.flatten
|
48
|
+
yield pattern
|
49
|
+
end
|
50
|
+
|
51
|
+
m += 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
extend Enumerable
|
56
|
+
end
|
57
|
+
end
|
data/lib/charty/index.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Charty
|
2
|
+
module IRubyHelper
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def iruby_notebook?
|
6
|
+
# TODO: This cannot distinguish notebook and console.
|
7
|
+
defined?(IRuby)
|
8
|
+
end
|
9
|
+
|
10
|
+
def vscode?
|
11
|
+
ENV.key?("VSCODE_PID")
|
12
|
+
end
|
13
|
+
|
14
|
+
def nteract?
|
15
|
+
ENV.key?("NTERACT_EXE")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/charty/plot_methods.rb
CHANGED
@@ -130,6 +130,76 @@ module Charty
|
|
130
130
|
)
|
131
131
|
end
|
132
132
|
|
133
|
+
# Line plot
|
134
|
+
#
|
135
|
+
# @param x [vector-like object, key in data]
|
136
|
+
# @param y [vector-like object, key in data]
|
137
|
+
# @param color [vector-like object, key in data]
|
138
|
+
# @param style [vector-like object, key in data]
|
139
|
+
# @param size [vector-like object, key in data]
|
140
|
+
# @param data [table-like object]
|
141
|
+
# @param key_color [color object]
|
142
|
+
# @param palette [String,Array<Numeric>,Palette]
|
143
|
+
# @param color_order [Array<String>,Array<Symbol>]
|
144
|
+
# @param color_norm
|
145
|
+
# @param sizes [Array, Hash]
|
146
|
+
# @param size_order [Array]
|
147
|
+
# @param size_norm
|
148
|
+
# @param dashes [true, false, Array, Hash]
|
149
|
+
# @param markers [true, false, Array, Hash]
|
150
|
+
# @param style_order [Array]
|
151
|
+
# @param units [vector-like object, key in data]
|
152
|
+
# @param estimator [:mean]
|
153
|
+
# @param n_boot [Integer]
|
154
|
+
# @param random [Integer, Random, nil]
|
155
|
+
# @param sort [true, false]
|
156
|
+
# @param err_style [:band, :bars]
|
157
|
+
# @param err_params [Hash]
|
158
|
+
# @param error_bar
|
159
|
+
# @param x_scale [:linear, :log10]
|
160
|
+
# @param y_scale [:linear, :log10]
|
161
|
+
# @param legend [:auto, :brief, :full, false]
|
162
|
+
# How to draw legend. If :brief, numeric color and size variables
|
163
|
+
# will be represented with a sample of evenly spaced values. If
|
164
|
+
# :full, every group will get an entry in the legend. If :auto,
|
165
|
+
# choose between brief or full representation based on number of
|
166
|
+
# levels. If false, no legend data is added and no legend is drawn.
|
167
|
+
def line_plot(x: nil, y: nil, color: nil, style: nil, size: nil,
|
168
|
+
data: nil, key_color: nil, palette: nil, color_order: nil,
|
169
|
+
color_norm: nil, sizes: nil, size_order: nil, size_norm: nil,
|
170
|
+
markers: nil, dashes: true, style_order: nil,
|
171
|
+
units: nil, estimator: :mean, n_boot: 1000, random: nil,
|
172
|
+
sort: true, err_style: :band, err_params: nil, error_bar: [:ci, 95],
|
173
|
+
x_scale: :linear, y_scale: :linear, legend: :auto, **options, &block)
|
174
|
+
Plotters::LinePlotter.new(
|
175
|
+
data: data,
|
176
|
+
variables: { x: x, y: y, color: color, style: style, size: size },
|
177
|
+
key_color: key_color,
|
178
|
+
palette: palette,
|
179
|
+
color_order: color_order,
|
180
|
+
color_norm: color_norm,
|
181
|
+
sizes: sizes,
|
182
|
+
size_order: size_order,
|
183
|
+
size_norm: size_norm,
|
184
|
+
markers: markers,
|
185
|
+
dashes: dashes,
|
186
|
+
style_order: style_order,
|
187
|
+
units: units,
|
188
|
+
estimator: estimator,
|
189
|
+
n_boot: n_boot,
|
190
|
+
random: random,
|
191
|
+
sort: sort,
|
192
|
+
err_style: err_style,
|
193
|
+
err_params: err_params,
|
194
|
+
error_bar: error_bar,
|
195
|
+
x_scale: x_scale,
|
196
|
+
y_scale: y_scale,
|
197
|
+
legend: legend,
|
198
|
+
**options,
|
199
|
+
&block
|
200
|
+
)
|
201
|
+
end
|
202
|
+
|
133
203
|
# Scatter plot
|
134
204
|
#
|
135
205
|
# @param x [vector-like object, key in data]
|
@@ -146,7 +216,7 @@ module Charty
|
|
146
216
|
# @param size_order [Array]
|
147
217
|
# @param size_norm
|
148
218
|
# @param markers [true, false, Array, Hash]
|
149
|
-
# @param
|
219
|
+
# @param style_order [Array]
|
150
220
|
# @param alpha [scalar number]
|
151
221
|
# Propotional opacity of the points.
|
152
222
|
# @param legend [:auto, :brief, :full, false]
|
@@ -158,7 +228,7 @@ module Charty
|
|
158
228
|
def scatter_plot(x: nil, y: nil, color: nil, style: nil, size: nil,
|
159
229
|
data: nil, key_color: nil, palette: nil, color_order: nil,
|
160
230
|
color_norm: nil, sizes: nil, size_order: nil, size_norm: nil,
|
161
|
-
markers: true,
|
231
|
+
markers: true, style_order: nil, alpha: nil, legend: :auto,
|
162
232
|
**options, &block)
|
163
233
|
Plotters::ScatterPlotter.new(
|
164
234
|
data: data,
|
@@ -171,13 +241,55 @@ module Charty
|
|
171
241
|
size_order: size_order,
|
172
242
|
size_norm: size_norm,
|
173
243
|
markers: markers,
|
174
|
-
|
244
|
+
style_order: style_order,
|
175
245
|
alpha: alpha,
|
176
246
|
legend: legend,
|
177
247
|
**options,
|
178
248
|
&block
|
179
249
|
)
|
180
250
|
end
|
251
|
+
|
252
|
+
def hist_plot(data: nil, x: nil, y: nil, color: nil, weights: nil,
|
253
|
+
stat: :count, bins: :auto,
|
254
|
+
bin_range: nil, common_bins: true,
|
255
|
+
key_color: nil, palette: nil, color_order: nil, color_norm: nil,
|
256
|
+
legend: true, **options, &block)
|
257
|
+
# TODO: support following arguments
|
258
|
+
# - wiehgts
|
259
|
+
# - binwidth
|
260
|
+
# - discrete
|
261
|
+
# - cumulative
|
262
|
+
# - common_norm
|
263
|
+
# - multiple
|
264
|
+
# - element
|
265
|
+
# - fill
|
266
|
+
# - shrink
|
267
|
+
# - kde
|
268
|
+
# - kde_params
|
269
|
+
# - line_params
|
270
|
+
# - thresh
|
271
|
+
# - pthresh
|
272
|
+
# - pmax
|
273
|
+
# - cbar
|
274
|
+
# - cbar_params
|
275
|
+
# - x_log_scale
|
276
|
+
# - y_log_scale
|
277
|
+
Plotters::HistogramPlotter.new(
|
278
|
+
data: data,
|
279
|
+
variables: { x: x, y: y, color: color },
|
280
|
+
weights: weights,
|
281
|
+
stat: stat,
|
282
|
+
bins: bins,
|
283
|
+
bin_range: bin_range,
|
284
|
+
common_bins: common_bins,
|
285
|
+
key_color: key_color,
|
286
|
+
palette: palette,
|
287
|
+
color_order: color_order,
|
288
|
+
color_norm: color_norm,
|
289
|
+
legend: legend,
|
290
|
+
**options,
|
291
|
+
&block)
|
292
|
+
end
|
181
293
|
end
|
182
294
|
|
183
295
|
extend PlotMethods
|
data/lib/charty/plotter.rb
CHANGED
@@ -237,11 +237,11 @@ module Charty
|
|
237
237
|
end
|
238
238
|
|
239
239
|
def render(filename=nil)
|
240
|
-
@backend.
|
240
|
+
@backend.old_style_render(self, filename)
|
241
241
|
end
|
242
242
|
|
243
243
|
def save(filename=nil, **kw)
|
244
|
-
@backend.
|
244
|
+
@backend.old_style_save(self, filename, **kw)
|
245
245
|
end
|
246
246
|
|
247
247
|
def apply(backend)
|
data/lib/charty/plotters.rb
CHANGED
@@ -9,3 +9,7 @@ require_relative "plotters/count_plotter"
|
|
9
9
|
require_relative "plotters/vector_plotter"
|
10
10
|
require_relative "plotters/relational_plotter"
|
11
11
|
require_relative "plotters/scatter_plotter"
|
12
|
+
require_relative "plotters/line_plotter"
|
13
|
+
|
14
|
+
require_relative "plotters/distribution_plotter"
|
15
|
+
require_relative "plotters/histogram_plotter"
|
@@ -8,16 +8,38 @@ module Charty
|
|
8
8
|
self.data = data
|
9
9
|
self.palette = palette
|
10
10
|
substitute_options(options)
|
11
|
+
|
12
|
+
@var_levels = {}
|
13
|
+
@var_ordered = {x: false, y: false}
|
14
|
+
|
11
15
|
yield self if block_given?
|
12
16
|
end
|
13
17
|
|
14
18
|
attr_reader :data, :x, :y, :color
|
15
19
|
attr_reader :color_order, :key_color, :palette
|
16
20
|
|
21
|
+
def var_levels
|
22
|
+
variables.each_key do |var|
|
23
|
+
# TODO: Move mappers from RelationalPlotter to here,
|
24
|
+
# and remove the use of instance_variable_get
|
25
|
+
if instance_variable_defined?(:"@#{var}_mapper")
|
26
|
+
mapper = instance_variable_get(:"@#{var}_mapper")
|
27
|
+
@var_levels[var] = mapper.levels
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@var_levels
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
"#<#{self.class}:0x%016x>" % self.object_id
|
35
|
+
end
|
36
|
+
|
17
37
|
def data=(data)
|
18
38
|
@data = case data
|
19
39
|
when nil, Charty::Table
|
20
40
|
data
|
41
|
+
when method(:array?)
|
42
|
+
Charty::Vector.new(data)
|
21
43
|
else
|
22
44
|
Charty::Table.new(data)
|
23
45
|
end
|
@@ -36,11 +58,7 @@ module Charty
|
|
36
58
|
end
|
37
59
|
|
38
60
|
def color_order=(color_order)
|
39
|
-
|
40
|
-
unless color_order.nil?
|
41
|
-
raise NotImplementedError,
|
42
|
-
"Specifying color_order is not supported yet"
|
43
|
-
end
|
61
|
+
@color_order = color_order
|
44
62
|
end
|
45
63
|
|
46
64
|
# TODO: move to categorical_plotter
|
@@ -140,16 +158,93 @@ module Charty
|
|
140
158
|
end
|
141
159
|
|
142
160
|
private def remove_na!(ary)
|
143
|
-
ary.reject!
|
144
|
-
next true if x.nil?
|
145
|
-
x.respond_to?(:nan?) && x.nan?
|
146
|
-
end
|
161
|
+
ary.reject! {|x| Util.missing?(x) }
|
147
162
|
ary
|
148
163
|
end
|
149
164
|
|
165
|
+
private def each_subset(grouping_vars, reverse: false, processed: false, by_facet: true, allow_empty: false, drop_na: true)
|
166
|
+
case grouping_vars
|
167
|
+
when nil
|
168
|
+
grouping_vars = []
|
169
|
+
when String, Symbol
|
170
|
+
grouping_vars = [grouping_vars.to_sym]
|
171
|
+
end
|
172
|
+
|
173
|
+
if by_facet
|
174
|
+
[:col, :row].each do |facet_var|
|
175
|
+
grouping_vars << facet_var if variables.key?(facet_var)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
grouping_vars = grouping_vars.select {|var| variables.key?(var) }
|
180
|
+
|
181
|
+
data = processed ? processed_data : plot_data
|
182
|
+
data = data.drop_na if drop_na
|
183
|
+
|
184
|
+
levels = var_levels.dup
|
185
|
+
|
186
|
+
([:x, :y] & grouping_vars).each do |axis|
|
187
|
+
levels[axis] = plot_data[axis].categorical_order()
|
188
|
+
if processed
|
189
|
+
# TODO: perform inverse conversion of axis scaling here
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
if not grouping_vars.empty?
|
194
|
+
grouped = data.group_by(grouping_vars, sort: false)
|
195
|
+
grouped.each_group do |group_key, group_data|
|
196
|
+
next if group_data.empty? && !allow_empty
|
197
|
+
|
198
|
+
yield(grouping_vars.zip(group_key).to_h, group_data)
|
199
|
+
end
|
200
|
+
else
|
201
|
+
yield({}, data.dup)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def processed_data
|
206
|
+
@processed_data ||= calculate_processed_data
|
207
|
+
end
|
208
|
+
|
209
|
+
private def calculate_processed_data
|
210
|
+
# TODO: axis scaling support
|
211
|
+
plot_data
|
212
|
+
end
|
213
|
+
|
214
|
+
def save(filename, **kwargs)
|
215
|
+
backend = Backends.current
|
216
|
+
call_render_plot(backend, notebook: false, **kwargs)
|
217
|
+
backend.save(filename, **kwargs)
|
218
|
+
end
|
219
|
+
|
220
|
+
def render(notebook: false, **kwargs)
|
221
|
+
backend = Backends.current
|
222
|
+
call_render_plot(backend, notebook: notebook, **kwargs)
|
223
|
+
backend.render(notebook: notebook, **kwargs)
|
224
|
+
end
|
225
|
+
|
226
|
+
private def call_render_plot(backend, notebook: false, **kwargs)
|
227
|
+
backend.begin_figure
|
228
|
+
render_plot(backend, notebook: notebook, **kwargs)
|
229
|
+
end
|
230
|
+
|
231
|
+
private def render_plot(*, **)
|
232
|
+
raise NotImplementedError,
|
233
|
+
"subclass must implement #{__method__}"
|
234
|
+
end
|
235
|
+
|
150
236
|
def to_iruby
|
151
|
-
|
152
|
-
|
237
|
+
render(notebook: IRubyHelper.iruby_notebook?)
|
238
|
+
end
|
239
|
+
|
240
|
+
def to_iruby_mimebundle(include: [], exclude: [])
|
241
|
+
backend = Backends.current
|
242
|
+
if backend.respond_to?(:render_mimebundle)
|
243
|
+
call_render_plot(backend, notebook: true)
|
244
|
+
backend.render_mimebundle(include: include, exclude: exclude)
|
245
|
+
else
|
246
|
+
{}
|
247
|
+
end
|
153
248
|
end
|
154
249
|
end
|
155
250
|
end
|