flex-station-data 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 021c77855ba20d73d59feec617693f9144813dd8df75bf7152e5910b725e4d96
4
- data.tar.gz: 6083225e530d6237b32240da1d9d36673ee0295f7e55ff20e2d7611f9a34984f
3
+ metadata.gz: 8d58049eac2b497f587a9e2b467eb09ada8fe9582c3dced6985aa59f26cbe58b
4
+ data.tar.gz: 6154e1b4930afde05d7449df4ce0ebfce74e92d0651944d163cb4664e6c880f6
5
5
  SHA512:
6
- metadata.gz: dc685111292440177fc03da73865dfdf9b70d6b9385ce23a7d622b1fbdbdd01698c7fd46beb963bb71064b58297f26ac4b0d110287eedd95f771cb859f31e20a
7
- data.tar.gz: c110c96e690d26968964d7814bd3dab6347bd2bad15f9171102ac05b32a9c7dbdb6c1a23d472ddea6734062623fce8b709b964eea2eed6313ad32dddf954526b
6
+ metadata.gz: 0307a6c1f8cff75dba0fb93ec17b2b49ec59db99cf1d5c18d487b40d2451695bc92fcbf911f1cba2e85fe859ccc2bd107537f6422eb1a14f0a9f5c684ac735a3
7
+ data.tar.gz: ff7e2b5c8d363aae425010d47e7e531028ae122772be9db1098f46113f28e1d04ffd6df065000ea69c21b138342071cfc4f618638754bffb7d9353bbb172252c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- flex-station-data (0.3.1)
4
+ flex-station-data (0.3.2)
5
5
  activesupport
6
6
  linefit
7
7
 
@@ -1,12 +1,21 @@
1
+ require "flex_station_data/sample"
2
+
1
3
  module FlexStationData
2
4
  class Plate
3
- attr_reader :label, :times, :temperatures, :samples
5
+ attr_reader :label, :times, :temperatures, :wells, :sample_map
4
6
 
5
- def initialize(label, times, temperatures, samples)
7
+ def initialize(label, times, temperatures, wells, sample_map)
6
8
  @label = label
7
9
  @times = times
8
10
  @temperatures = temperatures
9
- @samples = samples
11
+ @wells = wells
12
+ @sample_map = sample_map
13
+ end
14
+
15
+ def samples
16
+ @samples ||= sample_map.map do |label, well_labels|
17
+ Sample.new(label, well_labels, self)
18
+ end
10
19
  end
11
20
  end
12
21
  end
@@ -29,13 +29,13 @@ module FlexStationData
29
29
  end
30
30
 
31
31
  def wells_hash
32
- { "wells" => sample.readings.map(&:label).join(", ") }
32
+ { "wells" => sample.wells.join(", ") }
33
33
  end
34
34
 
35
35
  def regression_hash
36
36
  return SampleRegressionHash.headers.zip([]).to_h if errors?
37
37
 
38
- SampleRegressionHash.present(times, sample.mean.values, **options).transform_values(&:first)
38
+ SampleRegressionHash.present(times, sample.mean, **options).transform_values(&:first)
39
39
  end
40
40
 
41
41
  def present
@@ -8,7 +8,7 @@ module FlexStationData
8
8
  include Concerns::Presenter
9
9
 
10
10
  def sample_values
11
- [ *sample.readings, sample.mean ].map(&:values)
11
+ [ *sample.values, sample.mean ]
12
12
  end
13
13
 
14
14
  def regressions_hash
@@ -15,15 +15,20 @@ module FlexStationData
15
15
  @options = options
16
16
  end
17
17
 
18
+ def present
19
+ [
20
+ [ "Plate #{plate.label}" ],
21
+ *samples_csv
22
+ ]
23
+ end
24
+
25
+ private
26
+
18
27
  def samples_csv
19
28
  samples.flat_map do |sample|
20
29
  sample_presenter.present(times, sample, **options)
21
30
  end
22
31
  end
23
-
24
- def present
25
- [ ["Plate #{plate.label}"], *samples_csv ]
26
- end
27
32
  end
28
33
  end
29
34
  end
@@ -14,15 +14,20 @@ module FlexStationData
14
14
  @options = options
15
15
  end
16
16
 
17
+ def present
18
+ [
19
+ [ "File: #{file.basename.to_path}" ],
20
+ *plates_csv
21
+ ]
22
+ end
23
+
24
+ private
25
+
17
26
  def plates_csv
18
27
  plates.flat_map do |plate|
19
28
  plate_presenter.present(plate, **options)
20
29
  end
21
30
  end
22
-
23
- def present
24
- [ ["File: #{file.to_path}"], *plates_csv ]
25
- end
26
31
  end
27
32
  end
28
33
  end
@@ -1,5 +1,4 @@
1
1
  require "flex_station_data/concerns/presenter"
2
- require "flex_station_data/readings"
3
2
  require "flex_station_data/services/sample_quality"
4
3
 
5
4
  module FlexStationData
@@ -16,26 +15,24 @@ module FlexStationData
16
15
  @options = options
17
16
  end
18
17
 
19
- def readings
20
- @readings ||= [ Readings.new("time", times), *sample.readings, sample.mean ]
18
+ def errors
19
+ @errors ||= quality_control.call(sample, **options).reject(&:good?)
21
20
  end
22
21
 
23
- def headers
24
- readings.map(&:label)
22
+ def present
23
+ [
24
+ [ label ],
25
+ *body_csv,
26
+ [ ]
27
+ ]
25
28
  end
26
29
 
27
- def rows
28
- readings.map(&:values).transpose
29
- end
30
+ private
30
31
 
31
32
  def label
32
33
  "Sample #{sample.label}"
33
34
  end
34
35
 
35
- def errors
36
- @errors ||= quality_control.call(sample, **options).reject(&:good?)
37
- end
38
-
39
36
  def errors?
40
37
  errors.present?
41
38
  end
@@ -44,12 +41,20 @@ module FlexStationData
44
41
  errors.map(&:to_s).map(&method(:Array))
45
42
  end
46
43
 
44
+ def headers
45
+ [ "time", *sample.wells, "mean" ]
46
+ end
47
+
48
+ def values
49
+ [ times, *sample.values, sample.mean ]
50
+ end
51
+
47
52
  def values_csv
48
- [ headers, *rows ]
53
+ [ headers, *values.transpose ]
49
54
  end
50
55
 
51
- def present
52
- [ [label] ] + (errors? ? errors_csv : values_csv) + [ [] ]
56
+ def body_csv
57
+ errors? ? errors_csv : values_csv
53
58
  end
54
59
  end
55
60
  end
@@ -1,16 +1,29 @@
1
- require "flex_station_data/readings"
1
+ require "matrix"
2
+
3
+ require "flex_station_data/services/compute_mean"
2
4
 
3
5
  module FlexStationData
4
6
  class Sample
5
- attr_reader :label, :readings
7
+ attr_reader :label, :wells, :plate
8
+
9
+ delegate :wells, to: :plate, prefix: true
6
10
 
7
- def initialize(label, readings)
11
+ def initialize(label, wells, plate)
8
12
  @label = label
9
- @readings = readings
13
+ @wells = wells
14
+ @plate = plate
15
+ end
16
+
17
+ def values
18
+ wells.map(&plate_wells.method(:values))
19
+ end
20
+
21
+ def readings
22
+ @readings ||= wells.zip(values).map { |well, v| Readings.new(well, v) }
10
23
  end
11
24
 
12
25
  def mean
13
- @mean ||= Readings.mean(*readings)
26
+ @mean ||= values.transpose.map(&ComputeMean)
14
27
  end
15
28
  end
16
29
  end
@@ -1,7 +1,7 @@
1
1
  require "active_support/core_ext"
2
2
 
3
3
  require "flex_station_data/services/parse_plate_readings"
4
- require "flex_station_data/services/parse_plate_samples"
4
+ require "flex_station_data/services/parse_sample_map"
5
5
  require "flex_station_data/plate"
6
6
 
7
7
  module FlexStationData
@@ -16,13 +16,13 @@ module FlexStationData
16
16
  end
17
17
 
18
18
  def data_blocks
19
- plate_data.split { |row| row[0] == "~End" }
19
+ plate_data.split { |row| row[0] =~ /\A~End\s*\z/ }
20
20
  end
21
21
 
22
22
  def call
23
23
  times, temperatures, wells = ParsePlateReadings.call(data_blocks[0])
24
- samples = ParsePlateSamples.call(data_blocks[1], wells)
25
- Plate.new(label, times, temperatures, samples)
24
+ sample_map = ParseSampleMap.call(data_blocks[1])
25
+ Plate.new(label, times, temperatures, wells, sample_map)
26
26
  end
27
27
  end
28
28
  end
@@ -1,4 +1,5 @@
1
1
  require "active_support/core_ext"
2
+ require "matrix"
2
3
 
3
4
  require "flex_station_data/wells"
4
5
  require "flex_station_data/concerns/service"
@@ -13,45 +14,31 @@ module FlexStationData
13
14
  @plate_readings_block = plate_readings_block
14
15
  end
15
16
 
16
- def column_count
17
- @column_count ||= headers.reverse.drop_while(&:blank?).size
18
- end
19
-
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
17
+ def headers
18
+ @headers ||= plate_readings_block.first.reverse.drop_while(&:blank?).reverse
25
19
  end
26
20
 
27
- def parsed_columns
28
- @parsed_columns ||= parsed_rows.transpose
21
+ def matrix
22
+ @matrix ||= Matrix[
23
+ *plate_readings_block.drop(1).map { |row| parse_row(row[0...headers.size]) }.select { |row| row.any?(&:present?) }
24
+ ]
29
25
  end
30
26
 
31
27
  def times
32
- @times ||= parsed_columns[0].compact
28
+ @times ||= matrix.column(0).to_a.compact
33
29
  end
34
30
 
35
31
  def temperatures
36
- @temperatures ||= parsed_columns[1].compact
37
- end
38
-
39
- def values
40
- @values ||= parsed_columns.drop(2)
32
+ @temperatures ||= matrix.column(1).to_a.compact
41
33
  end
42
34
 
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
35
+ def wells_matrix
36
+ well_row_count = matrix.row_count / times.size
37
+ Matrix[*well_values.column_vectors.map { |col| col.to_a.each_slice(well_row_count).to_a.transpose }.transpose ]
51
38
  end
52
39
 
53
40
  def wells
54
- Wells.new(plate_readings_matrix)
41
+ Wells.new(wells_matrix)
55
42
  end
56
43
 
57
44
  def call
@@ -78,12 +65,8 @@ module FlexStationData
78
65
 
79
66
  private
80
67
 
81
- def headers
82
- plate_readings_block.first
83
- end
84
-
85
- def plate_readings_data
86
- @plate_readings_data ||= plate_readings_block.drop(1)
68
+ def well_values
69
+ matrix.minor(0..-1, 2..-1)
87
70
  end
88
71
 
89
72
  attr_reader :plate_readings_block
@@ -0,0 +1,50 @@
1
+ require "matrix"
2
+ require "active_support/core_ext"
3
+
4
+ require "flex_station_data/concerns/service"
5
+
6
+ module FlexStationData
7
+ class ParseSampleMap
8
+ include Concerns::Service
9
+
10
+ attr_reader :sample_map_block
11
+
12
+ def initialize(sample_map_block)
13
+ @sample_map_block = sample_map_block
14
+ end
15
+
16
+ def call
17
+ labels.zip(matrix.column(1).to_a.each_slice(wells_per_sample).to_a).to_h
18
+ end
19
+
20
+ private
21
+
22
+ def parse_row(row)
23
+ row.take(2).map(&:presence)
24
+ end
25
+
26
+ def empty_row?(row)
27
+ row.all?(&:blank?)
28
+ end
29
+
30
+ def sample_map_header?(row)
31
+ row[0] == "Sample"
32
+ end
33
+
34
+ def sample_map_rows
35
+ sample_map_block.map(&method(:parse_row)).split(&method(:sample_map_header?)).drop(1).first.split(&method(:empty_row?)).first
36
+ end
37
+
38
+ def matrix
39
+ @matrix ||= Matrix[*sample_map_rows]
40
+ end
41
+
42
+ def labels
43
+ @labels ||= matrix.column(0).to_a.compact
44
+ end
45
+
46
+ def wells_per_sample
47
+ matrix.row_count / labels.size
48
+ end
49
+ end
50
+ end
@@ -17,7 +17,7 @@ module FlexStationData
17
17
  end
18
18
 
19
19
  def call
20
- sample.readings.flat_map(&:values).map(&method(:value_quality)).uniq(&:to_s)
20
+ sample.values.flatten.map(&method(:value_quality)).uniq(&:to_s)
21
21
  end
22
22
  end
23
23
  end
@@ -1,6 +1,8 @@
1
1
  require "singleton"
2
2
  require "active_support/core_ext"
3
3
 
4
+ require "flex_station_data/concerns/service"
5
+
4
6
  module FlexStationData
5
7
  class ValueQuality
6
8
  include Concerns::Service
@@ -1,3 +1,3 @@
1
1
  module FlexStationData
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -1,29 +1,28 @@
1
- require "flex_station_data/readings"
1
+ require "matrix"
2
2
 
3
3
  module FlexStationData
4
4
  class Wells
5
- def initialize(plate_readings_matrix)
6
- @plate_readings_matrix = plate_readings_matrix
5
+ attr_reader :matrix
6
+
7
+ def initialize(matrix)
8
+ @matrix = matrix
7
9
  end
8
10
 
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
11
+ def values(well_label)
12
+ matrix[*coordinates(well_label)]
14
13
  end
15
14
 
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 ]
15
+ def coordinates(well_label)
16
+ coordinates_index[well_label] ||= begin
17
+ row, column = well_label.scan(/\A([A-Z])(\d+)\z/).first
18
+ [ row.ord - "A".ord, column.to_i - 1 ]
19
+ end
19
20
  end
20
21
 
21
22
  private
22
23
 
23
- def well_index
24
- @well_index ||= {}
24
+ def coordinates_index
25
+ @coordinates_index ||= {}
25
26
  end
26
-
27
- attr_reader :plate_readings_matrix
28
27
  end
29
28
  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.1
4
+ version: 0.3.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-27 00:00:00.000000000 Z
11
+ date: 2019-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -130,13 +130,12 @@ files:
130
130
  - lib/flex_station_data/presenters/plate_csv.rb
131
131
  - lib/flex_station_data/presenters/plates_csv.rb
132
132
  - lib/flex_station_data/presenters/sample_csv.rb
133
- - lib/flex_station_data/readings.rb
134
133
  - lib/flex_station_data/sample.rb
135
134
  - lib/flex_station_data/services/compute_mean.rb
136
135
  - lib/flex_station_data/services/load_plates.rb
137
136
  - lib/flex_station_data/services/parse_plate.rb
138
137
  - lib/flex_station_data/services/parse_plate_readings.rb
139
- - lib/flex_station_data/services/parse_plate_samples.rb
138
+ - lib/flex_station_data/services/parse_sample_map.rb
140
139
  - lib/flex_station_data/services/sample_quality.rb
141
140
  - lib/flex_station_data/services/value_quality.rb
142
141
  - lib/flex_station_data/version.rb
@@ -1,16 +0,0 @@
1
- require "flex_station_data/services/compute_mean"
2
-
3
- module FlexStationData
4
- class Readings
5
- attr_reader :label, :values
6
-
7
- def initialize(label, values)
8
- @label = label
9
- @values = values
10
- end
11
-
12
- def self.mean(*readings, label: "mean")
13
- new(label, readings.map(&:values).transpose.map(&ComputeMean))
14
- end
15
- end
16
- end
@@ -1,49 +0,0 @@
1
- require "flex_station_data/readings"
2
- require "flex_station_data/concerns/service"
3
-
4
- require "flex_station_data/sample"
5
-
6
- module FlexStationData
7
- class ParsePlateSamples
8
- include Concerns::Service
9
-
10
- def initialize(sample_map_block, wells)
11
- @sample_map_block = sample_map_block
12
- @wells = wells
13
- end
14
-
15
- def map_rows
16
- @map_rows ||= begin
17
- rows = sample_map_block.drop_while { |row| row[0] != "Sample" }.drop(1)
18
- rows = rows.map { |row| row.map(&:presence) }
19
- rows.take_while { |row| row.any?(&:present?) }.to_a
20
- end
21
- end
22
-
23
- def map_columns
24
- @map_columns ||= map_rows.transpose
25
- end
26
-
27
- def labels
28
- @labels ||= map_columns[0].compact
29
- end
30
-
31
- def wells_per_sample
32
- map_rows.size / labels.size
33
- end
34
-
35
- def sample_map
36
- @sample_map ||= map_columns[1].each_slice(wells_per_sample).to_a
37
- end
38
-
39
- def call
40
- labels.zip(sample_map).map do |label, well_labels|
41
- Sample.new(label, well_labels.map(&wells.method(:readings)))
42
- end
43
- end
44
-
45
- private
46
-
47
- attr_reader :sample_map_block, :wells
48
- end
49
- end