flex-station-data 0.3.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +33 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +106 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +23 -1
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +51 -28
  9. data/README.md +16 -29
  10. data/Rakefile +5 -1
  11. data/bin/flex-station +33 -11
  12. data/bin/flex-station-linear-regression +19 -37
  13. data/flex-station-data.gemspec +7 -4
  14. data/lib/flex_station_data.rb +2 -0
  15. data/lib/flex_station_data/concerns/callable.rb +33 -0
  16. data/lib/flex_station_data/concerns/presenter.rb +4 -18
  17. data/lib/flex_station_data/concerns/service.rb +4 -18
  18. data/lib/flex_station_data/default_sample_map.rb +33 -0
  19. data/lib/flex_station_data/linear_regression.rb +2 -0
  20. data/lib/flex_station_data/plate.rb +14 -3
  21. data/lib/flex_station_data/presenters/plate_hash.rb +26 -0
  22. data/lib/flex_station_data/presenters/plates_hash.rb +26 -0
  23. data/lib/flex_station_data/presenters/sample_hash.rb +47 -0
  24. data/lib/flex_station_data/presenters/sample_regression_hash.rb +44 -0
  25. data/lib/flex_station_data/sample.rb +20 -5
  26. data/lib/flex_station_data/services/compute_mean.rb +2 -0
  27. data/lib/flex_station_data/services/load_plates.rb +12 -1
  28. data/lib/flex_station_data/services/parse_plate.rb +6 -4
  29. data/lib/flex_station_data/services/parse_plate_readings.rb +43 -36
  30. data/lib/flex_station_data/services/parse_sample_map.rb +47 -0
  31. data/lib/flex_station_data/services/sample_quality.rb +6 -5
  32. data/lib/flex_station_data/services/value_quality.rb +5 -1
  33. data/lib/flex_station_data/version.rb +3 -1
  34. data/lib/flex_station_data/wells.rb +16 -15
  35. metadata +31 -19
  36. data/bin/flex-station-sample-data +0 -54
  37. data/lib/flex_station_data/presenters/linear_regression/plate_hash.rb +0 -27
  38. data/lib/flex_station_data/presenters/linear_regression/plates_hash.rb +0 -28
  39. data/lib/flex_station_data/presenters/linear_regression/sample_hash.rb +0 -47
  40. data/lib/flex_station_data/presenters/linear_regression/sample_regression_hash.rb +0 -43
  41. data/lib/flex_station_data/presenters/linear_regression/verbose_sample_csv.rb +0 -28
  42. data/lib/flex_station_data/presenters/plate_csv.rb +0 -29
  43. data/lib/flex_station_data/presenters/plates_csv.rb +0 -28
  44. data/lib/flex_station_data/presenters/sample_csv.rb +0 -56
  45. data/lib/flex_station_data/readings.rb +0 -16
  46. data/lib/flex_station_data/services/parse_plate_samples.rb +0 -49
@@ -1,16 +1,31 @@
1
- require "flex_station_data/readings"
1
+ # frozen_string_literal: true
2
+
3
+ require "matrix"
4
+
5
+ require "flex_station_data/services/compute_mean"
2
6
 
3
7
  module FlexStationData
4
8
  class Sample
5
- attr_reader :label, :readings
9
+ attr_reader :label, :wells, :plate
6
10
 
7
- def initialize(label, readings)
11
+ delegate :wells, to: :plate, prefix: true
12
+
13
+ def initialize(label, wells, plate)
8
14
  @label = label
9
- @readings = readings
15
+ @wells = wells
16
+ @plate = plate
17
+ end
18
+
19
+ def values
20
+ wells.map(&plate_wells.method(:values))
21
+ end
22
+
23
+ def readings
24
+ @readings ||= wells.zip(values).map { |well, v| Readings.new(well, v) }
10
25
  end
11
26
 
12
27
  def mean
13
- @mean ||= Readings.mean(*readings)
28
+ @mean ||= values.transpose.map(&ComputeMean)
14
29
  end
15
30
  end
16
31
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext"
2
4
 
3
5
  require "flex_station_data/concerns/service"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "csv"
2
4
  require "active_support/core_ext"
3
5
 
@@ -18,7 +20,10 @@ module FlexStationData
18
20
  end
19
21
 
20
22
  def data_blocks
21
- @data_blocks ||= data.split { |row| row[0] == "Plate:" }.drop(1)
23
+ @data_blocks ||= data.each_with_object([]) do |row, blocks|
24
+ blocks << [] if plate_row?(row)
25
+ blocks.last&.push(row)
26
+ end
22
27
  end
23
28
 
24
29
  def call
@@ -26,5 +31,11 @@ module FlexStationData
26
31
  FlexStationData::ParsePlate.call(index + 1, data_block)
27
32
  end
28
33
  end
34
+
35
+ private
36
+
37
+ def plate_row?(row)
38
+ row[0].to_s =~ /\A\s*Plate:\s*/i
39
+ end
29
40
  end
30
41
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext"
2
4
 
3
5
  require "flex_station_data/services/parse_plate_readings"
4
- require "flex_station_data/services/parse_plate_samples"
6
+ require "flex_station_data/services/parse_sample_map"
5
7
  require "flex_station_data/plate"
6
8
 
7
9
  module FlexStationData
@@ -16,13 +18,13 @@ module FlexStationData
16
18
  end
17
19
 
18
20
  def data_blocks
19
- plate_data.split { |row| row[0] == "~End" }
21
+ plate_data.split { |row| row[0] =~ /\A~End\s*\z/ }
20
22
  end
21
23
 
22
24
  def call
23
25
  times, temperatures, wells = ParsePlateReadings.call(data_blocks[0])
24
- samples = ParsePlateSamples.call(data_blocks[1], wells)
25
- Plate.new(label, times, temperatures, samples)
26
+ sample_map = ParseSampleMap.call(data_blocks[1])
27
+ Plate.new(label, times, temperatures, wells, sample_map)
26
28
  end
27
29
  end
28
30
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext"
4
+ require "matrix"
2
5
 
3
6
  require "flex_station_data/wells"
4
7
  require "flex_station_data/concerns/service"
@@ -9,49 +12,32 @@ module FlexStationData
9
12
 
10
13
  delegate :parse_time, :parse_value, :parse_row, to: :class
11
14
 
12
- def initialize(plate_readings_block)
13
- @plate_readings_block = plate_readings_block
15
+ def initialize(plate_data)
16
+ @plate_data = plate_data
14
17
  end
15
18
 
16
- def column_count
17
- @column_count ||= headers.reverse.drop_while(&:blank?).size
19
+ def readings_block
20
+ @readings_block ||= plate_data
21
+ .drop_while { |row| !header_row?(row) }
22
+ .drop_while { |row| !sample_row?(row) }
23
+ .take_while { |row| !end_row?(row) }
24
+ .select { |row| row.any?(&:present?) }
18
25
  end
19
26
 
20
- def parsed_rows
21
- @parsed_rows ||= begin
22
- rows = plate_readings_data.map { |row| parse_row(row[0...column_count]) }
23
- rows.select { |row| row.any?(&:present?) }
24
- end
25
- end
26
-
27
- def parsed_columns
28
- @parsed_columns ||= parsed_rows.transpose
27
+ def headers
28
+ @headers ||= plate_data.detect(&method(:header_row?)).reverse.drop_while(&:blank?).reverse
29
29
  end
30
30
 
31
31
  def times
32
- @times ||= parsed_columns[0].compact
32
+ @times ||= matrix.column(0).to_a.compact
33
33
  end
34
34
 
35
35
  def temperatures
36
- @temperatures ||= parsed_columns[1].compact
37
- end
38
-
39
- def values
40
- @values ||= parsed_columns.drop(2)
41
- end
42
-
43
- def wells_row_count
44
- parsed_rows.size / times.size
45
- end
46
-
47
- def plate_readings_matrix
48
- values.map do |values_column|
49
- values_column.each_slice(wells_row_count).to_a.transpose
50
- end.transpose
36
+ @temperatures ||= matrix.column(1).to_a.compact
51
37
  end
52
38
 
53
39
  def wells
54
- Wells.new(plate_readings_matrix)
40
+ Wells.new(wells_matrix)
55
41
  end
56
42
 
57
43
  def call
@@ -67,7 +53,9 @@ module FlexStationData
67
53
  end
68
54
 
69
55
  def parse_value(v)
70
- return Float(v) rescue v.presence
56
+ Float(v)
57
+ rescue ArgumentError, TypeError
58
+ v.presence
71
59
  end
72
60
 
73
61
  def parse_row(row)
@@ -78,14 +66,33 @@ module FlexStationData
78
66
 
79
67
  private
80
68
 
81
- def headers
82
- plate_readings_block.first
69
+ def header_row?(row)
70
+ row[1].to_s =~ /\A\s*Temperature\b/i
71
+ end
72
+
73
+ def sample_row?(row)
74
+ row[0].to_s =~ /\A\s*\d+:\d+:\d+\s*\z/
75
+ end
76
+
77
+ def end_row?(row)
78
+ row[0].to_s =~ /\A\s*~End\s*\z/i
79
+ end
80
+
81
+ def well_values
82
+ matrix.minor(0..-1, 2..-1)
83
+ end
84
+
85
+ def matrix
86
+ @matrix ||= Matrix[
87
+ *readings_block.map { |row| parse_row(row[0...headers.size]) }
88
+ ]
83
89
  end
84
90
 
85
- def plate_readings_data
86
- @plate_readings_data ||= plate_readings_block.drop(1)
91
+ def wells_matrix
92
+ well_row_count = matrix.row_count / times.size
93
+ Matrix[*well_values.column_vectors.map { |col| col.to_a.each_slice(well_row_count).to_a.transpose }.transpose]
87
94
  end
88
95
 
89
- attr_reader :plate_readings_block
96
+ attr_reader :plate_data
90
97
  end
91
98
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "matrix"
4
+ require "active_support/core_ext"
5
+
6
+ require "flex_station_data/concerns/service"
7
+
8
+ module FlexStationData
9
+ class ParseSampleMap
10
+ include Concerns::Service
11
+
12
+ attr_reader :plate_data
13
+
14
+ def initialize(plate_data)
15
+ @plate_data = plate_data
16
+ end
17
+
18
+ def sample_map_rows
19
+ plate_data
20
+ .drop_while { |row| !sample_map_header?(row) }
21
+ .drop(1)
22
+ .take_while { |row| !empty_row?(row) }
23
+ .map(&method(:parse_row))
24
+ end
25
+
26
+ def call
27
+ sample_map_rows.each_with_object([]) do |(label, well), memo|
28
+ memo << [ label, [] ] if label.present?
29
+ memo.last.last << well
30
+ end.to_h
31
+ end
32
+
33
+ private
34
+
35
+ def parse_row(row)
36
+ row.take(2).map(&:presence)
37
+ end
38
+
39
+ def empty_row?(row)
40
+ row.all?(&:blank?)
41
+ end
42
+
43
+ def sample_map_header?(row)
44
+ row[0].to_s =~ /\A\s*Sample\s*\z/i && row[1].to_s =~ /\A\s*Wells\s*\z/i
45
+ end
46
+ end
47
+ end
@@ -1,23 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "flex_station_data/services/value_quality"
2
4
 
3
5
  module FlexStationData
4
6
  class SampleQuality
5
7
  include Concerns::Service
6
8
 
7
- attr_reader :sample, :value_quality_control, :options
9
+ attr_reader :sample, :options
8
10
 
9
- def initialize(sample, value_quality_control: ValueQuality, **options)
11
+ def initialize(sample, **options)
10
12
  @sample = sample
11
- @value_quality_control = value_quality_control
12
13
  @options = options
13
14
  end
14
15
 
15
16
  def value_quality(value)
16
- value_quality_control.call(value, **options)
17
+ ValueQuality.call(value, **options)
17
18
  end
18
19
 
19
20
  def call
20
- sample.readings.flat_map(&:values).map(&method(:value_quality)).uniq(&:to_s)
21
+ sample.values.flatten.map(&method(:value_quality)).uniq(&:to_s)
21
22
  end
22
23
  end
23
24
  end
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "singleton"
2
4
  require "active_support/core_ext"
3
5
 
6
+ require "flex_station_data/concerns/service"
7
+
4
8
  module FlexStationData
5
9
  class ValueQuality
6
10
  include Concerns::Service
@@ -21,7 +25,7 @@ module FlexStationData
21
25
  attr_reader :description
22
26
 
23
27
  def initialize(description)
24
- @description ||= description
28
+ @description = description
25
29
  end
26
30
 
27
31
  def good?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FlexStationData
2
- VERSION = "0.3.0"
4
+ VERSION = "1.0.2"
3
5
  end
@@ -1,29 +1,30 @@
1
- require "flex_station_data/readings"
1
+ # frozen_string_literal: true
2
+
3
+ require "matrix"
2
4
 
3
5
  module FlexStationData
4
6
  class Wells
5
- def initialize(plate_readings_matrix)
6
- @plate_readings_matrix = plate_readings_matrix
7
+ attr_reader :matrix
8
+
9
+ def initialize(matrix)
10
+ @matrix = matrix
7
11
  end
8
12
 
9
- def readings(well_label)
10
- well_index[well_label] ||= begin
11
- row, column = parse_well_label(well_label)
12
- Readings.new(well_label, plate_readings_matrix[row][column])
13
- end
13
+ def values(well_label)
14
+ matrix[*coordinates(well_label)]
14
15
  end
15
16
 
16
- def parse_well_label(well_label)
17
- row, column = well_label.scan(/\A([A-Z])(\d+)\z/).first
18
- [ row.ord - "A".ord, column.to_i - 1 ]
17
+ def coordinates(well_label)
18
+ coordinates_index[well_label] ||= begin
19
+ row, column = well_label.scan(/\A([A-Z])(\d+)\z/).first
20
+ [ row.ord - "A".ord, column.to_i - 1 ]
21
+ end
19
22
  end
20
23
 
21
24
  private
22
25
 
23
- def well_index
24
- @well_index ||= {}
26
+ def coordinates_index
27
+ @coordinates_index ||= {}
25
28
  end
26
-
27
- attr_reader :plate_readings_matrix
28
29
  end
29
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flex-station-data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Carney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-24 00:00:00.000000000 Z
11
+ date: 2020-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,20 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '10.0'
47
+ version: '13.0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '10.0'
54
+ version: '13.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -53,7 +67,7 @@ dependencies:
53
67
  - !ruby/object:Gem::Version
54
68
  version: '3.8'
55
69
  - !ruby/object:Gem::Dependency
56
- name: pry
70
+ name: rubocop-rspec
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - ">="
@@ -100,12 +114,14 @@ email:
100
114
  executables:
101
115
  - flex-station
102
116
  - flex-station-linear-regression
103
- - flex-station-sample-data
104
117
  extensions: []
105
118
  extra_rdoc_files: []
106
119
  files:
120
+ - ".github/workflows/ruby.yml"
107
121
  - ".gitignore"
108
122
  - ".rspec"
123
+ - ".rubocop.yml"
124
+ - ".ruby-version"
109
125
  - CHANGELOG.md
110
126
  - CODE_OF_CONDUCT.md
111
127
  - Gemfile
@@ -115,28 +131,24 @@ files:
115
131
  - Rakefile
116
132
  - bin/flex-station
117
133
  - bin/flex-station-linear-regression
118
- - bin/flex-station-sample-data
119
134
  - flex-station-data.gemspec
120
135
  - lib/flex_station_data.rb
136
+ - lib/flex_station_data/concerns/callable.rb
121
137
  - lib/flex_station_data/concerns/presenter.rb
122
138
  - lib/flex_station_data/concerns/service.rb
139
+ - lib/flex_station_data/default_sample_map.rb
123
140
  - lib/flex_station_data/linear_regression.rb
124
141
  - lib/flex_station_data/plate.rb
125
- - lib/flex_station_data/presenters/linear_regression/plate_hash.rb
126
- - lib/flex_station_data/presenters/linear_regression/plates_hash.rb
127
- - lib/flex_station_data/presenters/linear_regression/sample_hash.rb
128
- - lib/flex_station_data/presenters/linear_regression/sample_regression_hash.rb
129
- - lib/flex_station_data/presenters/linear_regression/verbose_sample_csv.rb
130
- - lib/flex_station_data/presenters/plate_csv.rb
131
- - lib/flex_station_data/presenters/plates_csv.rb
132
- - lib/flex_station_data/presenters/sample_csv.rb
133
- - lib/flex_station_data/readings.rb
142
+ - lib/flex_station_data/presenters/plate_hash.rb
143
+ - lib/flex_station_data/presenters/plates_hash.rb
144
+ - lib/flex_station_data/presenters/sample_hash.rb
145
+ - lib/flex_station_data/presenters/sample_regression_hash.rb
134
146
  - lib/flex_station_data/sample.rb
135
147
  - lib/flex_station_data/services/compute_mean.rb
136
148
  - lib/flex_station_data/services/load_plates.rb
137
149
  - lib/flex_station_data/services/parse_plate.rb
138
150
  - lib/flex_station_data/services/parse_plate_readings.rb
139
- - lib/flex_station_data/services/parse_plate_samples.rb
151
+ - lib/flex_station_data/services/parse_sample_map.rb
140
152
  - lib/flex_station_data/services/sample_quality.rb
141
153
  - lib/flex_station_data/services/value_quality.rb
142
154
  - lib/flex_station_data/version.rb
@@ -155,14 +167,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
155
167
  requirements:
156
168
  - - ">="
157
169
  - !ruby/object:Gem::Version
158
- version: 2.4.4
170
+ version: 2.7.1
159
171
  required_rubygems_version: !ruby/object:Gem::Requirement
160
172
  requirements:
161
173
  - - ">="
162
174
  - !ruby/object:Gem::Version
163
175
  version: '0'
164
176
  requirements: []
165
- rubygems_version: 3.0.3
177
+ rubygems_version: 3.1.2
166
178
  signing_key:
167
179
  specification_version: 4
168
180
  summary: Data analysis tool for FlexStation microplate reader