macroape 3.2.2 → 3.3.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 (37) hide show
  1. data/Rakefile +28 -7
  2. data/lib/macroape.rb +14 -26
  3. data/lib/macroape/aligned_pair_intersection.rb +24 -24
  4. data/lib/macroape/collection.rb +1 -2
  5. data/lib/macroape/count_by_threshold.rb +8 -26
  6. data/lib/macroape/exec/eval_alignment.rb +19 -19
  7. data/lib/macroape/exec/eval_similarity.rb +18 -16
  8. data/lib/macroape/exec/find_pvalue.rb +8 -6
  9. data/lib/macroape/exec/find_threshold.rb +7 -5
  10. data/lib/macroape/exec/preprocess_collection.rb +10 -7
  11. data/lib/macroape/exec/scan_collection.rb +13 -10
  12. data/lib/macroape/pwm_compare.rb +33 -2
  13. data/lib/macroape/pwm_compare_aligned.rb +38 -2
  14. data/lib/macroape/threshold_by_pvalue.rb +48 -43
  15. data/lib/macroape/version.rb +3 -3
  16. data/macroape.gemspec +2 -0
  17. data/test/data/test_collection.yaml +70 -4
  18. data/test/eval_alignment_similarity_test.rb +19 -0
  19. data/test/eval_similarity_test.rb +26 -0
  20. data/test/find_pvalue_test.rb +25 -0
  21. data/test/find_threshold_test.rb +29 -0
  22. data/test/preprocess_collection_test.rb +9 -0
  23. data/test/scan_collection_test.rb +17 -0
  24. data/test/test_helper.rb +10 -0
  25. metadata +33 -16
  26. data/lib/macroape/aligned_pair_metrics.rb +0 -24
  27. data/lib/macroape/aligned_pair_transformations.rb +0 -23
  28. data/lib/macroape/extract_pwm.rb +0 -32
  29. data/lib/macroape/gauss_estimation.rb +0 -30
  30. data/lib/macroape/matrix_information.rb +0 -29
  31. data/lib/macroape/matrix_on_background.rb +0 -16
  32. data/lib/macroape/matrix_transformations.rb +0 -29
  33. data/lib/macroape/pair_metrics.rb +0 -9
  34. data/lib/macroape/pair_transformations.rb +0 -28
  35. data/lib/macroape/single_matrix.rb +0 -45
  36. data/lib/macroape/support.rb +0 -34
  37. data/test/macroape_test.rb +0 -125
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ class TestEvalAlignmentSimilarity < Test::Unit::TestCase
4
+ def test_process_at_optimal_alignment
5
+ IO.popen(Helpers.exec_cmd('eval_alignment','test/data/KLF4_f2.pat test/data/SP1_f1.pat -1 direct')){|f|
6
+ assert_equal "0.2420758234928527\n779.0\t11\n.>>>>>>>>>>\n>>>>>>>>>>>\n-1\tdirect\n", f.read
7
+ }
8
+ end
9
+ def test_process_not_optimal_alignment
10
+ IO.popen(Helpers.exec_cmd('eval_alignment','test/data/KLF4_f2.pat test/data/SP1_f1.pat 0 direct')){|f|
11
+ assert_equal "0.0017543859649122807\n7.0\t11\n>>>>>>>>>>.\n>>>>>>>>>>>\n0\tdirect\n", f.read
12
+ }
13
+ end
14
+ def test_process_at_optimal_alignment_reversed
15
+ IO.popen(Helpers.exec_cmd('eval_alignment','test/data/KLF4_f2.pat test/data/SP1_f1.pat -1 revcomp')){|f|
16
+ assert_equal "0.0\n0.0\t11\n.>>>>>>>>>>\n<<<<<<<<<<<\n-1\trevcomp\n", f.read
17
+ }
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class TestEvalSimilarity < Test::Unit::TestCase
4
+ def test_process_pair_of_pwms
5
+ IO.popen(Helpers.exec_cmd('eval_similarity','test/data/KLF4_f2.pat test/data/SP1_f1.pat')){|f|
6
+ assert_equal "0.2420758234928527\n779.0\t11\n.>>>>>>>>>>\n>>>>>>>>>>>\n-1\tdirect\n", f.read
7
+ }
8
+ end
9
+ def test_process_another_pair_of_pwms
10
+ IO.popen(Helpers.exec_cmd('eval_similarity','test/data/SP1_f1.pat test/data/AHR_si.pat')){|f|
11
+ assert_equal "0.0037332005973120955\n15.0\t11\n>>>>>>>>>>>\n.>>>>>>>>>.\n1\tdirect\n", f.read
12
+ }
13
+ end
14
+
15
+ def test_recognize_orientation_of_alignment
16
+ IO.popen(Helpers.exec_cmd('eval_similarity','test/data/SP1_f1_revcomp.pat test/data/SP1_f1.pat')){|f|
17
+ assert_equal "1.0\n2033.0\t11\n>>>>>>>>>>>\n<<<<<<<<<<<\n0\trevcomp\n", f.read
18
+ }
19
+ end
20
+
21
+ def test_process_custom_discretization
22
+ IO.popen(Helpers.exec_cmd('eval_similarity','test/data/SP1_f1.pat test/data/KLF4_f2.pat -d 1')){|f|
23
+ assert_equal "0.22754919499105544\n636.0\t11\n>>>>>>>>>>>\n.>>>>>>>>>>\n1\tdirect\n", f.read
24
+ }
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class FindPvalueTest < Test::Unit::TestCase
4
+ def test_process_one_threshold
5
+ IO.popen(Helpers.exec_cmd('find_pvalue', 'test/data/KLF4_f2.pat 4.1719')){|f|
6
+ assert_equal "4.1719\t1048.0\t0.00099945068359375\n", f.read
7
+ }
8
+ end
9
+ def test_process_several_thresholds
10
+ IO.popen(Helpers.exec_cmd('find_pvalue','test/data/KLF4_f2.pat 4.1719 5.2403')){|f|
11
+ assert_equal "4.1719\t1048.0\t0.00099945068359375\n5.2403\t524.0\t0.000499725341796875\n", f.read
12
+ }
13
+ end
14
+ def test_process_several_thresholds_result_is_ordered
15
+ IO.popen(Helpers.exec_cmd('find_pvalue','test/data/KLF4_f2.pat 5.2403 4.1719')){|f|
16
+ assert_equal "5.2403\t524.0\t0.000499725341796875\n4.1719\t1048.0\t0.00099945068359375\n", f.read
17
+ }
18
+ end
19
+ def test_custom_discretization
20
+ IO.popen(Helpers.exec_cmd('find_pvalue','test/data/KLF4_f2.pat 5.2403 -d 100')){|f|
21
+ assert_equal "5.2403\t527.0\t0.0005025863647460938\n", f.read
22
+ }
23
+ end
24
+ end
25
+
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class FindThresholdTest < Test::Unit::TestCase
4
+ def test_process_several_pvalues
5
+ pvalues = []
6
+ IO.popen(Helpers.exec_cmd('find_threshold', 'test/data/KLF4_f2.pat -p 0.001 0.0005'), &:read).lines.each{|line|
7
+ pvalue, threshold, real_pvalue = line.strip.split("\t")
8
+ pvalues << pvalue
9
+ assert_equal Helpers.obtain_pvalue_by_threshold("test/data/KLF4_f2.pat #{threshold}"), real_pvalue
10
+ }
11
+ assert_equal pvalues, ['0.0005', '0.001']
12
+ end
13
+ def test_process_one_pvalue
14
+ pvalue, threshold, real_pvalue = IO.popen(Helpers.exec_cmd('find_threshold', 'test/data/KLF4_f2.pat -p 0.001'), &:read).strip.split("\t")
15
+ assert_equal '0.001', pvalue
16
+ assert_equal Helpers.obtain_pvalue_by_threshold("test/data/KLF4_f2.pat #{threshold}"), real_pvalue
17
+ end
18
+ def test_process_default_pvalue
19
+ pvalue, threshold, real_pvalue = IO.popen(Helpers.exec_cmd('find_threshold','test/data/KLF4_f2.pat'), &:read).strip.split("\t")
20
+ assert_equal '0.0005', pvalue
21
+ assert_equal Helpers.obtain_pvalue_by_threshold("test/data/KLF4_f2.pat #{threshold}"), real_pvalue
22
+ end
23
+ def test_custom_discretization
24
+ pvalue, threshold, real_pvalue = IO.popen(Helpers.exec_cmd('find_threshold','test/data/KLF4_f2.pat -d 100'), &:read).strip.split("\t")
25
+ assert_equal '0.0005', pvalue
26
+ assert_equal Helpers.obtain_pvalue_by_threshold("test/data/KLF4_f2.pat #{threshold} -d 100"), real_pvalue
27
+ end
28
+ end
29
+
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class TestPreprocessCollection < Test::Unit::TestCase
4
+ def test_multipvalue_preproceessing
5
+ system(Helpers.exec_cmd('preprocess_collection','./test/data/test_collection -o test/data/test_collection.yaml.tmp -p 0.0005 0.0001 0.00005 --silent'))
6
+ assert_equal File.read('test/data/test_collection.yaml'), File.read('test/data/test_collection.yaml.tmp')
7
+ File.delete 'test/data/test_collection.yaml.tmp'
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ class TestScanCollection < Test::Unit::TestCase
4
+ def test_scan_default_cutoff
5
+ assert_equal File.read('test/data/KLF4_f2_scan_results_default_cutoff.txt'),
6
+ IO.popen(Helpers.exec_cmd('scan_collection','test/data/KLF4_f2.pat test/data/test_collection.yaml --silent'), &:read)
7
+ end
8
+ def test_scan_and_output_all_results
9
+ assert_equal File.read('test/data/KLF4_f2_scan_results_all.txt'),
10
+ IO.popen(Helpers.exec_cmd('scan_collection','test/data/KLF4_f2.pat test/data/test_collection.yaml --all --silent'), &:read)
11
+
12
+ end
13
+ def test_scan_precise_mode
14
+ assert_equal File.read('test/data/KLF4_f2_scan_results_precise_mode.txt'),
15
+ IO.popen(Helpers.exec_cmd('scan_collection','test/data/KLF4_f2.pat test/data/test_collection.yaml --precise --all --silent'), &:read)
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ require 'test/unit'
2
+
3
+ module Helpers
4
+ def self.obtain_pvalue_by_threshold(args)
5
+ IO.popen("find_pvalue #{args}",&:read).strip.split.last
6
+ end
7
+ def self.exec_cmd(executable, param_list)
8
+ "ruby #{File.dirname(File.absolute_path __FILE__)}/../lib/macroape/exec/#{executable}.rb #{param_list}"
9
+ end
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: macroape
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.2
4
+ version: 3.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-28 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-06-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bioinform
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.0
14
30
  description: Macroape is an abbreviation for MAtrix CompaRisOn by Approximate P-value
15
31
  Estimation. It's a bioinformatic tool for evaluating similarity measure and best
16
32
  alignment between a pair of Position Weight Matrices(PWM), finding thresholds by
@@ -41,8 +57,6 @@ files:
41
57
  - bin/scan_collection
42
58
  - lib/macroape.rb
43
59
  - lib/macroape/aligned_pair_intersection.rb
44
- - lib/macroape/aligned_pair_metrics.rb
45
- - lib/macroape/aligned_pair_transformations.rb
46
60
  - lib/macroape/collection.rb
47
61
  - lib/macroape/count_by_threshold.rb
48
62
  - lib/macroape/exec/eval_alignment.rb
@@ -51,17 +65,8 @@ files:
51
65
  - lib/macroape/exec/find_threshold.rb
52
66
  - lib/macroape/exec/preprocess_collection.rb
53
67
  - lib/macroape/exec/scan_collection.rb
54
- - lib/macroape/extract_pwm.rb
55
- - lib/macroape/gauss_estimation.rb
56
- - lib/macroape/matrix_information.rb
57
- - lib/macroape/matrix_on_background.rb
58
- - lib/macroape/matrix_transformations.rb
59
- - lib/macroape/pair_metrics.rb
60
- - lib/macroape/pair_transformations.rb
61
68
  - lib/macroape/pwm_compare.rb
62
69
  - lib/macroape/pwm_compare_aligned.rb
63
- - lib/macroape/single_matrix.rb
64
- - lib/macroape/support.rb
65
70
  - lib/macroape/threshold_by_pvalue.rb
66
71
  - lib/macroape/version.rb
67
72
  - macroape.gemspec
@@ -76,7 +81,13 @@ files:
76
81
  - test/data/test_collection/GABPA_f1.pat
77
82
  - test/data/test_collection/KLF4_f2.pat
78
83
  - test/data/test_collection/SP1_f1.pat
79
- - test/macroape_test.rb
84
+ - test/eval_alignment_similarity_test.rb
85
+ - test/eval_similarity_test.rb
86
+ - test/find_pvalue_test.rb
87
+ - test/find_threshold_test.rb
88
+ - test/preprocess_collection_test.rb
89
+ - test/scan_collection_test.rb
90
+ - test/test_helper.rb
80
91
  homepage: http://autosome.ru/macroape/
81
92
  licenses: []
82
93
  post_install_message:
@@ -113,4 +124,10 @@ test_files:
113
124
  - test/data/test_collection/GABPA_f1.pat
114
125
  - test/data/test_collection/KLF4_f2.pat
115
126
  - test/data/test_collection/SP1_f1.pat
116
- - test/macroape_test.rb
127
+ - test/eval_alignment_similarity_test.rb
128
+ - test/eval_similarity_test.rb
129
+ - test/find_pvalue_test.rb
130
+ - test/find_threshold_test.rb
131
+ - test/preprocess_collection_test.rb
132
+ - test/scan_collection_test.rb
133
+ - test/test_helper.rb
@@ -1,24 +0,0 @@
1
- module PWMCompare
2
- module AlignedPairMetrics
3
- def jaccard(first_threshold, second_threshold)
4
- f = first.counts_by_thresholds(first_threshold).first
5
- s = second.counts_by_thresholds(second_threshold).first
6
- if f == 0 or s == 0
7
- return {similarity: -1, tanimoto: -1, recognized_by_both: 0,
8
- recognized_by_first: f,
9
- recognized_by_second: s,
10
- }
11
- end
12
-
13
- intersect = counts_for_two_matrices(first_threshold, second_threshold)
14
- intersect = Math.sqrt(intersect[0] * intersect[1])
15
- union = f + s - intersect
16
- similarity = intersect.to_f / union
17
- { similarity: similarity,
18
- tanimoto: 1.0 - similarity,
19
- recognized_by_both: intersect,
20
- recognized_by_first: f,
21
- recognized_by_second: s }
22
- end
23
- end
24
- end
@@ -1,23 +0,0 @@
1
- module PWMCompare
2
- module AlignedPairTransformations
3
-
4
- #def discrete(rate)
5
- # PWMCompareAligned.new(first.discrete(rate), second.discrete(rate))
6
- #end
7
-
8
- def sort_pair_of_matrices_by(&block)
9
- mat = first.pwm.zip(second.pwm).sort_by(&block).transpose
10
- PWMCompareAligned.new(SinglePWM(mat[0],first.probabilities), SinglePWM(mat[1], second.probabilities))
11
- end
12
- def sort_decreasing_max
13
- PWMCompareAligned.new(*sort_pair_of_matrices_by{|col_pair| -col_pair[0].max} )
14
- end
15
- def sort_increasing_min
16
- PWMCompareAligned.new(*sort_pair_of_matrices_by{|col_pair| col_pair[0].min} )
17
- end
18
- def permute_columns(permutation_index)
19
- PWMCompareAligned.new(first.permute(permutation_index), second.permute(permutation_index))
20
- end
21
-
22
- end
23
- end
@@ -1,32 +0,0 @@
1
- # r_stream, w_stream - supposed to be a pipe. Data's read from r_stream, pwm's extracted, remaining data pushed back to w_stream
2
- # ... --> w_stream --> r_stream --> data
3
- # ^ |
4
- # | v
5
- # ... <-- w_stream <-- ... --> extracted pwm
6
- def extract_pwm(r_stream, w_stream)
7
- lines = r_stream.readlines
8
- return [r_stream, w_stream, nil] if lines.empty?
9
-
10
- extracted_pwm = [lines.shift]
11
- while extracted_pwm.last.chomp == ''
12
- extracted_pwm = [lines.shift.strip]
13
- return [r_stream, w_stream, nil] unless extracted_pwm.last
14
- end
15
-
16
- r_stream.close
17
- begin
18
- until lines.empty?
19
- line = lines.shift
20
- line.split.each{|x| Float(x) } # raises error if string is not a numeric
21
- raise 'Not a PWM string (too little number of numbers - may be empty string or name of next pwm). PWM finished' if line.split.size < 4
22
- extracted_pwm << line
23
- end
24
- rescue
25
- lines.unshift(line)
26
- end
27
- new_r_stream, new_w_stream = IO.pipe
28
- lines.each{|one_line| new_w_stream.write(one_line)}
29
- new_w_stream.close
30
-
31
- [new_r_stream, new_w_stream, extracted_pwm]
32
- end
@@ -1,30 +0,0 @@
1
- module PWM
2
- module GaussEstimation
3
- def score_mean
4
- bckgr = probabilities.map{|v| v.to_f / sum_of_probabilities}
5
- matrix.inject(0.0){ |mean, col| mean + 4.times.inject(0.0){|sum,letter| sum + col[letter] * bckgr[letter]} }
6
- end
7
- def score_variance
8
- bckgr = probabilities.map{|v| v.to_f / sum_of_probabilities}
9
- matrix.inject(0.0) do |variance, col|
10
- variance + 4.times.inject(0.0) { |sum,letter| sum + col[letter]**2 * bckgr[letter] } -
11
- 4.times.inject(0.0) { |sum,letter| sum + col[letter] * bckgr[letter] }**2
12
- end
13
- end
14
- def threshold_gauss_estimation(pvalue)
15
- sigma = Math.sqrt(score_variance)
16
- n_ = inverf2(1 - 2 * pvalue) * Math.sqrt(2)
17
- score_mean + n_ * sigma
18
- end
19
- def inverf2(x)
20
- sign = x < 0 ? -1 : 1
21
- x = x.abs
22
- a = 8 / (3*Math::PI) * (Math::PI-3) / (4-Math::PI)
23
- part0 = ( 2/(Math::PI*a) + (Math.log(1-x*x)) / 2 )**2
24
- part = -2 / (Math::PI * a) - Math.log(1-x*x)/2 + Math.sqrt(-1/a *
25
- Math.log(1-x*x) + part0)
26
- sign * Math.sqrt(part)
27
- end
28
- end
29
-
30
- end
@@ -1,29 +0,0 @@
1
- module PWM
2
- module MatrixInformation
3
- def length
4
- @length ||= matrix.length
5
- end
6
- def best_score
7
- @best_score ||= matrix.inject(0){|sum, col| sum + col.max}
8
- end
9
- def worst_score
10
- @worst_score ||= matrix.inject(0){|sum, col| sum + col.min}
11
- end
12
- def best_suffix
13
- return @best_suffix if @best_suffix
14
- @best_suffix = Array.new(length + 1, 0) # best score of suffix s[i..l]
15
- length.times{|i| @best_suffix[length - i - 1] = matrix[length - i - 1].max + @best_suffix[length - i] }
16
- @best_suffix
17
- end
18
- def worst_suffix
19
- return @worst_suffix if @worst_suffix
20
- @worst_suffix = Array.new(length + 1, 0)
21
- length.times{|i| @worst_suffix[length - i - 1] = matrix[length - i - 1].min + @worst_suffix[length - i] }
22
- @worst_suffix
23
- end
24
- def refresh_infos
25
- @length = @best_score = @worst_score = @best_suffix = @worst_suffix = nil
26
- self
27
- end
28
- end
29
- end
@@ -1,16 +0,0 @@
1
- module PWM
2
- class MatrixOnBackground < SingleMatrix
3
- attr_reader :probabilities
4
- def initialize(matrix,background)
5
- super(matrix)
6
- @probabilities = background
7
- end
8
- def sum_of_probabilities
9
- @sum_of_probabilities ||= probabilities.inject(0.0, &:+)
10
- end
11
- def number_of_words
12
- sum_of_probabilities ** length
13
- end
14
- include GaussEstimation, ThresholdByPvalue, CountByThreshold
15
- end
16
- end
@@ -1,29 +0,0 @@
1
- module PWM
2
- module MatrixTransformations
3
- def reverse_complement
4
- clone_and_transform( matrix.reverse.map(&:reverse) ).refresh_infos
5
- end
6
- def left_augment(n)
7
- clone_and_transform( [[0.0]*4]* n + matrix ).refresh_infos
8
- end
9
- def right_augment(n)
10
- clone_and_transform( matrix + [[0.0]*4]* n ).refresh_infos
11
- end
12
- def shift_to_zero # make worst score == 0 by shifting scores of each column
13
- clone_and_transform( matrix.map{|col| col.map{|letter| letter - col.min}} ).refresh_infos
14
- end
15
- def discrete(rate)
16
- clone_and_transform( matrix.map{|col| col.map{|letter| (letter * rate).ceil}} ).refresh_infos
17
- end
18
- def split(length_of_first_part)
19
- [clone_and_transform( matrix.first(length_of_first_part)).refresh_infos, clone_and_transform(matrix.last(length - length_of_first_part)).refresh_infos]
20
- end
21
- def permute_columns(permutation_index)
22
- clone_and_transform( permutation_index.map{|col| matrix[col]} ).refresh_infos
23
- end
24
-
25
- def clone_and_transform(new_matrix)
26
- self.dup.instance_eval{ @matrix = new_matrix; self }
27
- end
28
- end
29
- end
@@ -1,9 +0,0 @@
1
- module PWMCompare
2
- module PairMetrics
3
- def jaccard(threshold_first, threshold_second)
4
- self.map_each_align do |align, alignment_info|
5
- align.jaccard(threshold_first, threshold_second).merge(alignment_info)
6
- end.max_by {|alignment_info| alignment_info[:similarity]}
7
- end
8
- end
9
- end
@@ -1,28 +0,0 @@
1
- module PWMCompare
2
- module PairTransformations
3
-
4
- def each
5
- second_rc = second.reverse_complement
6
- (-second.length..first.length).to_a.product([:direct,:revcomp]) do |shift, orientation|
7
- first_pwm_alignment = '.' * [-shift, 0].max + '>' * first.length
8
- second_pwm_alignment = '.' * [shift, 0].max + (orientation == :direct ? '>' : '<') * second.length
9
- overlap = [first.length + [-shift,0].max, second.length + [shift,0].max].min - shift.abs
10
- alignment_length = [first_pwm_alignment.length, second_pwm_alignment.length].max
11
- (first_pwm_alignment.length...alignment_length).each{|i| first_pwm_alignment[i] = '.'}
12
- (second_pwm_alignment.length...alignment_length).each{|i| second_pwm_alignment[i] = '.'}
13
-
14
- yield(PWMCompareAligned.new(first.left_augment([-shift,0].max),
15
- (orientation == :direct ? second : second_rc).left_augment([shift,0].max)),
16
- text: "#{first_pwm_alignment}\n#{second_pwm_alignment}",
17
- shift: shift,
18
- orientation: orientation,
19
- overlap: overlap,
20
- alignment_length: alignment_length
21
- )
22
- end
23
- end
24
- include Enumerable
25
- alias :each_align :each
26
- alias :map_each_align :map
27
- end
28
- end