rust 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ require_relative 'rust-core'
2
+
3
+ module Rust
4
+ class CSV
5
+ def self.read_all(pattern, **options)
6
+ result = {}
7
+ Dir.glob(pattern).each do |filename|
8
+ result[filename] = CSV.read(filename, **options)
9
+ end
10
+ return result
11
+ end
12
+
13
+ def self.read(filename, **options)
14
+ hash = {}
15
+ labels = nil
16
+
17
+ infer_numbers = options.has_key?(:infer_numbers) ? options.delete(:infer_numbers) : true
18
+ infer_integers = options.delete(:infer_integers)
19
+
20
+ ::CSV.foreach(filename, **options) do |row|
21
+ # TODO fix this ugly patch
22
+ unless options[:headers]
23
+ options[:headers] = (1..row.size).to_a.map { |e| "X#{e}" }
24
+
25
+ return CSV.read(filename, **options)
26
+ end
27
+
28
+ unless labels
29
+ labels = row.headers
30
+ labels.each do |label|
31
+ hash[label] = []
32
+ end
33
+ end
34
+
35
+ labels.each do |label|
36
+ hash[label] << row[label]
37
+ end
38
+ end
39
+
40
+ result = Rust::DataFrame.new(hash)
41
+ if infer_numbers
42
+ result = self.auto_infer_types(result, infer_integers)
43
+ end
44
+
45
+ return result
46
+ end
47
+
48
+ def self.write(filename, dataframe, **options)
49
+ raise TypeError, "Expected Rust::DataFrame" unless dataframe.is_a?(Rust::DataFrame)
50
+
51
+ write_headers = options[:headers] != false
52
+ options[:headers] = dataframe.column_names if options[:headers] == nil
53
+
54
+ hash = {}
55
+ labels = nil
56
+ ::CSV.open(filename, 'w', write_headers: write_headers, **options) do |csv|
57
+ dataframe.each do |row|
58
+ csv << row
59
+ end
60
+ end
61
+
62
+ return true
63
+ end
64
+
65
+ private
66
+ def self.auto_infer_types(dataframe, auto_infer_integers)
67
+ integer_columns = []
68
+ float_columns = []
69
+ dataframe.column_names.each do |column_name|
70
+ values = dataframe.column(column_name)
71
+
72
+ if values.all? { |s| !!Integer(s) rescue false }
73
+ integer_columns << column_name
74
+ elsif values.all? { |s| !!Float(s) rescue false }
75
+ float_columns << column_name
76
+ end
77
+ end
78
+
79
+ unless auto_infer_integers
80
+ float_columns += integer_columns
81
+ integer_columns = []
82
+ end
83
+
84
+ integer_columns.each do |numeric_column|
85
+ dataframe.transform_column!(numeric_column) { |v| v.to_i }
86
+ end
87
+
88
+ float_columns.each do |numeric_column|
89
+ dataframe.transform_column!(numeric_column) { |v| v.to_f }
90
+ end
91
+
92
+ return dataframe
93
+ end
94
+ end
95
+ end
@@ -45,10 +45,10 @@ module Rust::Descriptive
45
45
  raise "Percentiles outside the range: #{percentiles}" if percentiles.any? { |e| !e.between?(0, 1) }
46
46
 
47
47
  Rust.exclusive do
48
- Rust::R_ENGINE.data = data
49
- Rust::R_ENGINE.percs = percentiles
48
+ Rust['descriptive.data'] = data
49
+ Rust['descriptive.percs'] = percentiles
50
50
 
51
- call_result = Rust._pull("quantile(data, percs)")
51
+ call_result = Rust._pull("quantile(descriptive.data, descriptive.percs)")
52
52
  assert { call_result.is_a?(Array) }
53
53
  assert { call_result.size == percentiles.size }
54
54
 
@@ -25,17 +25,17 @@ module Rust::EffectSize::CliffDelta
25
25
  raise TypeError, "Expecting Array of numerics" if !d2.is_a?(Array) || !d2.all? { |e| e.is_a?(Numeric) }
26
26
 
27
27
  Rust.exclusive do
28
- Rust::R_ENGINE.a = d1
29
- Rust::R_ENGINE.b = d2
28
+ Rust['effsize.a'] = d1
29
+ Rust['effsize.b'] = d2
30
30
 
31
- Rust._eval("result = cliff.delta(a, b)")
31
+ Rust._eval("effsize.result = cliff.delta(effsize.a, effsize.b)")
32
32
 
33
33
  result = Rust::EffectSize::Result.new
34
34
  result.name = "Cliff's delta"
35
- result.estimate = Rust._pull("result$estimate")
36
- result.confidence_interval = Range.new(*Rust._pull("result$conf.int"))
37
- result.confidence_level = Rust._pull("result$conf.level")
38
- result.magnitude = Rust._pull("as.character(result$magnitude)").to_sym
35
+ result.estimate = Rust._pull("effsize.result$estimate")
36
+ result.confidence_interval = Range.new(*Rust._pull("effsize.result$conf.int"))
37
+ result.confidence_level = Rust._pull("effsize.result$conf.level")
38
+ result.magnitude = Rust._pull("as.character(effsize.result$magnitude)").to_sym
39
39
 
40
40
  return result
41
41
  end
@@ -50,17 +50,17 @@ module Rust::EffectSize::CohenD
50
50
  raise TypeError, "Expecting Array of numerics" if !d2.is_a?(Array) || !d2.all? { |e| e.is_a?(Numeric) }
51
51
 
52
52
  Rust.exclusive do
53
- Rust::R_ENGINE.a = d1
54
- Rust::R_ENGINE.b = d2
53
+ Rust['effsize.a'] = d1
54
+ Rust['effsize.b'] = d2
55
55
 
56
- Rust._eval("result = cohen.d(a, b)")
56
+ Rust._eval("effsize.result = cohen.d(effsize.a, effsize.b)")
57
57
 
58
58
  result = Rust::EffectSize::Result.new
59
59
  result.name = "Cohen's d"
60
- result.estimate = Rust._pull("result$estimate")
61
- result.confidence_interval = Range.new(*Rust._pull("result$conf.int"))
62
- result.confidence_level = Rust._pull("result$conf.level")
63
- result.magnitude = Rust._pull("as.character(result$magnitude)").to_sym
60
+ result.estimate = Rust._pull("effsize.result$estimate")
61
+ result.confidence_interval = Range.new(*Rust._pull("effsize.result$conf.int"))
62
+ result.confidence_level = Rust._pull("effsize.result$conf.level")
63
+ result.magnitude = Rust._pull("as.character(effsize.result$magnitude)").to_sym
64
64
 
65
65
  return result
66
66
  end
@@ -0,0 +1,351 @@
1
+ require_relative 'rust-core'
2
+ require_relative 'rust-calls'
3
+
4
+ module Rust::Plots
5
+ class BasePlot
6
+ def initialize
7
+ @plugins = []
8
+ @options = Rust::Options.new
9
+ end
10
+
11
+ def x_label(label)
12
+ @options['xlab'] = label
13
+
14
+ return self
15
+ end
16
+
17
+ def y_label(label)
18
+ @options['ylab'] = label
19
+
20
+ return self
21
+ end
22
+
23
+ def x_range(range)
24
+ @options['xlim'] = range
25
+
26
+ return self
27
+ end
28
+
29
+ def y_range(range)
30
+ @options['ylim'] = range
31
+
32
+ return self
33
+ end
34
+
35
+ def axis(axis)
36
+ @options['xaxt'] = 'n'
37
+ @options['yaxt'] = 'n'
38
+
39
+ self.plug(axis)
40
+
41
+ return self
42
+ end
43
+
44
+ def title(title)
45
+ @options['main'] = title
46
+
47
+ return self
48
+ end
49
+
50
+ def color(color)
51
+ @options['col'] = color
52
+
53
+ return self
54
+ end
55
+
56
+ def plug(plugin)
57
+ raise TypeError, "Expected Plugin" unless plugin.is_a?(Plugin)
58
+ @plugins << plugin
59
+
60
+ return self
61
+ end
62
+
63
+ def []=(option, value)
64
+ @options[option] = value
65
+ end
66
+
67
+ def show()
68
+ Rust.exclusive do
69
+ self._show
70
+ self._run_plugins
71
+ end
72
+
73
+ return self
74
+ end
75
+
76
+ def pdf(path, **options)
77
+ pdf_function = Rust::Function.new("pdf")
78
+ pdf_function.options = Rust::Options.from_hash(options)
79
+ pdf_function.options['file'] = path
80
+
81
+
82
+ Rust.exclusive do
83
+ pdf_function.call
84
+ self._show
85
+ self._run_plugins
86
+ Rust._eval("dev.off()")
87
+ end
88
+
89
+ return self
90
+ end
91
+
92
+ protected
93
+ def _show()
94
+ raise "You are trying to show a BasePlot"
95
+ end
96
+
97
+ def _run_plugins()
98
+ @plugins.each do |plugin|
99
+ plugin._run()
100
+ end
101
+
102
+ return self
103
+ end
104
+
105
+ def _augmented_options(options={})
106
+ result = @options.clone
107
+
108
+ options.each do |key, value|
109
+ result[key] = value
110
+ end
111
+
112
+ result.select! { |k, v| v != nil }
113
+
114
+ return result
115
+ end
116
+ end
117
+
118
+ class ScatterPlot < BasePlot
119
+ def initialize(x, y)
120
+ super()
121
+ @x = x
122
+ @y = y
123
+ end
124
+
125
+ def thickness(t)
126
+ self['lwd'] = t
127
+
128
+ return self
129
+ end
130
+
131
+ def lines()
132
+ self['type'] = "l"
133
+
134
+ return self
135
+ end
136
+
137
+ def points()
138
+ self['type'] = "p"
139
+
140
+ return self
141
+ end
142
+
143
+ def lines_and_points()
144
+ self['type'] = "b"
145
+
146
+ return self
147
+ end
148
+
149
+ protected
150
+ def _show()
151
+ Rust["plotter.x"] = @x
152
+ Rust["plotter.y"] = @y
153
+
154
+ function = Rust::Function.new("plot")
155
+ function.options = self._augmented_options
156
+ function.arguments << Rust::Variable.new("plotter.x")
157
+ function.arguments << Rust::Variable.new("plotter.y")
158
+
159
+ function.call
160
+
161
+ return self
162
+ end
163
+ end
164
+
165
+ class DistributionPlot < BasePlot
166
+ def initialize
167
+ super()
168
+ @series = []
169
+ end
170
+
171
+ def series(data, **options)
172
+ @series << [data, options]
173
+
174
+ return self
175
+ end
176
+ end
177
+
178
+ class DensityPlot < DistributionPlot
179
+ protected
180
+ def _show()
181
+ first = true
182
+ @series.each do |data, options|
183
+ Rust["plotter.series"] = data
184
+
185
+ if first
186
+ first = false
187
+ command = "plot"
188
+ else
189
+ command = "lines"
190
+ end
191
+
192
+ function = Rust::Function.new(command)
193
+ function.options = self._augmented_options({"col" => options[:color]})
194
+ function.arguments << Rust::Variable.new("density(plotter.series)")
195
+ function.call
196
+ end
197
+
198
+ return self
199
+ end
200
+ end
201
+
202
+ class BoxPlot < DistributionPlot
203
+ protected
204
+ def _show()
205
+ function = Rust::Function.new("boxplot")
206
+
207
+ names = []
208
+ @series.each_with_index do |data, i|
209
+ series, options = *data
210
+ varname = "plotter.series#{i}"
211
+ Rust[varname] = series
212
+ function.arguments << Rust::Variable.new(varname)
213
+ names << (options[:name] || (i+1).to_s)
214
+ end
215
+
216
+ function.options = self._augmented_options({'names' => names})
217
+
218
+ function.call
219
+
220
+ return self
221
+ end
222
+ end
223
+
224
+ class Plugin
225
+ def initialize
226
+ @options = Rust::Options.new
227
+ end
228
+
229
+ def []=(option, value)
230
+ @options[option] = value
231
+
232
+ return self
233
+ end
234
+
235
+ protected
236
+ def _run()
237
+ raise "You are trying to run an abstract Plugin"
238
+ end
239
+ end
240
+
241
+ class Axis < Plugin
242
+ BELOW = 1
243
+ LEFT = 2
244
+ ABOVE = 3
245
+ RIGHT = 4
246
+
247
+ def initialize(side)
248
+ super()
249
+
250
+ self['side'] = side
251
+ self.at(nil)
252
+ self.labels(true)
253
+ end
254
+
255
+ def at(values)
256
+ self['at'] = values
257
+
258
+ return self
259
+ end
260
+
261
+ def vertical_labels
262
+ self['las'] = 2
263
+
264
+ return self
265
+ end
266
+
267
+ def horizontal_labels
268
+ self['las'] = 1
269
+
270
+ return self
271
+ end
272
+
273
+ def labels(value)
274
+ self['labels'] = value
275
+
276
+ return self
277
+ end
278
+
279
+ def _run()
280
+ function = Rust::Function.new("axis")
281
+ function.options = @options
282
+
283
+ function.call
284
+
285
+ return self
286
+ end
287
+ end
288
+
289
+ class Grid < Plugin
290
+ def initialize
291
+ super()
292
+
293
+ @x = Float::NAN
294
+ @y = Float::NAN
295
+ end
296
+
297
+ def x(value)
298
+ @x = value
299
+
300
+ return self
301
+ end
302
+
303
+ def y(value)
304
+ @y = value
305
+
306
+ return self
307
+ end
308
+
309
+ def auto_x
310
+ @x = nil
311
+
312
+ return self
313
+ end
314
+
315
+ def auto_y
316
+ @y = nil
317
+
318
+ return self
319
+ end
320
+
321
+ def hide_x
322
+ @x = Float::NAN
323
+
324
+ return self
325
+ end
326
+
327
+ def hide_y
328
+ @y = Float::NAN
329
+
330
+ return self
331
+ end
332
+
333
+ def _run()
334
+ function = Rust::Function.new("grid")
335
+
336
+ function.arguments << @x
337
+ function.arguments << @y
338
+ function.options = @options
339
+
340
+ function.call
341
+
342
+ return self
343
+ end
344
+ end
345
+ end
346
+
347
+ module Rust::RBindings
348
+ def plot(x, y)
349
+ Rust::Plots::ScatterPlot.new(x, y).show
350
+ end
351
+ end