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