flex-station-data 0.3.2 → 1.0.0

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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +12 -0
  5. data/Gemfile.lock +1 -1
  6. data/README.md +16 -29
  7. data/bin/flex-station-linear-regression +7 -29
  8. data/flex-station-data.gemspec +1 -1
  9. data/lib/flex_station_data/default_sample_map.rb +31 -0
  10. data/lib/flex_station_data/presenters/plate_hash.rb +24 -0
  11. data/lib/flex_station_data/presenters/plates_hash.rb +24 -0
  12. data/lib/flex_station_data/presenters/sample_hash.rb +45 -0
  13. data/lib/flex_station_data/presenters/sample_regression_hash.rb +42 -0
  14. data/lib/flex_station_data/services/load_plates.rb +10 -1
  15. data/lib/flex_station_data/services/parse_plate_readings.rb +34 -14
  16. data/lib/flex_station_data/services/parse_sample_map.rb +16 -21
  17. data/lib/flex_station_data/services/sample_quality.rb +3 -4
  18. data/lib/flex_station_data/services/value_quality.rb +1 -1
  19. data/lib/flex_station_data/version.rb +1 -1
  20. metadata +11 -14
  21. data/bin/flex-station-sample-data +0 -54
  22. data/lib/flex_station_data/presenters/linear_regression/plate_hash.rb +0 -27
  23. data/lib/flex_station_data/presenters/linear_regression/plates_hash.rb +0 -28
  24. data/lib/flex_station_data/presenters/linear_regression/sample_hash.rb +0 -47
  25. data/lib/flex_station_data/presenters/linear_regression/sample_regression_hash.rb +0 -43
  26. data/lib/flex_station_data/presenters/linear_regression/verbose_sample_csv.rb +0 -28
  27. data/lib/flex_station_data/presenters/plate_csv.rb +0 -34
  28. data/lib/flex_station_data/presenters/plates_csv.rb +0 -33
  29. data/lib/flex_station_data/presenters/sample_csv.rb +0 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d58049eac2b497f587a9e2b467eb09ada8fe9582c3dced6985aa59f26cbe58b
4
- data.tar.gz: 6154e1b4930afde05d7449df4ce0ebfce74e92d0651944d163cb4664e6c880f6
3
+ metadata.gz: 6814ca0e722e1da44873ec3cd5571864984f028be6bb098a548dc6b5a21af430
4
+ data.tar.gz: cf535779a83284369d3a406590edd9a055e53cbc24fdcb49384f8445e829f170
5
5
  SHA512:
6
- metadata.gz: 0307a6c1f8cff75dba0fb93ec17b2b49ec59db99cf1d5c18d487b40d2451695bc92fcbf911f1cba2e85fe859ccc2bd107537f6422eb1a14f0a9f5c684ac735a3
7
- data.tar.gz: ff7e2b5c8d363aae425010d47e7e531028ae122772be9db1098f46113f28e1d04ffd6df065000ea69c21b138342071cfc4f618638754bffb7d9353bbb172252c
6
+ metadata.gz: 1ca3cbaa108a9bc868da418ad3c8393508b3ebe8e20db5a1a16427e5426981c07f3232329c3469f61cb2694feb08c8ded37225ed47af7dc0544b8c65941c6a68
7
+ data.tar.gz: dc49217f185e779075f9f11aa7f2ec85cf958d18644383fdb01ea7827cdce64ab5c5aead16ee3c4148b82a9377de2ef71eaf47497e61e6b9323ff2a20a7b29e4
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ .idea/
@@ -0,0 +1 @@
1
+ 2.5.6
@@ -1,3 +1,15 @@
1
+ # 1.0.0
2
+
3
+ * Removed option for sample data report and verbose linear regression report.
4
+
5
+ # 0.3.2
6
+
7
+ * Internal refactoring
8
+
9
+ # 0.3.1
10
+
11
+ * Fixed bug
12
+
1
13
  # 0.3.0
2
14
 
3
15
  * The linear regression analysis report now produces a summary report of the
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- flex-station-data (0.3.2)
4
+ flex-station-data (1.0.0)
5
5
  activesupport
6
6
  linefit
7
7
 
data/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  Tools for reading and analyzing data from the FlexStation microplate reader.
4
4
 
5
- Currently this is somewhere between alpha and beta.
6
-
7
5
  ## Installation
8
6
 
9
7
  Add this line to your application's Gemfile:
@@ -28,51 +26,40 @@ To update your installation, use:
28
26
 
29
27
  ## Usage
30
28
 
31
- ### Viewing the sample data
32
-
33
- To view the sample results from a set of plate readings, use the following
29
+ To perform a linear regression analysis on the sample data, use the following
34
30
  command:
35
31
 
36
- $ flex-station sample-data <source file> [--threshold=<threshold>]
32
+ $ flex-station linear-regression <source file> [--threshold=<threshold>] [--min-r-squared=<minimum R²>]
37
33
 
38
34
  Where `source file` is the file that you got from the reader. You can specify
39
35
  multiple source files. The `threshold` setting is optional. If provided,
40
36
  samples with values that are below the `threshold` value will be skipped.
41
37
  `threshold` must be a number.
42
38
 
39
+ If a `--min-r-squared` value is given, samples with a R² value that falls
40
+ below the threshold will be flagged as "poor fits." If no `--min-r-squared` is
41
+ specified, a default of 0.75 will be used.
42
+
43
43
  The output is in CSV format. You'll probably want to save it to a file. You
44
44
  can do that by piping the output to a file:
45
45
 
46
- $ flex-station sample-data source-data.csv --threshold=300 > sample-data.csv
47
-
48
- ### Performing linear regression analysis on the sample data
49
-
50
- To perform a linear regression analysis on the sample data, use the following
51
- command:
52
-
53
- $ flex-station-data linear-regression <source file> [--threshold=<threshold>] [--verbose] [--min-r-squared=<mininmum R²>]
54
-
55
- Note that the `source file` and `threshold` options are the same as for the
56
- `sample-data` command above. If a `--min-r-squared` value is given, samples
57
- with a R² value that falls below the threshold will be flagged as "poor fits."
58
- If no `--min-r-squared` is specified, a default of 0.75 will be used.
59
-
60
- By default the linear regression tool will produce a summary report giving the
61
- slope, intercept, and R² values for each sample. However if `--verbose` is
62
- specified, it will also include the sample data and regressions for each well.
63
-
64
- As with the sample data tool, you will probably want to pipe the output to a file:
65
-
66
46
  $ flex-station linear-regression source-data.csv --threshold=300 > linear-regression.csv
67
47
 
68
48
  ## Contributing
69
49
 
70
- Bug reports and pull requests are welcome on GitHub at https://github.com/johncarney/flex-station-data. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
50
+ Bug reports and pull requests are welcome on GitHub at
51
+ https://github.com/johncarney/flex-station-data. This project is intended to
52
+ be a safe, welcoming space for collaboration, and contributors are expected to
53
+ adhere to the [Contributor Covenant](http://contributor-covenant.org) code of
54
+ conduct.
71
55
 
72
56
  ## License
73
57
 
74
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
58
+ The gem is available as open source under the terms of the
59
+ [MIT License](https://opensource.org/licenses/MIT).
75
60
 
76
61
  ## Code of Conduct
77
62
 
78
- Everyone interacting in the FlexStationData project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/johncarney/flex-station-data/blob/master/CODE_OF_CONDUCT.md).
63
+ Everyone interacting in the FlexStationData project’s codebases, issue
64
+ trackers, chat rooms and mailing lists is expected to follow the
65
+ [code of conduct](https://github.com/johncarney/flex-station-data/blob/master/CODE_OF_CONDUCT.md).
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "flex_station_data/services/load_plates"
4
- require "flex_station_data/presenters/plates_csv"
5
- require "flex_station_data/presenters/linear_regression/plates_hash"
6
- require "flex_station_data/presenters/linear_regression/verbose_sample_csv"
4
+ require "flex_station_data/presenters/plates_hash"
7
5
 
8
6
  module FlexStationData
9
7
  class LinearRegressionApp
@@ -31,10 +29,6 @@ module FlexStationData
31
29
  Float(option(:threshold)) rescue nil
32
30
  end
33
31
 
34
- def verbose?
35
- option(:verbose)
36
- end
37
-
38
32
  def min_r_squared
39
33
  Float(option("min-r-squared")) rescue 0.75
40
34
  end
@@ -49,21 +43,9 @@ module FlexStationData
49
43
  end
50
44
  end
51
45
 
52
- def verbose_csv
46
+ def plate_hashes
53
47
  plates.flat_map do |file, file_plates|
54
- Presenters::PlatesCsv.present(
55
- file,
56
- file_plates,
57
- sample_presenter: Presenters::LinearRegression::VerboseSampleCsv,
58
- threshold: threshold,
59
- min_r_squared: min_r_squared
60
- )
61
- end
62
- end
63
-
64
- def summary_hashes
65
- plates.flat_map do |file, file_plates|
66
- Presenters::LinearRegression::PlatesHash.present(
48
+ Presenters::PlatesHash.present(
67
49
  file,
68
50
  file_plates,
69
51
  threshold: threshold,
@@ -78,9 +60,9 @@ module FlexStationData
78
60
  end
79
61
  end
80
62
 
81
- def summary_hash
82
- @summary_hash ||= begin
83
- result = summary_hashes.each_with_object({}) do |hash, memo|
63
+ def hash
64
+ @hash ||= begin
65
+ result = plate_hashes.each_with_object({}) do |hash, memo|
84
66
  hash.each do |header, value|
85
67
  memo[header] ||= []
86
68
  memo[header] << value
@@ -92,12 +74,8 @@ module FlexStationData
92
74
  end
93
75
  end
94
76
 
95
- def summary_csv
96
- [ summary_hash.keys, *summary_hash.values.transpose ]
97
- end
98
-
99
77
  def csv
100
- verbose? ? verbose_csv : summary_csv
78
+ [ hash.keys, *hash.values.transpose ]
101
79
  end
102
80
 
103
81
  def call
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ["lib"]
30
30
 
31
- spec.required_ruby_version = ">= 2.4.4"
31
+ spec.required_ruby_version = ">= 2.5.6"
32
32
 
33
33
  spec.add_development_dependency "bundler", "~> 2.0"
34
34
  spec.add_development_dependency "rake", "~> 10.0"
@@ -0,0 +1,31 @@
1
+ module FlexStationData
2
+ class DefaultSampleMap
3
+ attr_reader :rows, :columns, :wells_per_sample
4
+
5
+ def initialize(rows, columns, wells_per_sample)
6
+ @rows = rows
7
+ @columns = columns
8
+ @wells_per_sample = wells_per_sample
9
+ end
10
+
11
+ def [](sample_label)
12
+ sample_label = Integer(sample_label)
13
+ map[sample_label] ||= map_sample(sample_label)
14
+ end
15
+
16
+ private
17
+
18
+ def map_sample(sample_label)
19
+ column, row = (sample_label - 1).divmod(rows)
20
+ row_label = ("A".ord + row).chr
21
+ base_column = (column * wells_per_sample) + 1
22
+ (0...wells_per_sample).map do |column_offset|
23
+ [ row_label, base_column +column_offset ].join("")
24
+ end
25
+ end
26
+
27
+ def map
28
+ @map ||= {}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ require "flex_station_data/presenters/sample_hash"
2
+
3
+ module FlexStationData
4
+ module Presenters
5
+ class PlateHash
6
+ include Concerns::Presenter
7
+
8
+ attr_reader :plate, :options
9
+
10
+ delegate :times, :samples, to: :plate
11
+
12
+ def initialize(plate, **options)
13
+ @plate = plate
14
+ @options = options
15
+ end
16
+
17
+ def present
18
+ samples.map do |sample|
19
+ { "plate" => plate.label }.merge(SampleHash.present(times, sample, **options))
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require "flex_station_data/presenters/plate_hash"
2
+
3
+ module FlexStationData
4
+ module Presenters
5
+ class PlatesHash
6
+ include Concerns::Presenter
7
+
8
+ attr_reader :file, :plates, :options
9
+
10
+ def initialize(file, plates, **options)
11
+ @file = file
12
+ @plates = plates
13
+ @options = options
14
+ end
15
+
16
+ def present
17
+ base = { "file" => file.basename.to_s }
18
+ plates.flat_map do |plate|
19
+ PlateHash.present(plate, **options).map(&base.method(:merge))
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,45 @@
1
+ require "flex_station_data/concerns/presenter"
2
+ require "flex_station_data/services/sample_quality"
3
+ require "flex_station_data/presenters/sample_regression_hash"
4
+
5
+ module FlexStationData
6
+ module Presenters
7
+ class SampleHash
8
+ include Concerns::Presenter
9
+
10
+ attr_reader :times, :sample, :quality_control, :options
11
+
12
+ def initialize(times, sample, **options)
13
+ @times = times
14
+ @sample = sample
15
+ @options = options
16
+ end
17
+
18
+ def errors
19
+ @errors ||= SampleQuality.call(sample, **options).reject(&:good?)
20
+ end
21
+
22
+ def errors?
23
+ errors.present?
24
+ end
25
+
26
+ def errors_hash
27
+ { "error" => errors.first&.to_s }
28
+ end
29
+
30
+ def wells_hash
31
+ { "wells" => sample.wells.join(", ") }
32
+ end
33
+
34
+ def regression_hash
35
+ return SampleRegressionHash.headers.zip([]).to_h if errors?
36
+
37
+ SampleRegressionHash.present(times, sample.mean, **options).transform_values(&:first)
38
+ end
39
+
40
+ def present
41
+ { "sample" => sample.label }.merge(wells_hash).merge(errors_hash).merge(regression_hash)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,42 @@
1
+ require "flex_station_data/concerns/presenter"
2
+ require "flex_station_data/linear_regression"
3
+
4
+ module FlexStationData
5
+ module Presenters
6
+ class SampleRegressionHash
7
+ include Concerns::Presenter
8
+
9
+ PRODUCTS = {
10
+ slope: "slope",
11
+ intercept: "intercept",
12
+ r_squared: "R²",
13
+ quality: "quality"
14
+ }.freeze
15
+
16
+ attr_reader :times, :sample_values, :min_r_squared, :options
17
+
18
+ def initialize(times, *sample_values, min_r_squared: nil, **options)
19
+ @times = times
20
+ @sample_values = sample_values
21
+ @min_r_squared = min_r_squared
22
+ @options = options
23
+ end
24
+
25
+ def sample_regressions
26
+ @sample_regressions ||= sample_values.map do |values|
27
+ FlexStationData::LinearRegression.new(times, values, min_r_squared: min_r_squared)
28
+ end
29
+ end
30
+
31
+ def present
32
+ PRODUCTS.each_with_object({}) do |(method, label), memo|
33
+ memo[label] = sample_regressions.map(&method)
34
+ end
35
+ end
36
+
37
+ def self.headers
38
+ PRODUCTS.values
39
+ end
40
+ end
41
+ end
42
+ end
@@ -18,7 +18,10 @@ module FlexStationData
18
18
  end
19
19
 
20
20
  def data_blocks
21
- @data_blocks ||= data.split { |row| row[0] == "Plate:" }.drop(1)
21
+ @data_blocks ||= data.each_with_object([]) do |row, blocks|
22
+ blocks << [] if plate_row?(row)
23
+ blocks.last&.push(row)
24
+ end
22
25
  end
23
26
 
24
27
  def call
@@ -26,5 +29,11 @@ module FlexStationData
26
29
  FlexStationData::ParsePlate.call(index + 1, data_block)
27
30
  end
28
31
  end
32
+
33
+ private
34
+
35
+ def plate_row?(row)
36
+ row[0].to_s =~ /\A\s*Plate:\s*/i
37
+ end
29
38
  end
30
39
  end
@@ -10,18 +10,20 @@ module FlexStationData
10
10
 
11
11
  delegate :parse_time, :parse_value, :parse_row, to: :class
12
12
 
13
- def initialize(plate_readings_block)
14
- @plate_readings_block = plate_readings_block
13
+ def initialize(plate_data)
14
+ @plate_data = plate_data
15
15
  end
16
16
 
17
- def headers
18
- @headers ||= plate_readings_block.first.reverse.drop_while(&:blank?).reverse
17
+ def readings_block
18
+ @readings_block ||= plate_data
19
+ .drop_while { |row| !header_row?(row) }
20
+ .drop_while { |row| !sample_row?(row) }
21
+ .take_while { |row| !end_row?(row) }
22
+ .select { |row| row.any?(&:present?) }
19
23
  end
20
24
 
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
- ]
25
+ def headers
26
+ @headers ||= plate_data.detect(&method(:header_row?)).reverse.drop_while(&:blank?).reverse
25
27
  end
26
28
 
27
29
  def times
@@ -32,11 +34,6 @@ module FlexStationData
32
34
  @temperatures ||= matrix.column(1).to_a.compact
33
35
  end
34
36
 
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 ]
38
- end
39
-
40
37
  def wells
41
38
  Wells.new(wells_matrix)
42
39
  end
@@ -65,10 +62,33 @@ module FlexStationData
65
62
 
66
63
  private
67
64
 
65
+ def header_row?(row)
66
+ row[1].to_s =~ /\A\s*Temperature\b/i
67
+ end
68
+
69
+ def sample_row?(row)
70
+ row[0].to_s =~ /\A\s*\d+:\d+:\d+\s*\z/
71
+ end
72
+
73
+ def end_row?(row)
74
+ row[0].to_s =~ /\A\s*~End\s*\z/i
75
+ end
76
+
68
77
  def well_values
69
78
  matrix.minor(0..-1, 2..-1)
70
79
  end
71
80
 
72
- attr_reader :plate_readings_block
81
+ def matrix
82
+ @matrix ||= Matrix[
83
+ *readings_block.map { |row| parse_row(row[0...headers.size]) }
84
+ ]
85
+ end
86
+
87
+ def wells_matrix
88
+ well_row_count = matrix.row_count / times.size
89
+ Matrix[*well_values.column_vectors.map { |col| col.to_a.each_slice(well_row_count).to_a.transpose }.transpose ]
90
+ end
91
+
92
+ attr_reader :plate_data
73
93
  end
74
94
  end
@@ -7,14 +7,25 @@ module FlexStationData
7
7
  class ParseSampleMap
8
8
  include Concerns::Service
9
9
 
10
- attr_reader :sample_map_block
10
+ attr_reader :plate_data
11
11
 
12
- def initialize(sample_map_block)
13
- @sample_map_block = sample_map_block
12
+ def initialize(plate_data)
13
+ @plate_data = plate_data
14
+ end
15
+
16
+ def sample_map_rows
17
+ plate_data
18
+ .drop_while { |row| !sample_map_header?(row) }
19
+ .drop(1)
20
+ .take_while { |row| !empty_row?(row) }
21
+ .map(&method(:parse_row))
14
22
  end
15
23
 
16
24
  def call
17
- labels.zip(matrix.column(1).to_a.each_slice(wells_per_sample).to_a).to_h
25
+ sample_map_rows.each_with_object([]) do |(label, well), memo|
26
+ memo << [ label, [] ] if label.present?
27
+ memo.last.last << well
28
+ end.to_h
18
29
  end
19
30
 
20
31
  private
@@ -28,23 +39,7 @@ module FlexStationData
28
39
  end
29
40
 
30
41
  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
42
+ row[0].to_s =~ /\A\s*Sample\s*\z/i && row[1].to_s =~ /\A\s*Wells\s*\z/i
48
43
  end
49
44
  end
50
45
  end
@@ -4,16 +4,15 @@ module FlexStationData
4
4
  class SampleQuality
5
5
  include Concerns::Service
6
6
 
7
- attr_reader :sample, :value_quality_control, :options
7
+ attr_reader :sample, :options
8
8
 
9
- def initialize(sample, value_quality_control: ValueQuality, **options)
9
+ def initialize(sample, **options)
10
10
  @sample = sample
11
- @value_quality_control = value_quality_control
12
11
  @options = options
13
12
  end
14
13
 
15
14
  def value_quality(value)
16
- value_quality_control.call(value, **options)
15
+ ValueQuality.call(value, **options)
17
16
  end
18
17
 
19
18
  def call
@@ -23,7 +23,7 @@ module FlexStationData
23
23
  attr_reader :description
24
24
 
25
25
  def initialize(description)
26
- @description ||= description
26
+ @description = description
27
27
  end
28
28
 
29
29
  def good?
@@ -1,3 +1,3 @@
1
1
  module FlexStationData
2
- VERSION = "0.3.2"
2
+ VERSION = "1.0.0"
3
3
  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.2
4
+ version: 1.0.0
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-28 00:00:00.000000000 Z
11
+ date: 2019-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,12 +100,12 @@ email:
100
100
  executables:
101
101
  - flex-station
102
102
  - flex-station-linear-regression
103
- - flex-station-sample-data
104
103
  extensions: []
105
104
  extra_rdoc_files: []
106
105
  files:
107
106
  - ".gitignore"
108
107
  - ".rspec"
108
+ - ".ruby-version"
109
109
  - CHANGELOG.md
110
110
  - CODE_OF_CONDUCT.md
111
111
  - Gemfile
@@ -115,21 +115,17 @@ files:
115
115
  - Rakefile
116
116
  - bin/flex-station
117
117
  - bin/flex-station-linear-regression
118
- - bin/flex-station-sample-data
119
118
  - flex-station-data.gemspec
120
119
  - lib/flex_station_data.rb
121
120
  - lib/flex_station_data/concerns/presenter.rb
122
121
  - lib/flex_station_data/concerns/service.rb
122
+ - lib/flex_station_data/default_sample_map.rb
123
123
  - lib/flex_station_data/linear_regression.rb
124
124
  - 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
125
+ - lib/flex_station_data/presenters/plate_hash.rb
126
+ - lib/flex_station_data/presenters/plates_hash.rb
127
+ - lib/flex_station_data/presenters/sample_hash.rb
128
+ - lib/flex_station_data/presenters/sample_regression_hash.rb
133
129
  - lib/flex_station_data/sample.rb
134
130
  - lib/flex_station_data/services/compute_mean.rb
135
131
  - lib/flex_station_data/services/load_plates.rb
@@ -154,14 +150,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
150
  requirements:
155
151
  - - ">="
156
152
  - !ruby/object:Gem::Version
157
- version: 2.4.4
153
+ version: 2.5.6
158
154
  required_rubygems_version: !ruby/object:Gem::Requirement
159
155
  requirements:
160
156
  - - ">="
161
157
  - !ruby/object:Gem::Version
162
158
  version: '0'
163
159
  requirements: []
164
- rubygems_version: 3.0.3
160
+ rubyforge_project:
161
+ rubygems_version: 2.7.6.2
165
162
  signing_key:
166
163
  specification_version: 4
167
164
  summary: Data analysis tool for FlexStation microplate reader
@@ -1,54 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "flex_station_data/services/load_plates"
4
- require "flex_station_data/presenters/plates_csv"
5
-
6
- module FlexStationData
7
- class SampleDataApp
8
- include Concerns::Service
9
-
10
- OPTION_RE = /\A--(\w+(?:-\w+)*)(?:=(.*))?\z/.freeze
11
-
12
- attr_reader :args, :options
13
-
14
- def initialize(*args)
15
- @options, @args = args.partition { |arg| arg =~ OPTION_RE }
16
- @options.map! do |option|
17
- option.scan(OPTION_RE).first
18
- end
19
- end
20
-
21
- def threshold
22
- name, value = options.reverse.detect { |name, value| name == "threshold" }
23
- return nil if name.blank?
24
-
25
- Float(value)
26
- end
27
-
28
- def files
29
- @files ||= args.map { |arg| Pathname(arg) }
30
- end
31
-
32
- def plates
33
- @plates ||= files.map do |file|
34
- [ file, LoadPlates.call(file) ]
35
- end
36
- end
37
-
38
- def csv
39
- plates.flat_map do |file, file_plates|
40
- Presenters::PlatesCsv.present(file, file_plates, threshold: threshold)
41
- end
42
- end
43
-
44
- def call
45
- CSV do |out|
46
- csv.each do |row|
47
- out << row
48
- end
49
- end
50
- end
51
- end
52
- end
53
-
54
- FlexStationData::SampleDataApp.call(*ARGV)
@@ -1,27 +0,0 @@
1
- require "flex_station_data/presenters/linear_regression/sample_hash"
2
-
3
- module FlexStationData
4
- module Presenters
5
- module LinearRegression
6
- class PlateHash
7
- include Concerns::Presenter
8
-
9
- attr_reader :plate, :sample_presenter, :options
10
-
11
- delegate :times, :samples, to: :plate
12
-
13
- def initialize(plate, sample_presenter: SampleHash, **options)
14
- @plate = plate
15
- @sample_presenter = sample_presenter
16
- @options = options
17
- end
18
-
19
- def present
20
- samples.map do |sample|
21
- { "plate" => plate.label }.merge(sample_presenter.present(times, sample, **options))
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,28 +0,0 @@
1
- require "flex_station_data/presenters/linear_regression/plate_hash"
2
-
3
- module FlexStationData
4
- module Presenters
5
- module LinearRegression
6
- class PlatesHash
7
- include Concerns::Presenter
8
-
9
- attr_reader :file, :plates, :plate_presenter, :options
10
-
11
- def initialize(file, plates, plate_presenter: PlateHash, **options)
12
- @file = file
13
- @plates = plates
14
- @plate_presenter = plate_presenter
15
- @options = options
16
- end
17
-
18
- def present
19
- plates.flat_map do |plate|
20
- plate_presenter.present(plate, **options).map do |plate_hash|
21
- { "file" => file.basename.to_s }.merge(plate_hash)
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,47 +0,0 @@
1
- require "flex_station_data/presenters/sample_csv"
2
- require "flex_station_data/presenters/linear_regression/sample_regression_hash"
3
-
4
- module FlexStationData
5
- module Presenters
6
- module LinearRegression
7
- class SampleHash
8
- include Concerns::Presenter
9
-
10
- attr_reader :times, :sample, :quality_control, :options
11
-
12
- def initialize(times, sample, quality_control: SampleQuality, **options)
13
- @times = times
14
- @sample = sample
15
- @quality_control = quality_control
16
- @options = options
17
- end
18
-
19
- def errors
20
- @errors ||= quality_control.call(sample, **options).reject(&:good?)
21
- end
22
-
23
- def errors?
24
- errors.present?
25
- end
26
-
27
- def errors_hash
28
- { "error" => errors.first&.to_s }
29
- end
30
-
31
- def wells_hash
32
- { "wells" => sample.wells.join(", ") }
33
- end
34
-
35
- def regression_hash
36
- return SampleRegressionHash.headers.zip([]).to_h if errors?
37
-
38
- SampleRegressionHash.present(times, sample.mean, **options).transform_values(&:first)
39
- end
40
-
41
- def present
42
- { "sample" => sample.label }.merge(wells_hash).merge(errors_hash).merge(regression_hash)
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,43 +0,0 @@
1
- require "flex_station_data/linear_regression"
2
-
3
- module FlexStationData
4
- module Presenters
5
- module LinearRegression
6
- class SampleRegressionHash
7
- include Concerns::Presenter
8
-
9
- PRODUCTS = {
10
- slope: "slope",
11
- intercept: "intercept",
12
- r_squared: "R²",
13
- quality: "quality"
14
- }.freeze
15
-
16
- attr_reader :times, :sample_values, :min_r_squared, :options
17
-
18
- def initialize(times, *sample_values, min_r_squared: nil, **options)
19
- @times = times
20
- @sample_values = sample_values
21
- @min_r_squared = min_r_squared
22
- @options = options
23
- end
24
-
25
- def sample_regressions
26
- @sample_regressions ||= sample_values.map do |values|
27
- FlexStationData::LinearRegression.new(times, values, min_r_squared: min_r_squared)
28
- end
29
- end
30
-
31
- def present
32
- PRODUCTS.each_with_object({}) do |(method, label), memo|
33
- memo[label] = sample_regressions.map(&method)
34
- end
35
- end
36
-
37
- def self.headers
38
- PRODUCTS.values
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,28 +0,0 @@
1
- require "flex_station_data/presenters/sample_csv"
2
- require "flex_station_data/presenters/linear_regression/sample_regression_hash"
3
-
4
- module FlexStationData
5
- module Presenters
6
- module LinearRegression
7
- class VerboseSampleCsv < Presenters::SampleCsv
8
- include Concerns::Presenter
9
-
10
- def sample_values
11
- [ *sample.values, sample.mean ]
12
- end
13
-
14
- def regressions_hash
15
- SampleRegressionHash.present(times, *sample_values, **options)
16
- end
17
-
18
- def regressions_csv
19
- regressions_hash.to_a.map(&:flatten)
20
- end
21
-
22
- def values_csv
23
- super + regressions_csv
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,34 +0,0 @@
1
- require "flex_station_data/presenters/sample_csv"
2
-
3
- module FlexStationData
4
- module Presenters
5
- class PlateCsv
6
- include Concerns::Presenter
7
-
8
- attr_reader :plate, :sample_presenter, :options
9
-
10
- delegate :times, :samples, to: :plate
11
-
12
- def initialize(plate, sample_presenter: SampleCsv, **options)
13
- @plate = plate
14
- @sample_presenter = sample_presenter
15
- @options = options
16
- end
17
-
18
- def present
19
- [
20
- [ "Plate #{plate.label}" ],
21
- *samples_csv
22
- ]
23
- end
24
-
25
- private
26
-
27
- def samples_csv
28
- samples.flat_map do |sample|
29
- sample_presenter.present(times, sample, **options)
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,33 +0,0 @@
1
- require "flex_station_data/presenters/plate_csv"
2
-
3
- module FlexStationData
4
- module Presenters
5
- class PlatesCsv
6
- include Concerns::Presenter
7
-
8
- attr_reader :file, :plates, :plate_presenter, :options
9
-
10
- def initialize(file, plates, plate_presenter: PlateCsv, **options)
11
- @file = file
12
- @plates = plates
13
- @plate_presenter = plate_presenter
14
- @options = options
15
- end
16
-
17
- def present
18
- [
19
- [ "File: #{file.basename.to_path}" ],
20
- *plates_csv
21
- ]
22
- end
23
-
24
- private
25
-
26
- def plates_csv
27
- plates.flat_map do |plate|
28
- plate_presenter.present(plate, **options)
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,61 +0,0 @@
1
- require "flex_station_data/concerns/presenter"
2
- require "flex_station_data/services/sample_quality"
3
-
4
- module FlexStationData
5
- module Presenters
6
- class SampleCsv
7
- include Concerns::Presenter
8
-
9
- attr_reader :times, :sample, :quality_control, :options
10
-
11
- def initialize(times, sample, quality_control: SampleQuality, **options)
12
- @times = times
13
- @sample = sample
14
- @quality_control = quality_control
15
- @options = options
16
- end
17
-
18
- def errors
19
- @errors ||= quality_control.call(sample, **options).reject(&:good?)
20
- end
21
-
22
- def present
23
- [
24
- [ label ],
25
- *body_csv,
26
- [ ]
27
- ]
28
- end
29
-
30
- private
31
-
32
- def label
33
- "Sample #{sample.label}"
34
- end
35
-
36
- def errors?
37
- errors.present?
38
- end
39
-
40
- def errors_csv
41
- errors.map(&:to_s).map(&method(:Array))
42
- end
43
-
44
- def headers
45
- [ "time", *sample.wells, "mean" ]
46
- end
47
-
48
- def values
49
- [ times, *sample.values, sample.mean ]
50
- end
51
-
52
- def values_csv
53
- [ headers, *values.transpose ]
54
- end
55
-
56
- def body_csv
57
- errors? ? errors_csv : values_csv
58
- end
59
- end
60
- end
61
- end