charty 0.2.3 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +56 -23
  3. data/.github/workflows/nmatrix.yml +67 -0
  4. data/.github/workflows/pycall.yml +86 -0
  5. data/Gemfile +18 -0
  6. data/README.md +172 -4
  7. data/Rakefile +4 -5
  8. data/charty.gemspec +10 -6
  9. data/examples/sample_images/hist_gruff.png +0 -0
  10. data/images/penguins_body_mass_g_flipper_length_mm_scatter_plot.png +0 -0
  11. data/images/penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png +0 -0
  12. data/images/penguins_body_mass_g_flipper_length_mm_species_sex_scatter_plot.png +0 -0
  13. data/images/penguins_species_body_mass_g_bar_plot_h.png +0 -0
  14. data/images/penguins_species_body_mass_g_bar_plot_v.png +0 -0
  15. data/images/penguins_species_body_mass_g_box_plot_h.png +0 -0
  16. data/images/penguins_species_body_mass_g_box_plot_v.png +0 -0
  17. data/images/penguins_species_body_mass_g_sex_bar_plot_v.png +0 -0
  18. data/images/penguins_species_body_mass_g_sex_box_plot_v.png +0 -0
  19. data/lib/charty.rb +8 -1
  20. data/lib/charty/backends/bokeh.rb +2 -2
  21. data/lib/charty/backends/google_charts.rb +1 -1
  22. data/lib/charty/backends/gruff.rb +14 -3
  23. data/lib/charty/backends/plotly.rb +731 -32
  24. data/lib/charty/backends/plotly_helpers/html_renderer.rb +203 -0
  25. data/lib/charty/backends/plotly_helpers/notebook_renderer.rb +87 -0
  26. data/lib/charty/backends/plotly_helpers/plotly_renderer.rb +121 -0
  27. data/lib/charty/backends/pyplot.rb +514 -66
  28. data/lib/charty/backends/rubyplot.rb +1 -1
  29. data/lib/charty/cache_dir.rb +27 -0
  30. data/lib/charty/dash_pattern_generator.rb +57 -0
  31. data/lib/charty/index.rb +213 -0
  32. data/lib/charty/iruby_helper.rb +18 -0
  33. data/lib/charty/linspace.rb +1 -1
  34. data/lib/charty/plot_methods.rb +283 -8
  35. data/lib/charty/plotter.rb +2 -2
  36. data/lib/charty/plotters.rb +11 -0
  37. data/lib/charty/plotters/abstract_plotter.rb +186 -16
  38. data/lib/charty/plotters/bar_plotter.rb +189 -7
  39. data/lib/charty/plotters/box_plotter.rb +64 -11
  40. data/lib/charty/plotters/categorical_plotter.rb +272 -40
  41. data/lib/charty/plotters/count_plotter.rb +7 -0
  42. data/lib/charty/plotters/distribution_plotter.rb +143 -0
  43. data/lib/charty/plotters/estimation_support.rb +84 -0
  44. data/lib/charty/plotters/histogram_plotter.rb +186 -0
  45. data/lib/charty/plotters/line_plotter.rb +300 -0
  46. data/lib/charty/plotters/random_support.rb +25 -0
  47. data/lib/charty/plotters/relational_plotter.rb +635 -0
  48. data/lib/charty/plotters/scatter_plotter.rb +80 -0
  49. data/lib/charty/plotters/vector_plotter.rb +6 -0
  50. data/lib/charty/statistics.rb +96 -2
  51. data/lib/charty/table.rb +160 -15
  52. data/lib/charty/table_adapters.rb +2 -0
  53. data/lib/charty/table_adapters/active_record_adapter.rb +17 -9
  54. data/lib/charty/table_adapters/base_adapter.rb +166 -0
  55. data/lib/charty/table_adapters/daru_adapter.rb +39 -3
  56. data/lib/charty/table_adapters/datasets_adapter.rb +13 -2
  57. data/lib/charty/table_adapters/hash_adapter.rb +141 -16
  58. data/lib/charty/table_adapters/narray_adapter.rb +25 -6
  59. data/lib/charty/table_adapters/nmatrix_adapter.rb +15 -5
  60. data/lib/charty/table_adapters/pandas_adapter.rb +163 -0
  61. data/lib/charty/util.rb +28 -0
  62. data/lib/charty/vector.rb +69 -0
  63. data/lib/charty/vector_adapters.rb +187 -0
  64. data/lib/charty/vector_adapters/array_adapter.rb +101 -0
  65. data/lib/charty/vector_adapters/daru_adapter.rb +163 -0
  66. data/lib/charty/vector_adapters/narray_adapter.rb +182 -0
  67. data/lib/charty/vector_adapters/nmatrix_adapter.rb +37 -0
  68. data/lib/charty/vector_adapters/numpy_adapter.rb +168 -0
  69. data/lib/charty/vector_adapters/pandas_adapter.rb +199 -0
  70. data/lib/charty/version.rb +1 -1
  71. metadata +92 -25
@@ -0,0 +1,101 @@
1
+ require "date"
2
+
3
+ module Charty
4
+ module VectorAdapters
5
+ class ArrayAdapter < BaseAdapter
6
+ VectorAdapters.register(:array, self)
7
+
8
+ extend Forwardable
9
+ include Enumerable
10
+
11
+ def self.supported?(data)
12
+ case data
13
+ when Array
14
+ case data[0]
15
+ when Numeric, String, Time, Date, DateTime, true, false, nil
16
+ true
17
+ else
18
+ false
19
+ end
20
+ else
21
+ false
22
+ end
23
+ end
24
+
25
+ def initialize(data, index: nil)
26
+ @data = check_data(data)
27
+ self.index = index || RangeIndex.new(0 ... length)
28
+ end
29
+
30
+ include NameSupport
31
+ include IndexSupport
32
+
33
+ def_delegators :data, :values_at
34
+
35
+ def where(mask)
36
+ masked_data, masked_index = where_in_array(mask)
37
+ Charty::Vector.new(masked_data, index: masked_index, name: name)
38
+ end
39
+
40
+ def first_nonnil
41
+ data.drop_while(&:nil?).first
42
+ end
43
+
44
+ def boolean?
45
+ case first_nonnil
46
+ when true, false
47
+ true
48
+ else
49
+ false
50
+ end
51
+ end
52
+
53
+ def numeric?
54
+ case first_nonnil
55
+ when Numeric
56
+ true
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ def categorical?
63
+ false
64
+ end
65
+
66
+ def categories
67
+ nil
68
+ end
69
+
70
+ def_delegator :data, :uniq, :unique_values
71
+
72
+ def group_by(grouper)
73
+ groups = data.each_index.group_by {|i| grouper[i] }
74
+ groups.map { |g, vals|
75
+ vals.collect! {|i| self[i] }
76
+ [g, Charty::Vector.new(vals)]
77
+ }.to_h
78
+ end
79
+
80
+ def drop_na
81
+ if numeric?
82
+ Charty::Vector.new(data.reject { |x| Util.missing?(x) })
83
+ else
84
+ Charty::Vector.new(data.compact)
85
+ end
86
+ end
87
+
88
+ def eq(val)
89
+ Charty::Vector.new(data.map {|x| x == val },
90
+ index: index,
91
+ name: name)
92
+ end
93
+
94
+ def notnull
95
+ Charty::Vector.new(data.map {|x| ! Util.missing?(x) },
96
+ index: index,
97
+ name: name)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,163 @@
1
+ module Charty
2
+ module VectorAdapters
3
+ class DaruVectorAdapter < BaseAdapter
4
+ VectorAdapters.register(:daru_vector, self)
5
+
6
+ def self.supported?(data)
7
+ defined?(Daru::Vector) && data.is_a?(Daru::Vector)
8
+ end
9
+
10
+ def initialize(data)
11
+ @data = check_data(data)
12
+ end
13
+
14
+ def_delegator :data, :size, :length
15
+
16
+ def index
17
+ DaruIndex.new(data.index)
18
+ end
19
+
20
+ def index=(new_index)
21
+ case new_index
22
+ when DaruIndex
23
+ data.index = new_index.values
24
+ when Index
25
+ data.index = new_index.to_a
26
+ else
27
+ data.index = new_index
28
+ end
29
+ end
30
+
31
+ def_delegators :data, :name, :name=
32
+
33
+ def compare_data_equality(other)
34
+ case other
35
+ when DaruVectorAdapter
36
+ data == other.data
37
+ when ArrayAdapter
38
+ data.to_a == other.data
39
+ when NArrayAdapter, NMatrixAdapter, NumpyAdapter, PandasSeriesAdapter
40
+ other.compare_data_equality(self)
41
+ else
42
+ data == other.data.to_a
43
+ end
44
+ end
45
+
46
+ def [](key)
47
+ case key
48
+ when Charty::Vector
49
+ where(key)
50
+ else
51
+ data[key]
52
+ end
53
+ end
54
+
55
+ def_delegators :data, :[]=, :to_a
56
+
57
+ def values_at(*indices)
58
+ indices.map {|i| data.at(i) }
59
+ end
60
+
61
+ def where(mask)
62
+ masked_data, masked_index = where_in_array(mask)
63
+ Charty::Vector.new(Daru::Vector.new(masked_data, index: masked_index), name: name)
64
+ end
65
+
66
+ def where_in_array(mask)
67
+ mask = check_mask_vector(mask)
68
+ masked_data = []
69
+ masked_index = []
70
+ mask.each_with_index do |f, i|
71
+ case f
72
+ when true, 1
73
+ masked_data << data[i]
74
+ masked_index << data.index.key(i)
75
+ end
76
+ end
77
+ return masked_data, masked_index
78
+ end
79
+
80
+ def first_nonnil
81
+ data.drop_while(&:nil?).first
82
+ end
83
+
84
+ def boolean?
85
+ case
86
+ when numeric?, categorical?
87
+ false
88
+ else
89
+ case first_nonnil
90
+ when true, false
91
+ true
92
+ else
93
+ false
94
+ end
95
+ end
96
+ end
97
+
98
+ def_delegators :data, :numeric?
99
+ def_delegator :data, :category?, :categorical?
100
+
101
+ def categories
102
+ data.categories.compact if categorical?
103
+ end
104
+
105
+ def unique_values
106
+ data.uniq.to_a
107
+ end
108
+
109
+ def group_by(grouper)
110
+ case grouper
111
+ when Daru::Vector
112
+ if grouper.category?
113
+ # TODO: A categorical Daru::Vector cannot perform group_by well
114
+ grouper = Daru::Vector.new(grouper.to_a)
115
+ end
116
+ groups = grouper.group_by.groups
117
+ groups.map { |g, indices|
118
+ [g.first, Charty::Vector.new(data[*indices])]
119
+ }.to_h
120
+ when Charty::Vector
121
+ case grouper.data
122
+ when Daru::Vector
123
+ return group_by(grouper.data)
124
+ else
125
+ return group_by(Daru::Vector.new(grouper.to_a))
126
+ end
127
+ else
128
+ return group_by(Charty::Vector.new(grouper))
129
+ end
130
+ end
131
+
132
+ def drop_na
133
+ values = data.reject {|x| Util.missing?(x) }
134
+ Charty::Vector.new(Daru::Vector.new(values))
135
+ end
136
+
137
+ def eq(val)
138
+ Charty::Vector.new(data.eq(val).to_a,
139
+ index: data.index.to_a,
140
+ name: name)
141
+ end
142
+
143
+ def notnull
144
+ notnull_data = data.map {|x| ! Util.missing?(x) }
145
+ Charty::Vector.new(notnull_data, index: data.index.to_a, name: name)
146
+ end
147
+
148
+ def_delegator :data, :mean
149
+
150
+ def stdev(population: false)
151
+ if population
152
+ data.standard_deviation_sample
153
+ else
154
+ data.standard_deviation_population
155
+ end
156
+ end
157
+
158
+ def percentile(q)
159
+ data.linear_percentile(q)
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,182 @@
1
+ module Charty
2
+ module VectorAdapters
3
+ class NArrayAdapter < BaseAdapter
4
+ VectorAdapters.register(:narray, self)
5
+
6
+ extend Forwardable
7
+ include Enumerable
8
+
9
+ def self.supported?(data)
10
+ defined?(Numo::NArray) && data.is_a?(Numo::NArray)
11
+ end
12
+
13
+ def initialize(data)
14
+ @data = check_data(data)
15
+ self.index = index || RangeIndex.new(0 ... length)
16
+ end
17
+
18
+ def compare_data_equality(other)
19
+ case other
20
+ when ArrayAdapter, NArrayAdapter
21
+ data == other.data
22
+ when NumpyAdapter, PandasSeriesAdapter
23
+ other.compare_data_equality(self)
24
+ else
25
+ data == other.data.to_a
26
+ end
27
+ end
28
+
29
+ include NameSupport
30
+ include IndexSupport
31
+
32
+ def where(mask)
33
+ mask = check_mask_vector(mask)
34
+ case mask.data
35
+ when Numo::Bit
36
+ bits = mask.data
37
+ masked_data = data[bits]
38
+ masked_index = bits.where.map {|i| index[i] }.to_a
39
+ else
40
+ masked_data, masked_index = where_in_array(mask)
41
+ masked_data = data.class[*masked_data]
42
+ end
43
+ Charty::Vector.new(masked_data, index: masked_index, name: name)
44
+ end
45
+
46
+ def boolean?
47
+ case data
48
+ when Numo::Bit
49
+ true
50
+ when Numo::RObject
51
+ i, n = 0, data.size
52
+ while i < n
53
+ case data[i]
54
+ when nil, true, false
55
+ # do nothing
56
+ else
57
+ return false
58
+ end
59
+ i += 1
60
+ end
61
+ true
62
+ else
63
+ false
64
+ end
65
+ end
66
+
67
+ def numeric?
68
+ case data
69
+ when Numo::Bit,
70
+ Numo::RObject
71
+ false
72
+ else
73
+ true
74
+ end
75
+ end
76
+
77
+ def categorical?
78
+ false
79
+ end
80
+
81
+ def categories
82
+ nil
83
+ end
84
+
85
+ def unique_values
86
+ existence = {}
87
+ i, n = 0, data.size
88
+ unique = []
89
+ while i < n
90
+ x = data[i]
91
+ unless existence[x]
92
+ unique << x
93
+ existence[x] = true
94
+ end
95
+ i += 1
96
+ end
97
+ unique
98
+ end
99
+
100
+ def group_by(grouper)
101
+ case grouper
102
+ when Charty::Vector
103
+ # nothing to do
104
+ else
105
+ grouper = Charty::Vector.new(grouper)
106
+ end
107
+
108
+ group_keys = grouper.unique_values
109
+
110
+ case grouper.data
111
+ when Numo::NArray
112
+ grouper = grouper.data
113
+ else
114
+ grouper = Numo::NArray[*grouper.to_a]
115
+ end
116
+
117
+ group_keys.map { |g|
118
+ [g, Charty::Vector.new(data[grouper.eq(g)])]
119
+ }.to_h
120
+ end
121
+
122
+ def drop_na
123
+ case data
124
+ when Numo::DFloat, Numo::SFloat, Numo::DComplex, Numo::SComplex
125
+ Charty::Vector.new(data[~data.isnan])
126
+ when Numo::RObject
127
+ where_is_nan = data.isnan
128
+ values = []
129
+ i, n = 0, data.size
130
+ while i < n
131
+ x = data[i]
132
+ unless x.nil? || where_is_nan[i] == 1
133
+ values << x
134
+ end
135
+ i += 1
136
+ end
137
+ Charty::Vector.new(Numo::RObject[*values])
138
+ else
139
+ self
140
+ end
141
+ end
142
+
143
+ def eq(val)
144
+ Charty::Vector.new(data.eq(val),
145
+ index: index,
146
+ name: name)
147
+ end
148
+
149
+ def notnull
150
+ case data
151
+ when Numo::RObject
152
+ i, n = 0, length
153
+ notnull_data = Numo::Bit.zeros(n)
154
+ while i < n
155
+ notnull_data[i] = ! Util.missing?(data[i])
156
+ i += 1
157
+ end
158
+ when ->(x) { x.respond_to?(:isnan) }
159
+ notnull_data = ~data.isnan
160
+ else
161
+ notnull_data = Numo::Bit.ones(length)
162
+ end
163
+ Charty::Vector.new(notnull_data, index: index, name: name)
164
+ end
165
+
166
+ def mean
167
+ data.mean(nan: true)
168
+ end
169
+
170
+ def stdev(population: false)
171
+ s = data.stddev(nan: true)
172
+ if population
173
+ # Numo::NArray does not support population standard deviation
174
+ n = data.isnan.sum
175
+ s * (n - 1) / n
176
+ else
177
+ s
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,37 @@
1
+ module Charty
2
+ module VectorAdapters
3
+ class NMatrixAdapter < BaseAdapter
4
+ VectorAdapters.register(:nmatrix, self)
5
+
6
+ extend Forwardable
7
+ include Enumerable
8
+
9
+ def self.supported?(data)
10
+ defined?(NMatrix) && data.is_a?(NMatrix)
11
+ end
12
+
13
+ def initialize(data)
14
+ @data = check_data(data)
15
+ self.index = index || RangeIndex.new(0 ... length)
16
+ end
17
+
18
+ def compare_data_equality(other)
19
+ case other
20
+ when NMatrixAdapter
21
+ data == other.data
22
+ when ArrayAdapter, DaruVectorAdapter
23
+ data.to_a == other.data.to_a
24
+ when NArrayAdapter, NumpyAdapter, PandasSeriesAdapter
25
+ other.compare_data_equality(self)
26
+ else
27
+ data == other.data.to_a
28
+ end
29
+ end
30
+
31
+ include NameSupport
32
+ include IndexSupport
33
+
34
+ alias length size
35
+ end
36
+ end
37
+ end