feldtruby 0.3.14 → 0.3.16

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.
@@ -0,0 +1,11 @@
1
+ class Array
2
+ def all_pairs
3
+
4
+ return [] if length < 2
5
+
6
+ x, *rest = self
7
+
8
+ rest.map {|e| [x, e]} + rest.all_pairs
9
+
10
+ end
11
+ end
@@ -0,0 +1,64 @@
1
+ require 'stringio'
2
+
3
+ module FeldtRuby
4
+
5
+ class Logger
6
+ def initialize(io = STDOUT)
7
+
8
+ @io = io
9
+
10
+ # We save a unique array of events for each type.
11
+ @events = Hash.new {|h,k| h[k] = Array.new}
12
+
13
+ end
14
+
15
+ # Return the number of events of type _eventType_.
16
+ def num_events eventType = nil
17
+ @events[eventType].length
18
+ end
19
+
20
+ Event = Struct.new(:description, :time_stamp)
21
+
22
+ # Count an event of type _eventType_.
23
+ def log_event eventType = nil, description = ""
24
+ @events[eventType] << Event.new(description, Time.now)
25
+ end
26
+
27
+ # Return all the events, i.e. descriptions and time stamp, for a given _eventType_.
28
+ def events(eventType = nil)
29
+ @events[eventType]
30
+ end
31
+
32
+ # Return all the event descriptions for a given _eventType_.
33
+ def event_descriptions(eventType = nil)
34
+ @events[eventType].map {|e| e.description}
35
+ end
36
+
37
+ # Log an event described by a string _str_ optionally with an event type
38
+ # _eventType_.
39
+ def log str, eventType = nil
40
+
41
+ description = log_entry_description(str, eventType)
42
+
43
+ log_event eventType, description
44
+
45
+ io_puts description
46
+
47
+ end
48
+
49
+ # Puts the given _str_ on the io stream.
50
+ def io_puts str
51
+ @io.puts str
52
+ end
53
+
54
+ # Map a string and event type to a log string.
55
+ def log_entry_description str, eventType = nil
56
+
57
+ event_tag = eventType ? "{#{eventType.to_s}}: " : ""
58
+
59
+ event_tag + str
60
+
61
+ end
62
+ end
63
+
64
+ end
@@ -20,6 +20,14 @@ module MiniTest::Assertions
20
20
  end
21
21
  end
22
22
 
23
+ NumTestRepetitions = 50
24
+
25
+ def repeatedly_it(message, &testcode)
26
+ NumTestRepetitions.times do |i|
27
+ it("#{i}: " + message, &testcode)
28
+ end
29
+ end
30
+
23
31
  module MiniTest::Expectations
24
32
  infect_an_assertion :assert_similar_proportions, :must_have_similar_proportions
25
33
  infect_an_assertion :assert_falsey, :must_be_falsey
@@ -110,8 +110,9 @@ class RCommunicator
110
110
  end
111
111
  end
112
112
 
113
- # Convert a Ruby object of one of the types String, Array, Integer or Float
114
- # to a String that can be used in R code/scripts to represent the object.
113
+ # Convert a Ruby object of one of the types String, Symbol, Array, Integer
114
+ # or Float to a String that can be used in R code/scripts to
115
+ # represent the object.
115
116
  def ruby_object_to_R_string(o)
116
117
 
117
118
  case o
@@ -119,6 +120,9 @@ class RCommunicator
119
120
  when String
120
121
  return o.inspect
121
122
 
123
+ when Symbol
124
+ return o.to_s
125
+
122
126
  when Array
123
127
  elems = o.map {|e| ruby_object_to_R_string(e)}.join(", ")
124
128
  return "c(#{elems})"
@@ -164,6 +168,10 @@ module Statistics
164
168
  res.p_value
165
169
  end
166
170
 
171
+ def correlation(ary1, ary2)
172
+ RC.call("cor", ary1, ary2)
173
+ end
174
+
167
175
  class DiffusionKDE
168
176
  attr_reader :densities, :mesh
169
177
 
@@ -246,9 +254,38 @@ module FeldtRuby::Statistics::Plotting
246
254
 
247
255
  end
248
256
 
249
- def hexbin_heatmap(csvFilePath, xlabel, ylabel, title = "heatmap", bins = 20)
257
+ def filled_contour(csvFilePath, xlabel, ylabel, title = "filled.contour")
258
+ include_library "MASS"
259
+ #include_library "ggplot2"
260
+
261
+ script = <<-EOS
262
+ data <- read.csv(#{csvFilePath.inspect})
263
+ k <- with(data, MASS::kde2d(#{xlabel}, #{ylabel}))
264
+ f <- filled.contour(k, color=topo.colors,
265
+ plot.title=title(main = _title_),
266
+ xlab=_xlabel_, ylab=_ylabel_)
267
+ f
268
+ EOS
269
+
270
+ subst_eval script, {:title => title,
271
+ :xlabel => xlabel.to_s, :ylabel => ylabel.to_s}
272
+
273
+ end
274
+
275
+ def smooth_scatter_plot(csvFilePath, xlabel, ylabel, title = "smoothscatter")
276
+ include_library "graphics"
277
+
278
+ script = <<-EOS
279
+ f <- ggplot(data, aes(#{xlabel}, #{ylabel})) +
280
+ geom_point() + geom_smooth( method="loess", se = FALSE )
281
+ EOS
282
+
283
+ plot_2dims(csvFilePath, script, xlabel.to_s, ylabel.to_s, title)
284
+ end
285
+
286
+ def hexbin_heatmap(csvFilePath, xlabel, ylabel, title = "heatmap", bins = 50)
250
287
  plot_2dims(csvFilePath,
251
- "f <- ggplot(data, aes(#{ylabel}, #{ylabel})) + geom_hex( bins = #{bins} )",
288
+ "f <- ggplot(data, aes(#{xlabel}, #{ylabel})) + geom_hex( bins = #{bins} )",
252
289
  xlabel, ylabel, title)
253
290
  end
254
291
 
@@ -260,7 +297,7 @@ module FeldtRuby::Statistics::Plotting
260
297
  f <- f + stat_smooth()
261
298
  EOS
262
299
 
263
- plot_2dims(csvFilePath, script, xlabel, ylabel, title)
300
+ plot_2dims(csvFilePath, script, xlabel.to_s, ylabel.to_s, title)
264
301
 
265
302
  end
266
303
 
@@ -1,3 +1,3 @@
1
1
  module FeldtRuby
2
- VERSION = "0.3.14"
2
+ VERSION = "0.3.16"
3
3
  end
data/test/helper.rb CHANGED
@@ -4,4 +4,5 @@ require 'minitest/spec'
4
4
 
5
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
6
  $LOAD_PATH.unshift(File.dirname(__FILE__))
7
- require 'feldtruby'
7
+ require 'feldtruby'
8
+ require 'feldtruby/minitest_extensions'
@@ -0,0 +1,43 @@
1
+ require 'feldtruby/array/permutations_and_subsets'
2
+
3
+ describe "all pairs of elements from an array" do
4
+
5
+ it "cannot return any pairs if there are fewer than 2 elements" do
6
+
7
+ [].all_pairs.must_equal []
8
+ [1].all_pairs.must_equal []
9
+ [:a].all_pairs.must_equal []
10
+
11
+ end
12
+
13
+ it "returns the only pair if 2 elements" do
14
+
15
+ [1, 2].all_pairs.must_equal [[1, 2]]
16
+ [1, "a"].all_pairs.must_equal [[1, "a"]]
17
+
18
+ end
19
+
20
+ it "returns the right pairs when 3 elements" do
21
+
22
+ [1, 2, 3].all_pairs.sort.must_equal [[1, 2], [1, 3], [2, 3]].sort
23
+
24
+ end
25
+
26
+ def invariant_all_original_elements_are_at_least_in_one_pair(ary)
27
+
28
+ ary.all_pairs.flatten.uniq.sort.must_equal ary.uniq.sort
29
+
30
+ end
31
+
32
+ repeatedly_it "returns the right number of pairs when > 3 elements" do
33
+
34
+ ary = Array.new(4 + rand(10)).map {rand(1000)}
35
+
36
+ invariant_all_original_elements_are_at_least_in_one_pair ary
37
+
38
+ num_pairs = ary.all_pairs
39
+ n = ary.length
40
+
41
+ end
42
+
43
+ end
@@ -1,16 +1,35 @@
1
1
  require 'minitest/spec'
2
2
  require 'feldtruby/net/html_doc_getter'
3
3
 
4
- describe "HtmlDocGetter" do
5
- it "Can get the html page as a string" do
6
- h = FeldtRuby::HtmlDocGetter.new
7
- s = h.get("http://www.google.com")
8
- s.must_be_instance_of String
4
+ # Skip these network-dependent tests if we have no network connection.
5
+ def has_network_connection?
6
+ begin
7
+ open("http://www.google.se")
8
+ return true
9
+ rescue Exception => e
10
+ return false
9
11
  end
12
+ end
10
13
 
11
- it "Can get the html page as a Nokogiri doc" do
12
- h = FeldtRuby::HtmlDocGetter.new
13
- d = h.get_html_doc("http://www.google.com")
14
- d.must_be_instance_of Nokogiri::HTML::Document
14
+ def quicker_has_network_connection?
15
+ reply = `ping -o google.se`
16
+ reply != "" # Is empty if no connection since error is printed on STDERR
17
+ end
18
+
19
+ if quicker_has_network_connection?
20
+
21
+ describe "HtmlDocGetter" do
22
+ it "Can get the html page as a string" do
23
+ h = FeldtRuby::HtmlDocGetter.new
24
+ s = h.get("http://www.google.com")
25
+ s.must_be_instance_of String
26
+ end
27
+
28
+ it "Can get the html page as a Nokogiri doc" do
29
+ h = FeldtRuby::HtmlDocGetter.new
30
+ d = h.get_html_doc("http://www.google.com")
31
+ d.must_be_instance_of Nokogiri::HTML::Document
32
+ end
15
33
  end
34
+
16
35
  end
@@ -0,0 +1,96 @@
1
+ require 'feldtruby/logger'
2
+
3
+ describe 'Logger' do
4
+
5
+ before do
6
+ @sio = StringIO.new
7
+ @l = FeldtRuby::Logger.new @sio
8
+ end
9
+
10
+ it 'has a event count of 0 when no events has been logged' do
11
+
12
+ @l.num_events.must_equal 0
13
+
14
+ end
15
+
16
+ it 'increases default event count when default events are logged' do
17
+
18
+ @l.log "1"
19
+ @l.num_events.must_equal 1
20
+
21
+ @l.log "2"
22
+ @l.num_events.must_equal 2
23
+
24
+ end
25
+
26
+ it 'can log default events (described in strings)' do
27
+
28
+ @l.log "event 1"
29
+ @sio.string.must_equal "event 1\n"
30
+ @l.num_events.must_equal 1
31
+
32
+ @l.log "event 2"
33
+ @sio.string.must_equal "event 1\nevent 2\n"
34
+ @l.num_events.must_equal 2
35
+
36
+ end
37
+
38
+ it 'can log events of a given type' do
39
+
40
+ @l.log "1", :increase
41
+ @sio.string.must_equal "{increase}: 1\n"
42
+ @l.num_events.must_equal 0
43
+ @l.num_events(:increase).must_equal 1
44
+
45
+ @l.log "2", :increase
46
+ @sio.string.must_equal "{increase}: 1\n{increase}: 2\n"
47
+ @l.num_events.must_equal 0
48
+ @l.num_events(:increase).must_equal 2
49
+
50
+ end
51
+
52
+ it 'can return old default events' do
53
+
54
+ @l.log "event 1"
55
+ @l.event_descriptions.must_equal ["event 1"]
56
+
57
+ @l.log "event 2"
58
+ @l.event_descriptions.must_equal ["event 1", "event 2"]
59
+
60
+ end
61
+
62
+ it 'can return old events of given type' do
63
+
64
+ @l.log "1", :increase
65
+ @l.log "2", :increase
66
+ @l.log "0.4", :alpha
67
+ @l.log "1", :increase
68
+
69
+ @l.event_descriptions(:increase).must_equal ["{increase}: 1", "{increase}: 2", "{increase}: 1"]
70
+
71
+ @l.event_descriptions(:alpha).must_equal ["{alpha}: 0.4"]
72
+
73
+ @l.event_descriptions(:beta).must_equal []
74
+
75
+ end
76
+
77
+ it 'time stamps each log entry' do
78
+
79
+ @l.log "1", :a
80
+ @l.log "2", :b
81
+ @l.log "2", :a
82
+
83
+ time_stamps_a = @l.events(:a).map {|e| e.time_stamp}
84
+ time_stamps_b = @l.events(:b).map {|e| e.time_stamp}
85
+
86
+ time_stamps_a[0].must_be_instance_of Time
87
+ time_stamps_a[1].must_be_instance_of Time
88
+ time_stamps_b[0].must_be_instance_of Time
89
+
90
+ time_stamps_a[0].must_be :<, time_stamps_a[1]
91
+ time_stamps_a[0].must_be :<, time_stamps_b[0]
92
+ time_stamps_b[0].must_be :<, time_stamps_a[1]
93
+
94
+ end
95
+
96
+ end
@@ -82,6 +82,18 @@ describe "Statistics" do
82
82
  kde.densities[3].must_be_close_to 0.2728
83
83
  end
84
84
  end
85
+
86
+ describe "correlation between Ruby arrays" do
87
+
88
+ it "works for a simple example from the R doc for cor" do
89
+ correlation( (1..10).to_a, (2..11).to_a ).must_equal 1
90
+ end
91
+
92
+ it "works for the inverse of the simple example from the R doc for cor" do
93
+ correlation( (1..10).to_a, (-11..-2).to_a.reverse ).must_equal -1
94
+ end
95
+
96
+ end
85
97
  end
86
98
 
87
99
  require 'feldtruby/minitest_extensions'
@@ -154,7 +166,7 @@ describe "Plotting" do
154
166
 
155
167
  File.exist?(out).must_equal true
156
168
 
157
- #File.delete out
169
+ File.delete out
158
170
 
159
171
  end
160
172
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feldtruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.14
4
+ version: 0.3.16
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-11 00:00:00.000000000 Z
12
+ date: 2013-03-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rinruby
@@ -79,9 +79,11 @@ files:
79
79
  - lib/feldtruby/array.rb
80
80
  - lib/feldtruby/array/basic_stats.rb
81
81
  - lib/feldtruby/array/count_by.rb
82
+ - lib/feldtruby/array/permutations_and_subsets.rb
82
83
  - lib/feldtruby/file/file_change_watcher.rb
83
84
  - lib/feldtruby/file/tempfile.rb
84
85
  - lib/feldtruby/float.rb
86
+ - lib/feldtruby/logger.rb
85
87
  - lib/feldtruby/math/rand.rb
86
88
  - lib/feldtruby/minitest_extensions.rb
87
89
  - lib/feldtruby/net/html_doc_getter.rb
@@ -115,11 +117,13 @@ files:
115
117
  - test/test_array.rb
116
118
  - test/test_array_basic_stats.rb
117
119
  - test/test_array_count_by.rb
120
+ - test/test_array_permutations_and_subsets.rb
118
121
  - test/test_clustering.rb
119
122
  - test/test_euclidean_distance.rb
120
123
  - test/test_fastmap.rb
121
124
  - test/test_float.rb
122
125
  - test/test_html_doc_getter.rb
126
+ - test/test_logger.rb
123
127
  - test/test_normalization.rb
124
128
  - test/test_optimize.rb
125
129
  - test/test_optimize_differential_evolution.rb
@@ -165,11 +169,13 @@ test_files:
165
169
  - test/test_array.rb
166
170
  - test/test_array_basic_stats.rb
167
171
  - test/test_array_count_by.rb
172
+ - test/test_array_permutations_and_subsets.rb
168
173
  - test/test_clustering.rb
169
174
  - test/test_euclidean_distance.rb
170
175
  - test/test_fastmap.rb
171
176
  - test/test_float.rb
172
177
  - test/test_html_doc_getter.rb
178
+ - test/test_logger.rb
173
179
  - test/test_normalization.rb
174
180
  - test/test_optimize.rb
175
181
  - test/test_optimize_differential_evolution.rb