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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/flex_station_data/plate.rb +12 -3
- data/lib/flex_station_data/presenters/linear_regression/sample_hash.rb +2 -2
- data/lib/flex_station_data/presenters/linear_regression/verbose_sample_csv.rb +1 -1
- data/lib/flex_station_data/presenters/plate_csv.rb +9 -4
- data/lib/flex_station_data/presenters/plates_csv.rb +9 -4
- data/lib/flex_station_data/presenters/sample_csv.rb +20 -15
- data/lib/flex_station_data/sample.rb +18 -5
- data/lib/flex_station_data/services/parse_plate.rb +4 -4
- data/lib/flex_station_data/services/parse_plate_readings.rb +15 -32
- data/lib/flex_station_data/services/parse_sample_map.rb +50 -0
- data/lib/flex_station_data/services/sample_quality.rb +1 -1
- data/lib/flex_station_data/services/value_quality.rb +2 -0
- data/lib/flex_station_data/version.rb +1 -1
- data/lib/flex_station_data/wells.rb +14 -15
- metadata +3 -4
- data/lib/flex_station_data/readings.rb +0 -16
- data/lib/flex_station_data/services/parse_plate_samples.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d58049eac2b497f587a9e2b467eb09ada8fe9582c3dced6985aa59f26cbe58b
|
4
|
+
data.tar.gz: 6154e1b4930afde05d7449df4ce0ebfce74e92d0651944d163cb4664e6c880f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0307a6c1f8cff75dba0fb93ec17b2b49ec59db99cf1d5c18d487b40d2451695bc92fcbf911f1cba2e85fe859ccc2bd107537f6422eb1a14f0a9f5c684ac735a3
|
7
|
+
data.tar.gz: ff7e2b5c8d363aae425010d47e7e531028ae122772be9db1098f46113f28e1d04ffd6df065000ea69c21b138342071cfc4f618638754bffb7d9353bbb172252c
|
data/Gemfile.lock
CHANGED
@@ -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, :
|
5
|
+
attr_reader :label, :times, :temperatures, :wells, :sample_map
|
4
6
|
|
5
|
-
def initialize(label, times, temperatures,
|
7
|
+
def initialize(label, times, temperatures, wells, sample_map)
|
6
8
|
@label = label
|
7
9
|
@times = times
|
8
10
|
@temperatures = temperatures
|
9
|
-
@
|
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.
|
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
|
38
|
+
SampleRegressionHash.present(times, sample.mean, **options).transform_values(&:first)
|
39
39
|
end
|
40
40
|
|
41
41
|
def present
|
@@ -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
|
20
|
-
@
|
18
|
+
def errors
|
19
|
+
@errors ||= quality_control.call(sample, **options).reject(&:good?)
|
21
20
|
end
|
22
21
|
|
23
|
-
def
|
24
|
-
|
22
|
+
def present
|
23
|
+
[
|
24
|
+
[ label ],
|
25
|
+
*body_csv,
|
26
|
+
[ ]
|
27
|
+
]
|
25
28
|
end
|
26
29
|
|
27
|
-
|
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, *
|
53
|
+
[ headers, *values.transpose ]
|
49
54
|
end
|
50
55
|
|
51
|
-
def
|
52
|
-
|
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 "
|
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, :
|
7
|
+
attr_reader :label, :wells, :plate
|
8
|
+
|
9
|
+
delegate :wells, to: :plate, prefix: true
|
6
10
|
|
7
|
-
def initialize(label,
|
11
|
+
def initialize(label, wells, plate)
|
8
12
|
@label = label
|
9
|
-
@
|
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 ||=
|
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/
|
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]
|
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
|
-
|
25
|
-
Plate.new(label, times, temperatures,
|
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
|
17
|
-
@
|
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
|
28
|
-
@
|
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 ||=
|
28
|
+
@times ||= matrix.column(0).to_a.compact
|
33
29
|
end
|
34
30
|
|
35
31
|
def temperatures
|
36
|
-
@temperatures ||=
|
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
|
44
|
-
|
45
|
-
|
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(
|
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
|
82
|
-
|
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
|
@@ -1,29 +1,28 @@
|
|
1
|
-
require "
|
1
|
+
require "matrix"
|
2
2
|
|
3
3
|
module FlexStationData
|
4
4
|
class Wells
|
5
|
-
|
6
|
-
|
5
|
+
attr_reader :matrix
|
6
|
+
|
7
|
+
def initialize(matrix)
|
8
|
+
@matrix = matrix
|
7
9
|
end
|
8
10
|
|
9
|
-
def
|
10
|
-
|
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
|
17
|
-
|
18
|
-
|
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
|
24
|
-
@
|
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.
|
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-
|
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/
|
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
|