charty 0.2.9 → 0.2.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/bar_plot.rb +19 -0
- data/examples/box_plot.rb +17 -0
- data/examples/scatter_plot.rb +17 -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/backends/plotly.rb +30 -4
- data/lib/charty/backends/plotly_helpers/notebook_renderer.rb +3 -1
- data/lib/charty/backends/pyplot.rb +30 -0
- data/lib/charty/backends/unicode_plot.rb +9 -9
- data/lib/charty/plot_methods.rb +41 -7
- data/lib/charty/plotters/abstract_plotter.rb +41 -9
- data/lib/charty/plotters/bar_plotter.rb +39 -0
- data/lib/charty/plotters/categorical_plotter.rb +9 -1
- data/lib/charty/plotters/distribution_plotter.rb +36 -6
- data/lib/charty/plotters/histogram_plotter.rb +6 -4
- data/lib/charty/plotters/line_plotter.rb +38 -5
- data/lib/charty/plotters/scatter_plotter.rb +4 -2
- data/lib/charty/table.rb +30 -23
- data/lib/charty/table_adapters/base_adapter.rb +88 -0
- data/lib/charty/table_adapters/daru_adapter.rb +41 -1
- data/lib/charty/table_adapters/hash_adapter.rb +54 -1
- data/lib/charty/table_adapters/pandas_adapter.rb +49 -1
- data/lib/charty/vector.rb +29 -1
- data/lib/charty/vector_adapters.rb +16 -0
- data/lib/charty/vector_adapters/pandas_adapter.rb +10 -1
- data/lib/charty/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d885d476eadfadd3f76f138707ffaf6166eec006b4528fb19c3acce0b97b1c85
|
4
|
+
data.tar.gz: 0630f23f19b65177f3b6dc238717a81a019f9dfa40a40c143d71dcc5c5f760f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 535a69b8d794ccbd30b4328f3188c8a8b50c850cfd84285f79b31162296a9d981313e561ea1089a68be3368b7eb1c83ccc3cb2ff511b8f79aef77e544e261bbe
|
7
|
+
data.tar.gz: 804de2468433db38b5381bcbccab4c28e84c7592bce5c5a98a539ce99c589449759e65ffe7f2e808bd3c5cb5e002ee2219219111561f66f590dbb0ac2c0757bc
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This example generates box_plot results in README.md
|
2
|
+
|
3
|
+
require "charty"
|
4
|
+
require "datasets"
|
5
|
+
require "matplotlib"
|
6
|
+
|
7
|
+
Charty::Backends.use(:pyplot)
|
8
|
+
Matplotlib.use(:agg)
|
9
|
+
|
10
|
+
penguins = Datasets::Penguins.new
|
11
|
+
|
12
|
+
Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g)
|
13
|
+
.save("penguins_species_body_mass_g_bar_plot_v.png")
|
14
|
+
|
15
|
+
Charty.bar_plot(data: penguins, x: :body_mass_g, y: :species)
|
16
|
+
.save("penguins_species_body_mass_g_bar_plot_h.png")
|
17
|
+
|
18
|
+
Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex)
|
19
|
+
.save("penguins_species_body_mass_g_sex_bar_plot_v.png")
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "charty"
|
2
|
+
require "datasets"
|
3
|
+
require "matplotlib"
|
4
|
+
|
5
|
+
Charty::Backends.use(:pyplot)
|
6
|
+
Matplotlib.use(:agg)
|
7
|
+
|
8
|
+
penguins = Datasets::Penguins.new
|
9
|
+
|
10
|
+
Charty.box_plot(data: penguins, x: :species, y: :body_mass_g)
|
11
|
+
.save("penguins_species_body_mass_g_box_plot_v.png")
|
12
|
+
|
13
|
+
Charty.box_plot(data: penguins, x: :body_mass_g, y: :species)
|
14
|
+
.save("penguins_species_body_mass_g_box_plot_h.png")
|
15
|
+
|
16
|
+
Charty.box_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex)
|
17
|
+
.save("penguins_species_body_mass_g_sex_box_plot_v.png")
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "charty"
|
2
|
+
require "datasets"
|
3
|
+
require "matplotlib"
|
4
|
+
|
5
|
+
Charty::Backends.use(:pyplot)
|
6
|
+
Matplotlib.use(:agg)
|
7
|
+
|
8
|
+
penguins = Datasets::Penguins.new
|
9
|
+
|
10
|
+
Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm)
|
11
|
+
.save("penguins_body_mass_g_flipper_length_mm_scatter_plot.png")
|
12
|
+
|
13
|
+
Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm, color: :species)
|
14
|
+
.save("penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png")
|
15
|
+
|
16
|
+
Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm, color: :species, style: :sex)
|
17
|
+
.save("penguins_body_mass_g_flipper_length_mm_species_sex_scatter_plot.png")
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -134,10 +134,8 @@ module Charty
|
|
134
134
|
|
135
135
|
if orient == :v
|
136
136
|
x, y = bar_pos, values
|
137
|
-
x = group_names unless group_names.nil?
|
138
137
|
else
|
139
138
|
x, y = values, bar_pos
|
140
|
-
y = group_names unless group_names.nil?
|
141
139
|
end
|
142
140
|
|
143
141
|
trace = {
|
@@ -241,9 +239,9 @@ module Charty
|
|
241
239
|
}
|
242
240
|
|
243
241
|
if orient == :v
|
244
|
-
trace.update(y: values, x: group_keys)
|
242
|
+
trace.update(y: values, x: group_keys.map(&:to_s))
|
245
243
|
else
|
246
|
-
trace.update(x: values, y: group_keys)
|
244
|
+
trace.update(x: values, y: group_keys.map(&:to_s))
|
247
245
|
end
|
248
246
|
|
249
247
|
trace
|
@@ -613,6 +611,11 @@ module Charty
|
|
613
611
|
end
|
614
612
|
end
|
615
613
|
|
614
|
+
def set_title(title)
|
615
|
+
@layout[:title] ||= {}
|
616
|
+
@layout[:title][:text] = title
|
617
|
+
end
|
618
|
+
|
616
619
|
def set_xlabel(label)
|
617
620
|
@layout[:xaxis] ||= {}
|
618
621
|
@layout[:xaxis][:title] = label
|
@@ -657,6 +660,29 @@ module Charty
|
|
657
660
|
@layout[:yaxis][:range] = [min, max]
|
658
661
|
end
|
659
662
|
|
663
|
+
def set_xscale(scale)
|
664
|
+
scale = check_scale_type(scale, :xscale)
|
665
|
+
@layout[:xaxis] ||= {}
|
666
|
+
@layout[:xaxis][:type] = scale
|
667
|
+
end
|
668
|
+
|
669
|
+
def set_yscale(scale)
|
670
|
+
scale = check_scale_type(scale, :yscale)
|
671
|
+
@layout[:yaxis] ||= {}
|
672
|
+
@layout[:yaxis][:type] = scale
|
673
|
+
end
|
674
|
+
|
675
|
+
private def check_scale_type(val, name)
|
676
|
+
case
|
677
|
+
when :linear, :log
|
678
|
+
val
|
679
|
+
else
|
680
|
+
raise ArgumentError,
|
681
|
+
"Invalid #{name} type: %p" % val,
|
682
|
+
caller
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
660
686
|
def disable_xaxis_grid
|
661
687
|
# do nothing
|
662
688
|
end
|
@@ -7,7 +7,7 @@ module Charty
|
|
7
7
|
@initialized = false
|
8
8
|
end
|
9
9
|
|
10
|
-
def activate
|
10
|
+
def activate
|
11
11
|
return if @initialized
|
12
12
|
|
13
13
|
unless IRubyHelper.iruby_notebook?
|
@@ -50,6 +50,8 @@ module Charty
|
|
50
50
|
END_SCRIPT
|
51
51
|
end
|
52
52
|
IRuby.display(script, mime: "text/html")
|
53
|
+
@initialized = true
|
54
|
+
nil
|
53
55
|
end
|
54
56
|
|
55
57
|
def render(figure, element_id: nil, post_script: nil)
|
@@ -662,6 +662,10 @@ module Charty
|
|
662
662
|
end
|
663
663
|
end
|
664
664
|
|
665
|
+
def set_title(title)
|
666
|
+
@pyplot.gca.set_title(String(title))
|
667
|
+
end
|
668
|
+
|
665
669
|
def set_xlabel(label)
|
666
670
|
@pyplot.gca.set_xlabel(String(label))
|
667
671
|
end
|
@@ -694,6 +698,27 @@ module Charty
|
|
694
698
|
@pyplot.gca.set_ylim(Float(min), Float(max))
|
695
699
|
end
|
696
700
|
|
701
|
+
def set_xscale(scale)
|
702
|
+
scale = check_scale_type(scale, :xscale)
|
703
|
+
@pyplot.gca.set_xscale(scale)
|
704
|
+
end
|
705
|
+
|
706
|
+
def set_yscale(scale)
|
707
|
+
scale = check_scale_type(scale, :yscale)
|
708
|
+
@pyplot.gca.set_yscale(scale)
|
709
|
+
end
|
710
|
+
|
711
|
+
private def check_scale_type(val, name)
|
712
|
+
case
|
713
|
+
when :linear, :log
|
714
|
+
val
|
715
|
+
else
|
716
|
+
raise ArgumentError,
|
717
|
+
"Invalid #{name} type: %p" % val,
|
718
|
+
caller
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
697
722
|
def disable_xaxis_grid
|
698
723
|
@pyplot.gca.xaxis.grid(false)
|
699
724
|
end
|
@@ -715,6 +740,11 @@ module Charty
|
|
715
740
|
nil
|
716
741
|
end
|
717
742
|
|
743
|
+
def render_mimebundle(include: [], exclude: [])
|
744
|
+
show
|
745
|
+
{}
|
746
|
+
end
|
747
|
+
|
718
748
|
SAVEFIG_OPTIONAL_PARAMS = [
|
719
749
|
:dpi, :quality, :optimize, :progressive, :facecolor, :edgecolor,
|
720
750
|
:orientation, :papertype, :transparent, :bbox_inches, :pad_inches,
|
@@ -16,7 +16,7 @@ module Charty
|
|
16
16
|
@layout = {}
|
17
17
|
end
|
18
18
|
|
19
|
-
def bar(bar_pos, values,
|
19
|
+
def bar(bar_pos, _group_names, values, colors, _orient, **kwargs)
|
20
20
|
@figure = {
|
21
21
|
type: :bar,
|
22
22
|
bar_pos: bar_pos,
|
@@ -24,7 +24,7 @@ module Charty
|
|
24
24
|
}
|
25
25
|
end
|
26
26
|
|
27
|
-
def box_plot(plot_data, positions,
|
27
|
+
def box_plot(plot_data, positions, **kwargs)
|
28
28
|
@figure = { type: :box, data: plot_data }
|
29
29
|
end
|
30
30
|
|
@@ -52,13 +52,13 @@ module Charty
|
|
52
52
|
# do nothing
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
56
|
-
case @figure[:type]
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
def render(**kwargs)
|
56
|
+
plot = case @figure[:type]
|
57
|
+
when :bar
|
58
|
+
::UnicodePlot.barplot(@layout[:xtick_labels], @figure[:values], xlabel: @layout[:xlabel])
|
59
|
+
when :box
|
60
|
+
::UnicodePlot.boxplot(@layout[:xtick_labels], @figure[:data], xlabel: @layout[:xlabel])
|
61
|
+
end
|
62
62
|
sio = StringIO.new
|
63
63
|
class << sio
|
64
64
|
def tty?; true; end
|
data/lib/charty/plot_methods.rb
CHANGED
@@ -23,19 +23,24 @@ module Charty
|
|
23
23
|
# @param cap_size Width of the caps on error bars.
|
24
24
|
# @param dodge [true,false] If true, bar position is shifted along the
|
25
25
|
# categorical axis for avoid overlapping when the color-dimension is used.
|
26
|
+
# @param log [true,false] Set the value-axis (e.g. Y-axis if orient is :v) to be log scale.
|
27
|
+
# @param x_label [String,Symbol,#to_str,nil] X-axis label.
|
28
|
+
# @param y_label [String,Symbol,#to_str,nil] Y-axis label.
|
29
|
+
# @param title [String,Symbol,#to_str,nil] Title text.
|
26
30
|
def bar_plot(x: nil, y: nil, color: nil, data: nil,
|
27
31
|
order: nil, color_order: nil,
|
28
32
|
estimator: :mean, ci: 95, n_boot: 1000, units: nil, random: nil,
|
29
33
|
orient: nil, key_color: nil, palette: nil, saturation: 1r,
|
30
34
|
error_color: [0.26, 0.26, 0.26], error_width: nil, cap_size: nil,
|
31
|
-
dodge: true,
|
35
|
+
dodge: true, log: false, x_label: nil, y_label: nil, title: nil,
|
36
|
+
**options, &block)
|
32
37
|
Plotters::BarPlotter.new(
|
33
38
|
data: data, variables: { x: x, y: y, color: color },
|
34
39
|
order: order, orient: orient,
|
35
40
|
estimator: estimator, ci: ci, n_boot: n_boot, units: units, random: random,
|
36
41
|
color_order: color_order, key_color: key_color, palette: palette, saturation: saturation,
|
37
42
|
error_color: error_color, error_width: error_width, cap_size: cap_size,
|
38
|
-
dodge: dodge,
|
43
|
+
dodge: dodge, log: log, x_label: x_label, y_label: y_label, title: title,
|
39
44
|
**options, &block
|
40
45
|
)
|
41
46
|
end
|
@@ -43,7 +48,8 @@ module Charty
|
|
43
48
|
def count_plot(x: nil, y: nil, color: nil, data: nil,
|
44
49
|
order: nil, color_order: nil,
|
45
50
|
orient: nil, key_color: nil, palette: nil, saturation: 1r,
|
46
|
-
dodge: true,
|
51
|
+
dodge: true, log: false, x_label: nil, y_label: nil, title: nil,
|
52
|
+
**options, &block)
|
47
53
|
case
|
48
54
|
when x.nil? && !y.nil?
|
49
55
|
x = y
|
@@ -70,6 +76,9 @@ module Charty
|
|
70
76
|
palette: palette,
|
71
77
|
saturation: saturation,
|
72
78
|
dodge: dodge,
|
79
|
+
x_label: x_label,
|
80
|
+
y_label: y_label,
|
81
|
+
title: title,
|
73
82
|
**options
|
74
83
|
) do |plotter|
|
75
84
|
plotter.value_label = "count"
|
@@ -106,11 +115,15 @@ module Charty
|
|
106
115
|
# @param whisker Propotion of the IQR past the low and high quartiles to
|
107
116
|
# extend the plot whiskers. Points outside of this range will be
|
108
117
|
# treated as outliers.
|
118
|
+
# @param x_label [String,Symbol,#to_str,nil] X-axis label.
|
119
|
+
# @param y_label [String,Symbol,#to_str,nil] Y-axis label.
|
120
|
+
# @param title [String,Symbol,#to_str,nil] Title text.
|
109
121
|
def box_plot(x: nil, y: nil, color: nil, data: nil,
|
110
122
|
order: nil, color_order: nil,
|
111
123
|
orient: nil, key_color: nil, palette: nil, saturation: 1r,
|
112
124
|
width: 0.8r, dodge: true, flier_size: 5, line_width: nil,
|
113
|
-
whisker: 1.5,
|
125
|
+
whisker: 1.5, x_label: nil, y_label: nil, title: nil,
|
126
|
+
**options, &block)
|
114
127
|
Plotters::BoxPlotter.new(
|
115
128
|
data: data,
|
116
129
|
variables: { x: x, y: y, color: color },
|
@@ -125,6 +138,9 @@ module Charty
|
|
125
138
|
flier_size: flier_size,
|
126
139
|
line_width: line_width,
|
127
140
|
whisker: whisker,
|
141
|
+
x_label: x_label,
|
142
|
+
y_label: y_label,
|
143
|
+
title: title,
|
128
144
|
**options,
|
129
145
|
&block
|
130
146
|
)
|
@@ -164,13 +180,18 @@ module Charty
|
|
164
180
|
# :full, every group will get an entry in the legend. If :auto,
|
165
181
|
# choose between brief or full representation based on number of
|
166
182
|
# levels. If false, no legend data is added and no legend is drawn.
|
183
|
+
# @param x_label [String,Symbol,#to_str,nil] X-axis label.
|
184
|
+
# @param y_label [String,Symbol,#to_str,nil] Y-axis label.
|
185
|
+
# @param title [String,Symbol,#to_str,nil] Title text.
|
167
186
|
def line_plot(x: nil, y: nil, color: nil, style: nil, size: nil,
|
168
187
|
data: nil, key_color: nil, palette: nil, color_order: nil,
|
169
188
|
color_norm: nil, sizes: nil, size_order: nil, size_norm: nil,
|
170
189
|
markers: nil, dashes: true, style_order: nil,
|
171
190
|
units: nil, estimator: :mean, n_boot: 1000, random: nil,
|
172
191
|
sort: true, err_style: :band, err_params: nil, error_bar: [:ci, 95],
|
173
|
-
x_scale: :linear, y_scale: :linear, legend: :auto,
|
192
|
+
x_scale: :linear, y_scale: :linear, legend: :auto,
|
193
|
+
x_label: nil, y_label: nil, title: nil,
|
194
|
+
**options, &block)
|
174
195
|
Plotters::LinePlotter.new(
|
175
196
|
data: data,
|
176
197
|
variables: { x: x, y: y, color: color, style: style, size: size },
|
@@ -195,6 +216,9 @@ module Charty
|
|
195
216
|
x_scale: x_scale,
|
196
217
|
y_scale: y_scale,
|
197
218
|
legend: legend,
|
219
|
+
x_label: x_label,
|
220
|
+
y_label: y_label,
|
221
|
+
title: title,
|
198
222
|
**options,
|
199
223
|
&block
|
200
224
|
)
|
@@ -225,11 +249,14 @@ module Charty
|
|
225
249
|
# :full, every group will get an entry in the legend. If :auto,
|
226
250
|
# choose between brief or full representation based on number of
|
227
251
|
# levels. If false, no legend data is added and no legend is drawn.
|
252
|
+
# @param x_label [String,Symbol,#to_str,nil] X-axis label.
|
253
|
+
# @param y_label [String,Symbol,#to_str,nil] Y-axis label.
|
254
|
+
# @param title [String,Symbol,#to_str,nil] Title text.
|
228
255
|
def scatter_plot(x: nil, y: nil, color: nil, style: nil, size: nil,
|
229
256
|
data: nil, key_color: nil, palette: nil, color_order: nil,
|
230
257
|
color_norm: nil, sizes: nil, size_order: nil, size_norm: nil,
|
231
258
|
markers: true, style_order: nil, alpha: nil, legend: :auto,
|
232
|
-
**options, &block)
|
259
|
+
x_label: nil, y_label: nil, title: nil, **options, &block)
|
233
260
|
Plotters::ScatterPlotter.new(
|
234
261
|
data: data,
|
235
262
|
variables: { x: x, y: y, color: color, style: style, size: size },
|
@@ -244,6 +271,9 @@ module Charty
|
|
244
271
|
style_order: style_order,
|
245
272
|
alpha: alpha,
|
246
273
|
legend: legend,
|
274
|
+
x_label: x_label,
|
275
|
+
y_label: y_label,
|
276
|
+
title: title,
|
247
277
|
**options,
|
248
278
|
&block
|
249
279
|
)
|
@@ -253,7 +283,8 @@ module Charty
|
|
253
283
|
stat: :count, bins: :auto,
|
254
284
|
bin_range: nil, common_bins: true,
|
255
285
|
key_color: nil, palette: nil, color_order: nil, color_norm: nil,
|
256
|
-
legend: true,
|
286
|
+
legend: true, x_label: nil, y_label: nil, title: nil,
|
287
|
+
**options, &block)
|
257
288
|
# TODO: support following arguments
|
258
289
|
# - wiehgts
|
259
290
|
# - binwidth
|
@@ -287,6 +318,9 @@ module Charty
|
|
287
318
|
color_order: color_order,
|
288
319
|
color_norm: color_norm,
|
289
320
|
legend: legend,
|
321
|
+
x_label: x_label,
|
322
|
+
y_label: y_label,
|
323
|
+
title: title,
|
290
324
|
**options,
|
291
325
|
&block)
|
292
326
|
end
|
@@ -35,6 +35,8 @@ module Charty
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def data=(data)
|
38
|
+
# TODO: Convert a Charty::Vector to a Charty::Table so that
|
39
|
+
# the Charty::Vector is handled as a wide form data
|
38
40
|
@data = case data
|
39
41
|
when nil, Charty::Table
|
40
42
|
data
|
@@ -81,6 +83,24 @@ module Charty
|
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
86
|
+
attr_reader :x_label
|
87
|
+
|
88
|
+
def x_label=(val)
|
89
|
+
@x_label = check_string(val, :x_label, allow_nil: true)
|
90
|
+
end
|
91
|
+
|
92
|
+
attr_reader :y_label
|
93
|
+
|
94
|
+
def y_label=(val)
|
95
|
+
@y_label = check_string(val, :y_label, allow_nil: true)
|
96
|
+
end
|
97
|
+
|
98
|
+
attr_reader :title
|
99
|
+
|
100
|
+
def title=(val)
|
101
|
+
@title = check_string(val, :title, allow_nil: true)
|
102
|
+
end
|
103
|
+
|
84
104
|
private def substitute_options(options)
|
85
105
|
options.each do |key, val|
|
86
106
|
send("#{key}=", val)
|
@@ -138,6 +158,27 @@ module Charty
|
|
138
158
|
end
|
139
159
|
end
|
140
160
|
|
161
|
+
private def check_string(value, name, allow_nil: false)
|
162
|
+
case value
|
163
|
+
when Symbol
|
164
|
+
value.to_s
|
165
|
+
else
|
166
|
+
if allow_nil && value.nil?
|
167
|
+
nil
|
168
|
+
else
|
169
|
+
orig_value = value
|
170
|
+
value = String.try_convert(value)
|
171
|
+
if value.nil?
|
172
|
+
raise ArgumentError,
|
173
|
+
"`#{name}` must be convertible to String: %p" % orig_value,
|
174
|
+
caller
|
175
|
+
else
|
176
|
+
value
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
141
182
|
private def variable_type(vector, boolean_type=:numeric)
|
142
183
|
if vector.numeric?
|
143
184
|
:numeric
|
@@ -181,15 +222,6 @@ module Charty
|
|
181
222
|
data = processed ? processed_data : plot_data
|
182
223
|
data = data.drop_na if drop_na
|
183
224
|
|
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
225
|
if not grouping_vars.empty?
|
194
226
|
grouped = data.group_by(grouping_vars, sort: false)
|
195
227
|
grouped.each_group do |group_key, group_data|
|
@@ -42,6 +42,12 @@ module Charty
|
|
42
42
|
@cap_size = check_number(cap_size, :cap_size, allow_nil: true)
|
43
43
|
end
|
44
44
|
|
45
|
+
attr_reader :log
|
46
|
+
|
47
|
+
def log=(val)
|
48
|
+
@log = check_boolean(val, :log)
|
49
|
+
end
|
50
|
+
|
45
51
|
private def render_plot(backend, **)
|
46
52
|
draw_bars(backend)
|
47
53
|
annotate_axes(backend)
|
@@ -81,6 +87,39 @@ module Charty
|
|
81
87
|
end
|
82
88
|
end
|
83
89
|
|
90
|
+
private def annotate_axes(backend)
|
91
|
+
super
|
92
|
+
|
93
|
+
if self.log
|
94
|
+
min_value, max_value = @estimations.minmax
|
95
|
+
if @plot_colors
|
96
|
+
unless @conf_int.empty?
|
97
|
+
min_value = [min_value, @conf_int[0]].min
|
98
|
+
max_value = [max_value, @conf_int[1]].max
|
99
|
+
end
|
100
|
+
else
|
101
|
+
ci_min = Util.filter_map(@conf_int) { |ci| ci[0] unless ci.empty? }
|
102
|
+
ci_max = Util.filter_map(@conf_int) { |ci| ci[1] unless ci.empty? }
|
103
|
+
min_value = [min_value, ci_min.min].min unless ci_min.empty?
|
104
|
+
max_value = [max_value, ci_max.max].max unless ci_max.empty?
|
105
|
+
end
|
106
|
+
if min_value > 1
|
107
|
+
min_value = 0
|
108
|
+
else
|
109
|
+
min_value = Math.log10(min_value).floor
|
110
|
+
end
|
111
|
+
max_value = Math.log10(max_value).ceil
|
112
|
+
case self.orient
|
113
|
+
when :v
|
114
|
+
backend.set_yscale(:log)
|
115
|
+
backend.set_ylim(min_value, max_value)
|
116
|
+
else
|
117
|
+
backend.set_xscale(:log)
|
118
|
+
backend.set_xlim(min_value, max_value)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
84
123
|
private def setup_estimations
|
85
124
|
if @color_names.nil?
|
86
125
|
setup_estimations_with_single_color_group
|
@@ -134,6 +134,7 @@ module Charty
|
|
134
134
|
order = @order # TODO: supply order via parameter
|
135
135
|
unless order
|
136
136
|
order = @data.column_names.select do |cn|
|
137
|
+
# TODO: Use Charty::Vector#numeric?
|
137
138
|
@data[cn].all? {|x| Float(x, exception: false) }
|
138
139
|
end
|
139
140
|
end
|
@@ -230,6 +231,7 @@ module Charty
|
|
230
231
|
end
|
231
232
|
return :h
|
232
233
|
end
|
234
|
+
|
233
235
|
case orient
|
234
236
|
when :v
|
235
237
|
if require_numeric && y_type != :numeric
|
@@ -263,7 +265,9 @@ module Charty
|
|
263
265
|
private def group_long_form(vals, groups, group_order)
|
264
266
|
grouped_vals = vals.group_by(groups)
|
265
267
|
|
266
|
-
plot_data = group_order.map
|
268
|
+
plot_data = group_order.map do |g|
|
269
|
+
grouped_vals[g] || Charty::Vector.new([])
|
270
|
+
end
|
267
271
|
|
268
272
|
if vals.respond_to?(:name)
|
269
273
|
value_label = vals.name
|
@@ -347,11 +351,15 @@ module Charty
|
|
347
351
|
end
|
348
352
|
|
349
353
|
private def annotate_axes(backend)
|
354
|
+
backend.set_title(self.title) if self.title
|
355
|
+
|
350
356
|
if orient == :v
|
351
357
|
xlabel, ylabel = @group_label, @value_label
|
352
358
|
else
|
353
359
|
xlabel, ylabel = @value_label, @group_label
|
354
360
|
end
|
361
|
+
xlabel = self.x_label if self.x_label
|
362
|
+
ylabel = self.y_label if self.y_label
|
355
363
|
backend.set_xlabel(xlabel) unless xlabel.nil?
|
356
364
|
backend.set_ylabel(ylabel) unless ylabel.nil?
|
357
365
|
|
@@ -3,7 +3,14 @@ module Charty
|
|
3
3
|
class DistributionPlotter < AbstractPlotter
|
4
4
|
def flat_structure
|
5
5
|
{
|
6
|
-
x:
|
6
|
+
x: :@values
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
def wide_structure
|
11
|
+
{
|
12
|
+
x: :@values,
|
13
|
+
color: :@columns
|
7
14
|
}
|
8
15
|
end
|
9
16
|
|
@@ -71,7 +78,6 @@ module Charty
|
|
71
78
|
return
|
72
79
|
end
|
73
80
|
|
74
|
-
# TODO: detect flat data
|
75
81
|
flat = data.is_a?(Charty::Vector)
|
76
82
|
if flat
|
77
83
|
@plot_data = {}
|
@@ -79,10 +85,10 @@ module Charty
|
|
79
85
|
|
80
86
|
[:x, :y].each do |var|
|
81
87
|
case self.flat_structure[var]
|
82
|
-
when
|
88
|
+
when :@index
|
83
89
|
@plot_data[var] = data.index.to_a
|
84
90
|
@variables[var] = data.index.name
|
85
|
-
when
|
91
|
+
when :@values
|
86
92
|
@plot_data[var] = data.to_a
|
87
93
|
@variables[var] = data.name
|
88
94
|
end
|
@@ -90,8 +96,32 @@ module Charty
|
|
90
96
|
|
91
97
|
@plot_data = Charty::Table.new(@plot_data)
|
92
98
|
else
|
93
|
-
|
94
|
-
|
99
|
+
numeric_columns = @data.column_names.select do |cn|
|
100
|
+
@data[cn].numeric?
|
101
|
+
end
|
102
|
+
wide_data = @data[numeric_columns]
|
103
|
+
|
104
|
+
melt_params = {var_name: :@columns, value_name: :@values }
|
105
|
+
if self.wide_structure.include?(:index)
|
106
|
+
melt_params[:id_vars] = :@index
|
107
|
+
end
|
108
|
+
|
109
|
+
@plot_data = wide_data.melt(**melt_params)
|
110
|
+
@variables = {}
|
111
|
+
self.wide_structure.each do |var, attr|
|
112
|
+
@plot_data[var] = @plot_data[attr]
|
113
|
+
|
114
|
+
@variables[var] = case attr
|
115
|
+
when :@columns
|
116
|
+
wide_data.columns.name
|
117
|
+
when :@index
|
118
|
+
wide_data.index.name
|
119
|
+
else
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
@plot_data = @plot_data[self.wide_structure.keys]
|
95
125
|
end
|
96
126
|
end
|
97
127
|
|
@@ -220,14 +220,16 @@ module Charty
|
|
220
220
|
end
|
221
221
|
|
222
222
|
private def annotate_axes(backend)
|
223
|
+
backend.set_title(self.title) if self.title
|
224
|
+
|
223
225
|
if univariate?
|
224
|
-
xlabel = self.variables[:x]
|
225
|
-
ylabel = self.variables[:y]
|
226
|
+
xlabel = self.x_label || self.variables[:x]
|
227
|
+
ylabel = self.y_label || self.variables[:y]
|
226
228
|
case self.univariate_variable
|
227
229
|
when :x
|
228
|
-
ylabel
|
230
|
+
ylabel ||= self.stat.to_s.capitalize
|
229
231
|
else
|
230
|
-
xlabel
|
232
|
+
xlabel ||= self.stat.to_s.capitalize
|
231
233
|
end
|
232
234
|
backend.set_ylabel(ylabel) if ylabel
|
233
235
|
backend.set_xlabel(xlabel) if xlabel
|
@@ -122,7 +122,7 @@ module Charty
|
|
122
122
|
|
123
123
|
include RandomSupport
|
124
124
|
|
125
|
-
attr_reader :sort, :err_style, :err_kws, :error_bar
|
125
|
+
attr_reader :sort, :err_style, :err_kws, :error_bar
|
126
126
|
|
127
127
|
def sort=(val)
|
128
128
|
@sort = check_boolean(val, :sort)
|
@@ -211,17 +211,21 @@ module Charty
|
|
211
211
|
[method, level]
|
212
212
|
end
|
213
213
|
|
214
|
+
attr_reader :x_scale
|
215
|
+
|
214
216
|
def x_scale=(val)
|
215
217
|
@x_scale = check_axis_scale(val, :x)
|
216
218
|
end
|
217
219
|
|
220
|
+
attr_reader :y_scale
|
221
|
+
|
218
222
|
def y_scale=(val)
|
219
223
|
@y_scale = check_axis_scale(val, :y)
|
220
224
|
end
|
221
225
|
|
222
226
|
private def check_axis_scale(val, axis)
|
223
227
|
case val
|
224
|
-
when :linear, "linear", :
|
228
|
+
when :linear, "linear", :log, "log"
|
225
229
|
val.to_sym
|
226
230
|
else
|
227
231
|
raise ArgumentError,
|
@@ -252,6 +256,15 @@ module Charty
|
|
252
256
|
sub_data = sub_data.sort_values(sort_cols)
|
253
257
|
end
|
254
258
|
|
259
|
+
# Perform axis scaling
|
260
|
+
if x_scale != :linear
|
261
|
+
sub_data[:x] = sub_data[:x].scale(x_scale)
|
262
|
+
end
|
263
|
+
if y_scale != :linear
|
264
|
+
sub_data[:y] = sub_data[:y].scale(x_scale)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Perform estimation and error calculation
|
255
268
|
unless estimator.nil?
|
256
269
|
if self.variables.include?(:units)
|
257
270
|
raise "`estimator` is must be nil when specifying `units`"
|
@@ -261,7 +274,22 @@ module Charty
|
|
261
274
|
sub_data = grouped.apply(agg_var, &aggregator.method(:aggregate)).reset_index
|
262
275
|
end
|
263
276
|
|
264
|
-
#
|
277
|
+
# Perform axis inverse scaling
|
278
|
+
if x_scale != :linear
|
279
|
+
sub_data.column_names.each do |cn|
|
280
|
+
if cn.start_with?("x")
|
281
|
+
sub_data[cn] = sub_data[cn].scale_inverse(x_scale)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
if y_scale != :linear
|
287
|
+
sub_data.column_names.each do |cn|
|
288
|
+
if cn.start_with?("y")
|
289
|
+
sub_data[cn] = sub_data[cn].scale_inverse(x_scale)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
265
293
|
|
266
294
|
unit_grouping = if self.variables.include?(:units)
|
267
295
|
sub_data.group_by(:units).each_group
|
@@ -290,10 +318,15 @@ module Charty
|
|
290
318
|
end
|
291
319
|
|
292
320
|
private def annotate_axes(backend)
|
293
|
-
|
294
|
-
|
321
|
+
backend.set_title(self.title) if self.title
|
322
|
+
|
323
|
+
xlabel = self.x_label || self.variables[:x]
|
324
|
+
ylabel = self.y_label || self.variables[:y]
|
295
325
|
backend.set_xlabel(xlabel) unless xlabel.nil?
|
296
326
|
backend.set_ylabel(ylabel) unless ylabel.nil?
|
327
|
+
|
328
|
+
backend.set_xscale(x_scale)
|
329
|
+
backend.set_yscale(y_scale)
|
297
330
|
end
|
298
331
|
end
|
299
332
|
end
|
@@ -70,8 +70,10 @@ module Charty
|
|
70
70
|
end
|
71
71
|
|
72
72
|
private def annotate_axes(backend)
|
73
|
-
|
74
|
-
|
73
|
+
backend.set_title(self.title) if self.title
|
74
|
+
|
75
|
+
xlabel = self.x_label || self.variables[:x]
|
76
|
+
ylabel = self.y_label || self.variables[:y]
|
75
77
|
backend.set_xlabel(xlabel) unless xlabel.nil?
|
76
78
|
backend.set_ylabel(ylabel) unless ylabel.nil?
|
77
79
|
end
|
data/lib/charty/table.rb
CHANGED
@@ -32,20 +32,7 @@ module Charty
|
|
32
32
|
def_delegators :adapter, :columns, :columns=
|
33
33
|
def_delegators :adapter, :index, :index=
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
def column?(name)
|
38
|
-
return true if column_names.include?(name)
|
39
|
-
|
40
|
-
case name
|
41
|
-
when String
|
42
|
-
column_names.include?(name.to_sym)
|
43
|
-
when Symbol
|
44
|
-
column_names.include?(name.to_s)
|
45
|
-
else
|
46
|
-
false
|
47
|
-
end
|
48
|
-
end
|
35
|
+
def_delegators :@adapter, :column_names, :column?
|
49
36
|
|
50
37
|
def_delegator :@adapter, :data, :raw_data
|
51
38
|
|
@@ -65,17 +52,35 @@ module Charty
|
|
65
52
|
end
|
66
53
|
|
67
54
|
def [](key)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
55
|
+
case key
|
56
|
+
when Array
|
57
|
+
@adapter[nil, key]
|
58
|
+
else
|
59
|
+
key = case key
|
60
|
+
when Symbol
|
61
|
+
key
|
62
|
+
else
|
63
|
+
String.try_convert(key).to_sym
|
64
|
+
end
|
65
|
+
if @column_cache.key?(key)
|
66
|
+
@column_cache[key]
|
67
|
+
else
|
68
|
+
@column_cache[key] = @adapter[nil, key]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def []=(key, values)
|
74
|
+
case key
|
75
|
+
when Array
|
76
|
+
raise ArgumentError,
|
77
|
+
"Substituting multiple keys is not supported"
|
78
|
+
when Symbol
|
79
|
+
# do nothing
|
76
80
|
else
|
77
|
-
|
81
|
+
key = key.to_str.to_sym
|
78
82
|
end
|
83
|
+
@adapter[key] = values
|
79
84
|
end
|
80
85
|
|
81
86
|
def group_by(grouper, sort: true, drop_na: true)
|
@@ -123,6 +128,8 @@ module Charty
|
|
123
128
|
|
124
129
|
def_delegator :adapter, :reset_index
|
125
130
|
|
131
|
+
def_delegator :adapter, :melt
|
132
|
+
|
126
133
|
class GroupByBase
|
127
134
|
end
|
128
135
|
|
@@ -16,6 +16,19 @@ module Charty
|
|
16
16
|
columns.to_a
|
17
17
|
end
|
18
18
|
|
19
|
+
def column?(name)
|
20
|
+
return true if column_names.include?(name)
|
21
|
+
|
22
|
+
case name
|
23
|
+
when String
|
24
|
+
column_names.include?(name.to_sym)
|
25
|
+
when Symbol
|
26
|
+
column_names.include?(name.to_s)
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
19
32
|
attr_reader :index
|
20
33
|
|
21
34
|
def index=(values)
|
@@ -126,6 +139,81 @@ module Charty
|
|
126
139
|
)
|
127
140
|
end
|
128
141
|
|
142
|
+
def melt(id_vars: nil, value_vars: nil, var_name: nil, value_name: :value)
|
143
|
+
if column?(value_name)
|
144
|
+
raise ArgumentError,
|
145
|
+
"The value of `value_name` must not be matched to the existing column names."
|
146
|
+
end
|
147
|
+
|
148
|
+
case value_name
|
149
|
+
when Symbol
|
150
|
+
# do nothing
|
151
|
+
else
|
152
|
+
value_name = value.to_str.to_sym
|
153
|
+
end
|
154
|
+
|
155
|
+
id_vars = check_melt_vars(id_vars, :id_vars)
|
156
|
+
value_vars = check_melt_vars(value_vars, :value_vars) { self.column_names }
|
157
|
+
value_vars -= id_vars
|
158
|
+
|
159
|
+
case var_name
|
160
|
+
when nil
|
161
|
+
var_name = self.columns.name
|
162
|
+
var_name = :variable if var_name.nil?
|
163
|
+
when Symbol
|
164
|
+
# do nothing
|
165
|
+
else
|
166
|
+
var_name = var_name.to_str
|
167
|
+
end
|
168
|
+
var_name = var_name.to_sym
|
169
|
+
|
170
|
+
n_batch_rows = self.length
|
171
|
+
n_target_columns = value_vars.length
|
172
|
+
melted_data = id_vars.map { |cn|
|
173
|
+
id_values = self[nil, cn].to_a
|
174
|
+
[cn.to_sym, id_values * n_target_columns]
|
175
|
+
}.to_h
|
176
|
+
|
177
|
+
melted_data[var_name] = value_vars.map { |cn| Array.new(n_batch_rows, cn) }.flatten
|
178
|
+
|
179
|
+
melted_data[value_name] = value_vars.map { |cn| self[nil, cn].to_a }.flatten
|
180
|
+
|
181
|
+
Charty::Table.new(melted_data)
|
182
|
+
end
|
183
|
+
|
184
|
+
private def check_melt_vars(val, name)
|
185
|
+
if val.nil?
|
186
|
+
val = if block_given?
|
187
|
+
yield
|
188
|
+
else
|
189
|
+
[]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
case val
|
193
|
+
when nil
|
194
|
+
nil
|
195
|
+
when Array
|
196
|
+
missing = val.reject {|cn| self.column?(cn) }
|
197
|
+
if missing.empty?
|
198
|
+
val.map do |v|
|
199
|
+
case v
|
200
|
+
when Symbol
|
201
|
+
v.to_s
|
202
|
+
else
|
203
|
+
v.to_str
|
204
|
+
end
|
205
|
+
end
|
206
|
+
else
|
207
|
+
raise ArgumentError,
|
208
|
+
"Missing column names in `#{name}` (%s)" % missing.join(", ")
|
209
|
+
end
|
210
|
+
when Symbol
|
211
|
+
[val.to_s]
|
212
|
+
else
|
213
|
+
[val.to_str]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
129
217
|
private def check_na_position(val)
|
130
218
|
case val
|
131
219
|
when :first, "first"
|
@@ -57,12 +57,52 @@ module Charty
|
|
57
57
|
column_data = if @data.has_vector?(column)
|
58
58
|
@data[column]
|
59
59
|
else
|
60
|
-
|
60
|
+
case column
|
61
|
+
when String
|
62
|
+
@data[column.to_sym]
|
63
|
+
else
|
64
|
+
@data[column.to_s]
|
65
|
+
end
|
61
66
|
end
|
62
67
|
Vector.new(column_data)
|
63
68
|
end
|
64
69
|
end
|
65
70
|
|
71
|
+
def []=(key, values)
|
72
|
+
case key
|
73
|
+
when Symbol
|
74
|
+
sym_key = key
|
75
|
+
str_key = key.to_s
|
76
|
+
else
|
77
|
+
str_key = key.to_str
|
78
|
+
sym_key = str_key.to_sym
|
79
|
+
end
|
80
|
+
case
|
81
|
+
when @data.has_vector?(sym_key)
|
82
|
+
key = sym_key
|
83
|
+
when @data.has_vector?(str_key)
|
84
|
+
key = str_key
|
85
|
+
end
|
86
|
+
|
87
|
+
case values
|
88
|
+
when Charty::Vector
|
89
|
+
case values.adapter
|
90
|
+
when Charty::VectorAdapters::DaruVectorAdapter
|
91
|
+
@data[key] = values.adapter.data
|
92
|
+
else
|
93
|
+
@data[key] = values.to_a
|
94
|
+
end
|
95
|
+
else
|
96
|
+
orig_values = values
|
97
|
+
values = Array.try_convert(values)
|
98
|
+
if values.nil?
|
99
|
+
raise ArgumentError, "`values` must be convertible to Array"
|
100
|
+
end
|
101
|
+
@data[key] = values
|
102
|
+
end
|
103
|
+
return values
|
104
|
+
end
|
105
|
+
|
66
106
|
private def check_type(type, data, name)
|
67
107
|
return data if data.is_a?(type)
|
68
108
|
raise TypeError, "#{name} must be a #{type}"
|
@@ -181,6 +181,11 @@ module Charty
|
|
181
181
|
@data[column][row]
|
182
182
|
else
|
183
183
|
case column
|
184
|
+
when Array
|
185
|
+
slice_data = column.map { |cn|
|
186
|
+
[cn, self[nil, cn]]
|
187
|
+
}.to_h
|
188
|
+
return Charty::Table.new(slice_data, index: self.index)
|
184
189
|
when Symbol
|
185
190
|
sym_key = column
|
186
191
|
str_key = column.to_s
|
@@ -194,10 +199,58 @@ module Charty
|
|
194
199
|
else
|
195
200
|
@data[str_key]
|
196
201
|
end
|
197
|
-
|
202
|
+
# FIXME: Here column_data need to be dupped to
|
203
|
+
# prevent to overwrite the name of Pandas::Series
|
204
|
+
Vector.new(column_data.dup, index: index, name: column)
|
198
205
|
end
|
199
206
|
end
|
200
207
|
|
208
|
+
def []=(key, values)
|
209
|
+
case key
|
210
|
+
when Symbol
|
211
|
+
str_key = key.to_s
|
212
|
+
sym_key = key
|
213
|
+
else
|
214
|
+
str_key = key.to_str
|
215
|
+
sym_key = str_key.to_sym
|
216
|
+
end
|
217
|
+
|
218
|
+
orig_values = values
|
219
|
+
case values
|
220
|
+
when Charty::Vector
|
221
|
+
values = values.data
|
222
|
+
else
|
223
|
+
values = Array.try_convert(values)
|
224
|
+
end
|
225
|
+
if values.nil?
|
226
|
+
raise ArgumentError,
|
227
|
+
"`values` must be convertible to Array"
|
228
|
+
end
|
229
|
+
|
230
|
+
if values.length != self.length
|
231
|
+
raise ArgumentError,
|
232
|
+
"`values` length does not match the length of the table"
|
233
|
+
end
|
234
|
+
|
235
|
+
if @data.key?(sym_key)
|
236
|
+
@data[sym_key] = values
|
237
|
+
elsif @data.key?(str_key)
|
238
|
+
@data[str_key] = values
|
239
|
+
elsif key == sym_key
|
240
|
+
@data[sym_key] = values
|
241
|
+
new_column = sym_key
|
242
|
+
else
|
243
|
+
@data[str_key] = values
|
244
|
+
new_column = sym_key
|
245
|
+
end
|
246
|
+
|
247
|
+
if new_column
|
248
|
+
self.columns = Index.new([*self.columns, new_column])
|
249
|
+
end
|
250
|
+
|
251
|
+
values
|
252
|
+
end
|
253
|
+
|
201
254
|
def each
|
202
255
|
i, n = 0, shape[0]
|
203
256
|
while i < n
|
@@ -42,6 +42,10 @@ module Charty
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
def column?(name)
|
46
|
+
data.__contains__(name)
|
47
|
+
end
|
48
|
+
|
45
49
|
def index
|
46
50
|
PandasIndex.new(data.index)
|
47
51
|
end
|
@@ -76,8 +80,33 @@ module Charty
|
|
76
80
|
if row
|
77
81
|
@data[column][row]
|
78
82
|
else
|
79
|
-
|
83
|
+
case column
|
84
|
+
when Array
|
85
|
+
Table.new(@data[column])
|
86
|
+
else
|
87
|
+
Vector.new(@data[column])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def []=(key, values)
|
93
|
+
case values
|
94
|
+
when Charty::Vector
|
95
|
+
case values.adapter
|
96
|
+
when Charty::VectorAdapters::PandasSeriesAdapter
|
97
|
+
@data[key] = values.adapter.data
|
98
|
+
else
|
99
|
+
@data[key] = values.to_a
|
100
|
+
end
|
101
|
+
else
|
102
|
+
orig_values = values
|
103
|
+
values = Array.try_convert(values)
|
104
|
+
if values.nil?
|
105
|
+
raise ArgumentError, "`values` must be convertible to Array"
|
106
|
+
end
|
107
|
+
@data[key] = values
|
80
108
|
end
|
109
|
+
return values
|
81
110
|
end
|
82
111
|
|
83
112
|
def drop_na
|
@@ -101,6 +130,15 @@ module Charty
|
|
101
130
|
Charty::Table.new(data.reset_index)
|
102
131
|
end
|
103
132
|
|
133
|
+
def melt(id_vars: nil, value_vars: nil, var_name: nil, value_name: :value)
|
134
|
+
id_vars = check_melt_vars(id_vars, :id_vars) { nil }
|
135
|
+
value_vars = check_melt_vars(value_vars, :value_vars) { nil }
|
136
|
+
|
137
|
+
Charty::Table.new(data.melt(id_vars: id_vars, value_vars: value_vars,
|
138
|
+
var_name: var_name, value_name: value_name,
|
139
|
+
ignore_index: true))
|
140
|
+
end
|
141
|
+
|
104
142
|
class GroupBy < Charty::Table::GroupByBase
|
105
143
|
def initialize(groupby)
|
106
144
|
@groupby = groupby
|
@@ -116,6 +154,7 @@ module Charty
|
|
116
154
|
each_group_key.to_a
|
117
155
|
end
|
118
156
|
|
157
|
+
# TODO: test
|
119
158
|
def each_group_key
|
120
159
|
return enum_for(__method__) unless block_given?
|
121
160
|
|
@@ -146,6 +185,15 @@ module Charty
|
|
146
185
|
end
|
147
186
|
end
|
148
187
|
|
188
|
+
# TODO: test
|
189
|
+
def each_group
|
190
|
+
return enum_for(__method__) unless block_given?
|
191
|
+
|
192
|
+
each_group_key do |key|
|
193
|
+
yield(Array(key), self[key])
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
149
197
|
def apply(*args, &block)
|
150
198
|
res = @groupby.apply(->(data) {
|
151
199
|
res = block.call(Charty::Table.new(data), *args)
|
data/lib/charty/vector.rb
CHANGED
@@ -51,6 +51,32 @@ module Charty
|
|
51
51
|
|
52
52
|
def_delegators :adapter, :mean, :stdev
|
53
53
|
|
54
|
+
def_delegators :adapter, :scale, :scale_inverse
|
55
|
+
|
56
|
+
def scale(method)
|
57
|
+
case method
|
58
|
+
when :linear
|
59
|
+
self
|
60
|
+
when :log
|
61
|
+
adapter.log_scale(method)
|
62
|
+
else
|
63
|
+
raise ArgumentError,
|
64
|
+
"Invalid scaling method: %p" % method
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def scale_inverse(method)
|
69
|
+
case method
|
70
|
+
when :linear
|
71
|
+
self
|
72
|
+
when :log
|
73
|
+
adapter.inverse_log_scale(method)
|
74
|
+
else
|
75
|
+
raise ArgumentError,
|
76
|
+
"Invalid scaling method: %p" % method
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
54
80
|
# TODO: write test
|
55
81
|
def categorical_order(order=nil)
|
56
82
|
if order.nil?
|
@@ -59,7 +85,9 @@ module Charty
|
|
59
85
|
order = categories
|
60
86
|
else
|
61
87
|
order = unique_values.compact
|
62
|
-
|
88
|
+
if numeric?
|
89
|
+
order.sort_by! {|x| Util.missing?(x) ? Float::INFINITY : x }
|
90
|
+
end
|
63
91
|
end
|
64
92
|
order.compact!
|
65
93
|
end
|
@@ -99,6 +99,22 @@ module Charty
|
|
99
99
|
def stdev(population: false)
|
100
100
|
Statistics.stdev(data, population: population)
|
101
101
|
end
|
102
|
+
|
103
|
+
def log_scale(method)
|
104
|
+
Charty::Vector.new(
|
105
|
+
self.map {|x| Math.log10(x) },
|
106
|
+
index: index,
|
107
|
+
name: name
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
def inverse_log_scale(method)
|
112
|
+
Charty::Vector.new(
|
113
|
+
self.map {|x| 10.0 ** x },
|
114
|
+
index: index,
|
115
|
+
name: name
|
116
|
+
)
|
117
|
+
end
|
102
118
|
end
|
103
119
|
|
104
120
|
module NameSupport
|
@@ -152,7 +152,8 @@ module Charty
|
|
152
152
|
group_keys = grouper.unique.to_a
|
153
153
|
groups = data.groupby(grouper)
|
154
154
|
group_keys.map {|g|
|
155
|
-
|
155
|
+
g_vals = groups.get_group(g) rescue []
|
156
|
+
[g, Charty::Vector.new(g_vals)]
|
156
157
|
}.to_h
|
157
158
|
when Charty::Vector
|
158
159
|
case grouper.adapter
|
@@ -194,6 +195,14 @@ module Charty
|
|
194
195
|
q = q.map {|x| x / 100.0 }
|
195
196
|
data.quantile(q)
|
196
197
|
end
|
198
|
+
|
199
|
+
def log_scale(method)
|
200
|
+
Charty::Vector.new(Numpy.log10(data))
|
201
|
+
end
|
202
|
+
|
203
|
+
def inverse_log_scale(method)
|
204
|
+
Charty::Vector.new(Numpy.power(10, data))
|
205
|
+
end
|
197
206
|
end
|
198
207
|
end
|
199
208
|
end
|
data/lib/charty/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: charty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- youchan
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-08-18 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: red-colors
|
@@ -246,6 +246,8 @@ files:
|
|
246
246
|
- charty.gemspec
|
247
247
|
- examples/Gemfile
|
248
248
|
- examples/active_record.ipynb
|
249
|
+
- examples/bar_plot.rb
|
250
|
+
- examples/box_plot.rb
|
249
251
|
- examples/daru.ipynb
|
250
252
|
- examples/iris_dataset.ipynb
|
251
253
|
- examples/nmatrix.ipynb
|
@@ -284,6 +286,7 @@ files:
|
|
284
286
|
- examples/sample_images/subplot_pyplot.png
|
285
287
|
- examples/sample_pyplot.ipynb
|
286
288
|
- examples/sample_rubyplot.ipynb
|
289
|
+
- examples/scatter_plot.rb
|
287
290
|
- images/design_concept.png
|
288
291
|
- images/penguins_body_mass_g_flipper_length_mm_scatter_plot.png
|
289
292
|
- images/penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png
|
@@ -369,7 +372,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
369
372
|
- !ruby/object:Gem::Version
|
370
373
|
version: '0'
|
371
374
|
requirements: []
|
372
|
-
rubygems_version: 3.2.
|
375
|
+
rubygems_version: 3.2.23
|
373
376
|
signing_key:
|
374
377
|
specification_version: 4
|
375
378
|
summary: Visualizing your data in a simple way.
|