charty 0.2.4 → 0.2.9
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/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
|