flex-station-data 0.3.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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