charty 0.2.7 → 0.2.11
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/charty.gemspec +1 -0
- 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 +53 -22
- data/lib/charty/backends/plotly_helpers/notebook_renderer.rb +4 -1
- data/lib/charty/backends/pyplot.rb +73 -0
- data/lib/charty/backends/unicode_plot.rb +16 -11
- data/lib/charty/index.rb +9 -0
- data/lib/charty/plot_methods.rb +46 -10
- 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 +44 -7
- data/lib/charty/plotters/histogram_plotter.rb +97 -35
- data/lib/charty/plotters/line_plotter.rb +38 -5
- data/lib/charty/plotters/scatter_plotter.rb +4 -2
- data/lib/charty/statistics.rb +2 -2
- data/lib/charty/table.rb +30 -23
- data/lib/charty/table_adapters/arrow_adapter.rb +53 -0
- 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 +58 -10
- data/lib/charty/table_adapters/pandas_adapter.rb +49 -1
- data/lib/charty/table_adapters.rb +1 -0
- data/lib/charty/vector.rb +30 -2
- data/lib/charty/vector_adapters/array_adapter.rb +1 -1
- data/lib/charty/vector_adapters/arrow_adapter.rb +156 -0
- data/lib/charty/vector_adapters/daru_adapter.rb +3 -6
- data/lib/charty/vector_adapters/narray_adapter.rb +10 -1
- data/lib/charty/vector_adapters/nmatrix_adapter.rb +1 -5
- data/lib/charty/vector_adapters/numpy_adapter.rb +4 -0
- data/lib/charty/vector_adapters/pandas_adapter.rb +10 -1
- data/lib/charty/vector_adapters/vector_adapter.rb +62 -0
- data/lib/charty/vector_adapters.rb +22 -0
- data/lib/charty/version.rb +1 -1
- metadata +23 -3
@@ -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/statistics.rb
CHANGED
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
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Charty
|
2
|
+
module TableAdapters
|
3
|
+
class ArrowAdapter < BaseAdapter
|
4
|
+
TableAdapters.register(:arrow, self)
|
5
|
+
|
6
|
+
def self.supported?(data)
|
7
|
+
defined?(Arrow::Table) && data.is_a?(Arrow::Table)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data)
|
11
|
+
@data = data
|
12
|
+
@column_names = @data.columns.map(&:name)
|
13
|
+
self.columns = Index.new(@column_names)
|
14
|
+
self.index = RangeIndex.new(0 ... length)
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :data
|
18
|
+
|
19
|
+
def length
|
20
|
+
@data.n_rows
|
21
|
+
end
|
22
|
+
|
23
|
+
def column_length
|
24
|
+
@column_names.length
|
25
|
+
end
|
26
|
+
|
27
|
+
def compare_data_equality(other)
|
28
|
+
case other
|
29
|
+
when ArrowAdapter
|
30
|
+
data == other.data
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def [](row, column)
|
37
|
+
if row
|
38
|
+
@data[column][row]
|
39
|
+
else
|
40
|
+
case column
|
41
|
+
when Array
|
42
|
+
Table.new(@data.select_columns(*column))
|
43
|
+
else
|
44
|
+
column_data = @data[column]
|
45
|
+
Vector.new(column_data.data.combine,
|
46
|
+
index: index,
|
47
|
+
name: column_data.name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -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}"
|
@@ -20,6 +20,8 @@ module Charty
|
|
20
20
|
end
|
21
21
|
when Hash
|
22
22
|
true
|
23
|
+
when ->(x) { defined?(CSV::Table) && x.is_a?(CSV::Table) }
|
24
|
+
true
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
@@ -73,12 +75,17 @@ module Charty
|
|
73
75
|
arrays[i] << record[key]
|
74
76
|
end
|
75
77
|
end
|
78
|
+
when Vector
|
79
|
+
arrays = data
|
76
80
|
when self.class.method(:array?)
|
77
81
|
unsupported_data_format unless data.all?(&self.class.method(:array?))
|
78
82
|
arrays = data.map(&:to_a).transpose
|
79
83
|
else
|
80
84
|
unsupported_data_format
|
81
85
|
end
|
86
|
+
when ->(x) { defined?(CSV::Table) && x.is_a?(CSV::Table) }
|
87
|
+
columns ||= data.headers
|
88
|
+
arrays = data.headers.map {|x| data[x] }
|
82
89
|
else
|
83
90
|
unsupported_data_format
|
84
91
|
end
|
@@ -116,20 +123,15 @@ module Charty
|
|
116
123
|
index = union_indexes(*indexes)
|
117
124
|
|
118
125
|
arrays = arrays.map do |array|
|
119
|
-
|
120
|
-
when Charty::Vector
|
121
|
-
array.data
|
122
|
-
when Hash
|
123
|
-
raise NotImplementedError
|
124
|
-
when self.class.method(:array?)
|
125
|
-
array
|
126
|
-
else
|
127
|
-
Array.try_convert(array)
|
128
|
-
end
|
126
|
+
Vector.try_convert(array)
|
129
127
|
end
|
130
128
|
|
131
129
|
columns = generate_column_names(arrays.length, columns)
|
132
130
|
|
131
|
+
arrays.zip(columns) do |array, column|
|
132
|
+
array.name = column.to_sym if array.name.to_s != column
|
133
|
+
end
|
134
|
+
|
133
135
|
return arrays, columns, index
|
134
136
|
end
|
135
137
|
|
@@ -176,6 +178,11 @@ module Charty
|
|
176
178
|
@data[column][row]
|
177
179
|
else
|
178
180
|
case column
|
181
|
+
when Array
|
182
|
+
slice_data = column.map { |cn|
|
183
|
+
[cn, self[nil, cn]]
|
184
|
+
}.to_h
|
185
|
+
return Charty::Table.new(slice_data, index: self.index)
|
179
186
|
when Symbol
|
180
187
|
sym_key = column
|
181
188
|
str_key = column.to_s
|
@@ -193,6 +200,47 @@ module Charty
|
|
193
200
|
end
|
194
201
|
end
|
195
202
|
|
203
|
+
def []=(key, values)
|
204
|
+
case key
|
205
|
+
when Symbol
|
206
|
+
str_key = key.to_s
|
207
|
+
sym_key = key
|
208
|
+
else
|
209
|
+
str_key = key.to_str
|
210
|
+
sym_key = str_key.to_sym
|
211
|
+
end
|
212
|
+
|
213
|
+
orig_values = values
|
214
|
+
values = Vector.try_convert(values)
|
215
|
+
if values.nil?
|
216
|
+
raise ArgumentError,
|
217
|
+
"`values` must be convertible to Charty::Vector"
|
218
|
+
end
|
219
|
+
|
220
|
+
if values.length != self.length
|
221
|
+
raise ArgumentError,
|
222
|
+
"`values` length does not match the length of the table"
|
223
|
+
end
|
224
|
+
|
225
|
+
if @data.key?(sym_key)
|
226
|
+
@data[sym_key] = values
|
227
|
+
elsif @data.key?(str_key)
|
228
|
+
@data[str_key] = values
|
229
|
+
elsif key == sym_key
|
230
|
+
@data[sym_key] = values
|
231
|
+
new_column = sym_key
|
232
|
+
else
|
233
|
+
@data[str_key] = values
|
234
|
+
new_column = sym_key
|
235
|
+
end
|
236
|
+
|
237
|
+
if new_column
|
238
|
+
self.columns = Index.new([*self.columns, new_column])
|
239
|
+
end
|
240
|
+
|
241
|
+
values
|
242
|
+
end
|
243
|
+
|
196
244
|
def each
|
197
245
|
i, n = 0, shape[0]
|
198
246
|
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)
|