daru 0.1.3.1 → 0.1.4

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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -1
  4. data/.rspec_formatter.rb +33 -0
  5. data/.rubocop.yml +26 -2
  6. data/History.md +38 -0
  7. data/README.md +22 -13
  8. data/Rakefile +50 -2
  9. data/benchmarks/csv_reading.rb +22 -0
  10. data/daru.gemspec +9 -2
  11. data/lib/daru.rb +36 -4
  12. data/lib/daru/accessors/array_wrapper.rb +6 -1
  13. data/lib/daru/accessors/dataframe_by_row.rb +10 -2
  14. data/lib/daru/accessors/gsl_wrapper.rb +1 -3
  15. data/lib/daru/accessors/nmatrix_wrapper.rb +9 -0
  16. data/lib/daru/category.rb +935 -0
  17. data/lib/daru/core/group_by.rb +29 -38
  18. data/lib/daru/core/merge.rb +186 -145
  19. data/lib/daru/core/query.rb +22 -11
  20. data/lib/daru/dataframe.rb +976 -885
  21. data/lib/daru/date_time/index.rb +166 -166
  22. data/lib/daru/date_time/offsets.rb +66 -77
  23. data/lib/daru/formatters/table.rb +54 -0
  24. data/lib/daru/helpers/array.rb +40 -0
  25. data/lib/daru/index.rb +476 -73
  26. data/lib/daru/io/io.rb +66 -45
  27. data/lib/daru/io/sql_data_source.rb +33 -62
  28. data/lib/daru/iruby/helpers.rb +38 -0
  29. data/lib/daru/iruby/templates/dataframe.html.erb +52 -0
  30. data/lib/daru/iruby/templates/dataframe_mi.html.erb +58 -0
  31. data/lib/daru/iruby/templates/multi_index.html.erb +12 -0
  32. data/lib/daru/iruby/templates/vector.html.erb +27 -0
  33. data/lib/daru/iruby/templates/vector_mi.html.erb +36 -0
  34. data/lib/daru/maths/arithmetic/dataframe.rb +16 -18
  35. data/lib/daru/maths/arithmetic/vector.rb +4 -6
  36. data/lib/daru/maths/statistics/dataframe.rb +8 -15
  37. data/lib/daru/maths/statistics/vector.rb +120 -98
  38. data/lib/daru/monkeys.rb +12 -40
  39. data/lib/daru/plotting/gruff.rb +3 -0
  40. data/lib/daru/plotting/gruff/category.rb +49 -0
  41. data/lib/daru/plotting/gruff/dataframe.rb +91 -0
  42. data/lib/daru/plotting/gruff/vector.rb +57 -0
  43. data/lib/daru/plotting/nyaplot.rb +3 -0
  44. data/lib/daru/plotting/nyaplot/category.rb +34 -0
  45. data/lib/daru/plotting/nyaplot/dataframe.rb +187 -0
  46. data/lib/daru/plotting/nyaplot/vector.rb +46 -0
  47. data/lib/daru/vector.rb +694 -421
  48. data/lib/daru/version.rb +1 -1
  49. data/profile/_base.rb +23 -0
  50. data/profile/df_to_a.rb +10 -0
  51. data/profile/filter.rb +13 -0
  52. data/profile/joining.rb +13 -0
  53. data/profile/sorting.rb +12 -0
  54. data/profile/vector_each_with_index.rb +9 -0
  55. data/spec/accessors/wrappers_spec.rb +2 -4
  56. data/spec/categorical_spec.rb +1734 -0
  57. data/spec/core/group_by_spec.rb +52 -2
  58. data/spec/core/merge_spec.rb +63 -2
  59. data/spec/core/query_spec.rb +236 -80
  60. data/spec/dataframe_spec.rb +1373 -79
  61. data/spec/date_time/data_spec.rb +3 -5
  62. data/spec/date_time/index_spec.rb +154 -17
  63. data/spec/date_time/offsets_spec.rb +3 -4
  64. data/spec/fixtures/empties.dat +2 -0
  65. data/spec/fixtures/strings.dat +2 -0
  66. data/spec/formatters/table_formatter_spec.rb +99 -0
  67. data/spec/helpers_spec.rb +8 -0
  68. data/spec/index/categorical_index_spec.rb +168 -0
  69. data/spec/index/index_spec.rb +283 -0
  70. data/spec/index/multi_index_spec.rb +570 -0
  71. data/spec/io/io_spec.rb +31 -4
  72. data/spec/io/sql_data_source_spec.rb +0 -1
  73. data/spec/iruby/dataframe_spec.rb +172 -0
  74. data/spec/iruby/helpers_spec.rb +49 -0
  75. data/spec/iruby/multi_index_spec.rb +37 -0
  76. data/spec/iruby/vector_spec.rb +107 -0
  77. data/spec/math/arithmetic/dataframe_spec.rb +71 -13
  78. data/spec/math/arithmetic/vector_spec.rb +8 -10
  79. data/spec/math/statistics/dataframe_spec.rb +3 -5
  80. data/spec/math/statistics/vector_spec.rb +45 -55
  81. data/spec/monkeys_spec.rb +32 -9
  82. data/spec/plotting/dataframe_spec.rb +386 -0
  83. data/spec/plotting/vector_spec.rb +230 -0
  84. data/spec/shared/vector_display_spec.rb +215 -0
  85. data/spec/spec_helper.rb +23 -0
  86. data/spec/vector_spec.rb +905 -138
  87. metadata +143 -11
  88. data/.rubocop_todo.yml +0 -44
  89. data/lib/daru/plotting/dataframe.rb +0 -104
  90. data/lib/daru/plotting/vector.rb +0 -38
  91. data/spec/daru_spec.rb +0 -58
  92. data/spec/index_spec.rb +0 -375
@@ -0,0 +1,230 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Daru::Vector, 'plotting' do
4
+ let(:vector) { Daru::Vector.new([11, 22, 33], index: [:a, :b, :c]) }
5
+ let(:plot) { instance_double('Nyaplot::Plot') }
6
+ let(:diagram) { instance_double('Nyaplot::Diagram') }
7
+
8
+ before do
9
+ Daru.plotting_library = :nyaplot
10
+ allow(Nyaplot::Plot).to receive(:new).and_return(plot)
11
+ end
12
+
13
+ it 'plots the vector' do
14
+ expect(plot).to receive(:add).with(:box, [11, 22, 33]).ordered
15
+ expect(plot).to receive(:show).ordered
16
+
17
+ vector.plot(type: :box)
18
+ end
19
+
20
+ context 'scatter' do
21
+ it 'is default type' do
22
+ expect(plot).to receive(:add).with(:scatter, instance_of(Array), instance_of(Array)).ordered
23
+ expect(plot).to receive(:show).ordered
24
+
25
+ vector.plot
26
+ end
27
+
28
+ it 'sets x_axis to 0...size' do
29
+ expect(plot).to receive(:add).with(:scatter, [0, 1, 2], [11, 22, 33]).ordered
30
+ expect(plot).to receive(:show).ordered
31
+
32
+ vector.plot(type: :scatter)
33
+ end
34
+ end
35
+
36
+ [:box, :histogram].each do |type|
37
+ context type.to_s do
38
+ it 'does not set x axis' do
39
+ expect(plot).to receive(:add).with(type, [11, 22, 33]).ordered
40
+ expect(plot).to receive(:show).ordered
41
+
42
+ vector.plot(type: type)
43
+ end
44
+ end
45
+ end
46
+
47
+ [:bar, :line].each do |type| # FIXME: what other types 2D plot could have?..
48
+ context type.to_s do
49
+ it 'sets x axis to index' do
50
+ expect(plot).to receive(:add).with(type, [:a, :b, :c], [11, 22, 33]).ordered
51
+ expect(plot).to receive(:show).ordered
52
+
53
+ vector.plot(type: type)
54
+ end
55
+ end
56
+ end
57
+
58
+ context 'with block provided' do
59
+ it 'yields plot and diagram' do
60
+ expect(plot).to receive(:add).with(:box, [11, 22, 33]).ordered.and_return(diagram)
61
+ expect(plot).to receive(:show).ordered
62
+
63
+ expect { |b| vector.plot(type: :box, &b) }.to yield_with_args(plot, diagram)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe Daru::Vector, 'plotting category' do
69
+ let(:plot) { instance_double('Nyaplot::Plot') }
70
+ let(:diagram) { instance_double('Nyaplot::Diagram') }
71
+ let(:dv) do
72
+ Daru::Vector.new ['III']*10 + ['II']*5 + ['I']*5,
73
+ type: :category,
74
+ categories: ['I', 'II', 'III']
75
+ end
76
+ before do
77
+ Daru.plotting_library = :nyaplot
78
+ allow(Nyaplot::Plot).to receive(:new).and_return(plot)
79
+ end
80
+ context 'bar' do
81
+ it 'plots bar graph taking a block' do
82
+ expect(plot).to receive(:add).with(:bar, ['I', 'II', 'III'], [5, 5, 10])
83
+ expect(plot).to receive :x_label
84
+ expect(plot).to receive :y_label
85
+ expect(plot).to receive(:show)
86
+ dv.plot(type: :bar) do |p|
87
+ p.x_label 'Categories'
88
+ p.y_label 'Frequency'
89
+ end
90
+ end
91
+
92
+ it 'plots bar graph without taking a block' do
93
+ expect(plot).to receive(:add).with(:bar, ["I", "II", "III"], [5, 5, 10])
94
+ expect(plot).to receive(:show)
95
+ dv.plot(type: :bar)
96
+ end
97
+
98
+ it 'plots bar graph with percentage' do
99
+ expect(plot).to receive(:add).with(:bar, ["I", "II", "III"], [25, 25, 50])
100
+ expect(plot).to receive(:yrange).with [0, 100]
101
+ expect(plot).to receive(:show)
102
+ dv.plot(type: :bar, method: :percentage)
103
+ end
104
+
105
+ it 'plots bar graph with fraction' do
106
+ expect(plot).to receive(:add).with(:bar, ["I", "II", "III"], [0.25, 0.25, 0.50])
107
+ expect(plot).to receive(:yrange).with [0, 1]
108
+ expect(plot).to receive(:show)
109
+ dv.plot(type: :bar, method: :fraction)
110
+ end
111
+ end
112
+
113
+ context 'other type' do
114
+ it { expect { dv.plot(type: :scatter) }.to raise_error ArgumentError }
115
+ end
116
+ end
117
+
118
+ describe Daru::Vector, 'plotting vector with gruff' do
119
+ let(:dv) { Daru::Vector.new [1, 2, 3] }
120
+ before { Daru.plotting_library = :gruff }
121
+
122
+ context 'line' do
123
+ let(:plot) { instance_double 'Gruff::Line' }
124
+ before { allow(Gruff::Line).to receive(:new).and_return(plot) }
125
+
126
+ it 'plots line graph without block' do
127
+ expect(plot).to receive(:labels=)
128
+ expect(plot).to receive(:data)
129
+ dv.plot type: :line
130
+ end
131
+
132
+ it 'plots line graph with block' do
133
+ expect(plot).to receive :labels=
134
+ expect(plot).to receive :data
135
+ expect(plot).to receive :title=
136
+ dv.plot(type: :line) { |p| p.title = 'hello' }
137
+ end
138
+ end
139
+
140
+ context 'bar' do
141
+ let(:plot) { instance_double 'Gruff::Bar' }
142
+ before { allow(Gruff::Bar).to receive(:new).and_return(plot) }
143
+
144
+ it 'plots bar graph' do
145
+ expect(plot).to receive :labels=
146
+ expect(plot).to receive :data
147
+ dv.plot type: :bar
148
+ end
149
+ end
150
+
151
+ context 'pie' do
152
+ let(:plot) { instance_double 'Gruff::Pie' }
153
+ before { allow(Gruff::Pie).to receive(:new).and_return(plot) }
154
+
155
+ it 'plots pie graph' do
156
+ expect(plot).to receive(:data).exactly(3).times
157
+ dv.plot type: :pie
158
+ end
159
+ end
160
+
161
+ context 'scatter' do
162
+ let(:plot) { instance_double 'Gruff::Scatter' }
163
+ before { allow(Gruff::Scatter).to receive(:new).and_return(plot) }
164
+
165
+ it 'plots scatter graph' do
166
+ expect(plot).to receive :data
167
+ dv.plot type: :scatter
168
+ end
169
+ end
170
+
171
+ context 'sidebar' do
172
+ let(:plot) { instance_double 'Gruff::SideBar' }
173
+ before { allow(Gruff::SideBar).to receive(:new).and_return(plot) }
174
+
175
+ it 'plots sidebar' do
176
+ expect(plot).to receive :labels=
177
+ expect(plot).to receive(:data).exactly(3).times
178
+ dv.plot type: :sidebar
179
+ end
180
+ end
181
+
182
+ context 'invalid type' do
183
+ it { expect { dv.plot type: :lol }.to raise_error ArgumentError }
184
+ end
185
+ end
186
+
187
+ describe Daru::Vector, 'plotting category vector with gruff' do
188
+ before { Daru.plotting_library = :gruff }
189
+ let(:dv) { Daru::Vector.new [1, 2, 3], type: :category }
190
+
191
+ context 'bar' do
192
+ let(:plot) { instance_double 'Gruff::Bar' }
193
+ before { allow(Gruff::Bar).to receive(:new).and_return(plot) }
194
+ it 'plots bar graph' do
195
+ expect(plot).to receive :labels=
196
+ expect(plot).to receive :data
197
+ dv.plot type: :bar
198
+ end
199
+
200
+ it 'plots bar graph with block' do
201
+ expect(plot).to receive :labels=
202
+ expect(plot).to receive :data
203
+ expect(plot).to receive :title=
204
+ dv.plot(type: :bar) { |p| p.title = 'hello' }
205
+ end
206
+ end
207
+
208
+ context 'pie' do
209
+ let(:plot) { instance_double 'Gruff::Pie' }
210
+ before { allow(Gruff::Pie).to receive(:new).and_return(plot) }
211
+ it 'plots pie graph' do
212
+ expect(plot).to receive(:data).exactly(3).times
213
+ dv.plot type: :pie
214
+ end
215
+ end
216
+
217
+ context 'sidebar' do
218
+ let(:plot) { instance_double 'Gruff::SideBar' }
219
+ before { allow(Gruff::SideBar).to receive(:new).and_return(plot) }
220
+ it 'plots sidebar graph' do
221
+ expect(plot).to receive :labels=
222
+ expect(plot).to receive(:data).exactly(3).times
223
+ dv.plot type: :sidebar
224
+ end
225
+ end
226
+
227
+ context 'invalid type' do
228
+ it { expect { dv.plot type: :lol }.to raise_error ArgumentError }
229
+ end
230
+ end
@@ -0,0 +1,215 @@
1
+ describe Daru::Vector do
2
+ # TODO: Add inspect specs for category
3
+ context '#inspect' do
4
+ context 'simple' do
5
+ subject(:vector) { Daru::Vector.new [1,2,3],
6
+ index: [:a, :b, :c], name: 'test'}
7
+ its(:inspect) { is_expected.to eq %Q{
8
+ |#<Daru::Vector(3)>
9
+ | test
10
+ | a 1
11
+ | b 2
12
+ | c 3
13
+ }.unindent }
14
+ end
15
+
16
+ context 'no name' do
17
+ subject(:vector) { Daru::Vector.new [1,2,3], index: [:a, :b, :c]}
18
+ its(:inspect) { is_expected.to eq %Q{
19
+ |#<Daru::Vector(3)>
20
+ | a 1
21
+ | b 2
22
+ | c 3
23
+ }.unindent }
24
+ end
25
+
26
+ context 'with nils' do
27
+ subject(:vector) { Daru::Vector.new [1,nil,3],
28
+ index: [:a, :b, :c], name: 'test'}
29
+ its(:inspect) { is_expected.to eq %Q{
30
+ |#<Daru::Vector(3)>
31
+ | test
32
+ | a 1
33
+ | b nil
34
+ | c 3
35
+ }.unindent }
36
+ end
37
+
38
+ context 'very large amount of data' do
39
+ subject(:vector) { Daru::Vector.new [1,2,3] * 100, name: 'test'}
40
+ its(:inspect) { is_expected.to eq %Q{
41
+ |#<Daru::Vector(300)>
42
+ | test
43
+ | 0 1
44
+ | 1 2
45
+ | 2 3
46
+ | 3 1
47
+ | 4 2
48
+ | 5 3
49
+ | 6 1
50
+ | 7 2
51
+ | 8 3
52
+ | 9 1
53
+ | 10 2
54
+ | 11 3
55
+ | 12 1
56
+ | 13 2
57
+ | 14 3
58
+ | ... ...
59
+ }.unindent }
60
+ end
61
+
62
+ context 'really long name or data' do
63
+ subject(:vector) { Daru::Vector.new [1,2,'this is ridiculously long'],
64
+ index: [:a, :b, :c], name: 'and this is not much better faithfully'}
65
+ its(:inspect) { is_expected.to eq %Q{
66
+ |#<Daru::Vector(3)>
67
+ | and this is not much
68
+ | a 1
69
+ | b 2
70
+ | c this is ridiculously
71
+ }.unindent }
72
+ end
73
+
74
+ context 'with multiindex' do
75
+ subject(:vector) {
76
+ Daru::Vector.new(
77
+ [1,2,3,4,5,6,7],
78
+ name: 'test',
79
+ index: Daru::MultiIndex.from_tuples([
80
+ %w[foo one],
81
+ %w[foo two],
82
+ %w[foo three],
83
+ %w[bar one],
84
+ %w[bar two],
85
+ %w[bar three],
86
+ %w[baz one],
87
+ ]),
88
+ )
89
+ }
90
+
91
+ its(:inspect) { is_expected.to eq %Q{
92
+ |#<Daru::Vector(7)>
93
+ | test
94
+ | foo one 1
95
+ | two 2
96
+ | three 3
97
+ | bar one 4
98
+ | two 5
99
+ | three 6
100
+ | baz one 7
101
+ }.unindent}
102
+ end
103
+
104
+ context 'threshold and spacing settings' do
105
+ end
106
+ end
107
+
108
+ [nil, :category].each do |type|
109
+ context '#to_html' do
110
+ let(:doc) { Nokogiri::HTML(vector.to_html) }
111
+ subject(:table) { doc.at('table') }
112
+ let(:header) { table.at('tr:first-child > th:first-child') }
113
+
114
+ context 'simple' do
115
+ let(:vector) { Daru::Vector.new [1,nil,3],
116
+ index: [:a, :b, :c], name: 'test', type: type }
117
+ it { is_expected.not_to be_nil }
118
+
119
+ describe 'header' do
120
+ subject { header }
121
+ it { is_expected.not_to be_nil }
122
+ its(['colspan']) { is_expected.to eq '2' }
123
+ its(:text) { is_expected.to eq "Daru::Vector(3)"\
124
+ "#{":category" if type == :category}" }
125
+ end
126
+
127
+ describe 'name' do
128
+ subject(:name) { table.at('tr:nth-child(2) > th:nth-child(2)') }
129
+ it { is_expected.not_to be_nil }
130
+ its(:text) { is_expected.to eq 'test' }
131
+
132
+ context 'withought name' do
133
+ let(:vector) { Daru::Vector.new [1,nil,3], index: [:a, :b, :c], type: type }
134
+
135
+ it { is_expected.to be_nil }
136
+ end
137
+ end
138
+
139
+ describe 'index' do
140
+ subject(:indexes) { table.search('tr > td:first-child').map(&:text) }
141
+ its(:count) { is_expected.to eq vector.size }
142
+ it { is_expected.to eq vector.index.to_a.map(&:to_s) }
143
+ end
144
+
145
+ describe 'values' do
146
+ subject(:indexes) { table.search('tr > td:last-child').map(&:text) }
147
+ its(:count) { is_expected.to eq vector.size }
148
+ it { is_expected.to eq vector.to_a.map(&:to_s) }
149
+ end
150
+ end
151
+
152
+ context 'large vector' do
153
+ subject(:vector) { Daru::Vector.new [1,2,3] * 100, name: 'test', type: type }
154
+ it 'has only 30 rows (+ 2 header rows, + 2 finishing rows)' do
155
+ expect(table.search('tr').size).to eq 34
156
+ end
157
+
158
+ describe '"skipped" row' do
159
+ subject(:row) { table.search('tr:nth-child(33) td').map(&:text) }
160
+ its(:count) { is_expected.to eq 2 }
161
+ it { is_expected.to eq ['...', '...'] }
162
+ end
163
+
164
+ describe 'last row' do
165
+ subject(:row) { table.search('tr:nth-child(34) td').map(&:text) }
166
+ its(:count) { is_expected.to eq 2 }
167
+ it { is_expected.to eq ['299', '3'] }
168
+ end
169
+ end
170
+
171
+ context 'multi-index' do
172
+ subject(:vector) {
173
+ Daru::Vector.new(
174
+ [1,2,3,4,5,6,7],
175
+ name: 'test',
176
+ type: type,
177
+ index: Daru::MultiIndex.from_tuples([
178
+ %w[foo one],
179
+ %w[foo two],
180
+ %w[foo three],
181
+ %w[bar one],
182
+ %w[bar two],
183
+ %w[bar three],
184
+ %w[baz one],
185
+ ]),
186
+ )
187
+ }
188
+
189
+ describe 'header' do
190
+ subject { header }
191
+ it { is_expected.not_to be_nil }
192
+ its(['colspan']) { is_expected.to eq '3' }
193
+ its(:text) { is_expected.to eq "Daru::Vector(7)"\
194
+ "#{":category" if type == :category}" }
195
+ end
196
+
197
+ describe 'name row' do
198
+ subject(:row) { table.at('tr:nth-child(2)').search('th') }
199
+ its(:count) { should == 2 }
200
+ it { expect(row.first['colspan']).to eq '2' }
201
+ end
202
+
203
+ describe 'first data row' do
204
+ let(:row) { table.at('tr:nth-child(3)') }
205
+ subject { row.inner_html.scan(/<t[dh].+?<\/t[dh]>/) }
206
+ it { is_expected.to eq [
207
+ '<th rowspan="3">foo</th>',
208
+ '<th rowspan="1">one</th>',
209
+ '<td>1</td>'
210
+ ]}
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -1,9 +1,12 @@
1
1
  require 'rspec'
2
+ require 'rspec/its'
2
3
  require 'matrix'
3
4
  require 'awesome_print'
4
5
  require 'distribution'
5
6
  require 'tempfile'
6
7
  require 'pry-byebug'
8
+ require 'nokogiri'
9
+ require 'gruff'
7
10
 
8
11
  def mri?
9
12
  RUBY_ENGINE == 'ruby'
@@ -21,6 +24,11 @@ end
21
24
 
22
25
  RSpec::Expectations.configuration.warn_about_potential_false_positives = false
23
26
 
27
+ require 'simplecov'
28
+ SimpleCov.start do
29
+ add_filter 'spec'
30
+ minimum_coverage_by_file 95
31
+ end
24
32
 
25
33
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
26
34
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -42,4 +50,19 @@ def expect_correct_df_in_delta df1, df2, delta
42
50
  end
43
51
  end
44
52
 
53
+ class String
54
+ # allows to pretty test agains multiline strings:
55
+ # %Q{
56
+ # |test
57
+ # |me
58
+ # }.unindent # =>
59
+ # "test
60
+ # me"
61
+ def unindent
62
+ gsub(/\n\s+?\|/, "\n") # for all lines looking like "<spaces>|" -- remove this.
63
+ .gsub(/\|\n/, "\n") # allow to write trailing space not removed by editor
64
+ .gsub(/^\n|\n\s+$/, '') # remove empty strings before and after
65
+ end
66
+ end
67
+
45
68
  Dir[File.expand_path('../support/**/*.rb', __FILE__)].each {|f| require f }