genevalidator 1.6.12 → 2.1.3

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 (91) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +30 -1
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +13 -12
  5. data/Gemfile +4 -1
  6. data/Gemfile.lock +135 -0
  7. data/README.md +104 -122
  8. data/Rakefile +377 -5
  9. data/aux/gv_results.slim +155 -0
  10. data/aux/html_files/css/gv.compiled.min.css +8 -0
  11. data/aux/{files → html_files}/css/src/bootstrap.min.css +0 -0
  12. data/aux/{files → html_files}/css/src/font-awesome.min.css +0 -0
  13. data/aux/{files → html_files}/css/src/style.css +0 -0
  14. data/aux/{files → html_files}/fonts/FontAwesome.otf +0 -0
  15. data/aux/{files → html_files}/fonts/fontawesome-webfont.eot +0 -0
  16. data/aux/{files → html_files}/fonts/fontawesome-webfont.svg +0 -0
  17. data/aux/{files → html_files}/fonts/fontawesome-webfont.ttf +0 -0
  18. data/aux/{files → html_files}/fonts/fontawesome-webfont.woff +0 -0
  19. data/aux/{files → html_files}/img/gene.png +0 -0
  20. data/aux/html_files/js/gv.compiled.min.js +1 -0
  21. data/aux/{files → html_files}/js/src/bootstrap.min.js +0 -0
  22. data/aux/{files → html_files}/js/src/d3.v3.min.js +0 -0
  23. data/aux/{files → html_files}/js/src/jquery-2.1.1.min.js +0 -0
  24. data/aux/{files → html_files}/js/src/jquery.tablesorter.min.js +0 -0
  25. data/aux/{files → html_files}/js/src/plots.js +1 -1
  26. data/aux/{files → html_files}/js/src/script.js +0 -0
  27. data/aux/{files → html_files}/json/.gitkeep +0 -0
  28. data/bin/genevalidator +393 -56
  29. data/exemplar_data/README.md +60 -0
  30. data/{data/mrna_data.fasta → exemplar_data/mrna_data.fa} +1 -1
  31. data/{data/protein_data.fasta → exemplar_data/protein_data.fa} +0 -0
  32. data/genevalidator.gemspec +35 -20
  33. data/install.sh +92 -0
  34. data/lib/genevalidator.rb +171 -56
  35. data/lib/genevalidator/arg_validation.rb +26 -55
  36. data/lib/genevalidator/blast.rb +44 -99
  37. data/lib/genevalidator/clusterization.rb +18 -22
  38. data/lib/genevalidator/exceptions.rb +17 -17
  39. data/lib/genevalidator/ext/array.rb +21 -4
  40. data/lib/genevalidator/get_raw_sequences.rb +32 -31
  41. data/lib/genevalidator/hsp.rb +31 -2
  42. data/lib/genevalidator/json_to_gv_results.rb +38 -122
  43. data/lib/genevalidator/output.rb +158 -172
  44. data/lib/genevalidator/output_files.rb +134 -0
  45. data/lib/genevalidator/pool.rb +2 -5
  46. data/lib/genevalidator/query.rb +1 -1
  47. data/lib/genevalidator/tabular_parser.rb +8 -29
  48. data/lib/genevalidator/validation.rb +48 -90
  49. data/lib/genevalidator/validation_alignment.rb +64 -75
  50. data/lib/genevalidator/validation_blast_reading_frame.rb +13 -9
  51. data/lib/genevalidator/validation_duplication.rb +85 -84
  52. data/lib/genevalidator/validation_gene_merge.rb +46 -35
  53. data/lib/genevalidator/validation_length_cluster.rb +18 -15
  54. data/lib/genevalidator/validation_length_rank.rb +19 -15
  55. data/lib/genevalidator/validation_maker_qi.rb +13 -12
  56. data/lib/genevalidator/validation_open_reading_frame.rb +16 -13
  57. data/lib/genevalidator/validation_report.rb +1 -1
  58. data/lib/genevalidator/validation_test.rb +1 -1
  59. data/lib/genevalidator/version.rb +1 -1
  60. data/test/overall.rb +1 -1
  61. data/test/test_all_validations.rb +36 -24
  62. data/test/test_blast.rb +39 -24
  63. data/test/test_clusterization_2d.rb +4 -4
  64. data/test/test_helper.rb +2 -2
  65. data/test/test_query.rb +16 -20
  66. data/test/test_validation_open_reading_frame.rb +122 -122
  67. data/test/test_validations.rb +12 -10
  68. metadata +94 -79
  69. data/aux/files/css/genevalidator.compiled.min.css +0 -16
  70. data/aux/files/js/genevalidator.compiled.min.js +0 -28
  71. data/aux/json_footer.erb +0 -8
  72. data/aux/json_header.erb +0 -19
  73. data/aux/json_query.erb +0 -15
  74. data/aux/template_footer.erb +0 -8
  75. data/aux/template_header.erb +0 -19
  76. data/aux/template_query.erb +0 -14
  77. data/data/README.md +0 -57
  78. data/data/mrna_data.fasta.blast_tabular +0 -3567
  79. data/data/mrna_data.fasta.blast_tabular.raw_seq +0 -53998
  80. data/data/mrna_data.fasta.blast_tabular.raw_seq.idx +0 -5440
  81. data/data/mrna_data.fasta.blast_xml +0 -39800
  82. data/data/mrna_data.fasta.blast_xml.raw_seq +0 -2554
  83. data/data/mrna_data.fasta.blast_xml.raw_seq.idx +0 -3127
  84. data/data/mrna_data.fasta.json +0 -1
  85. data/data/protein_data.fasta.blast_tabular +0 -3278
  86. data/data/protein_data.fasta.blast_tabular.raw_seq +0 -61295
  87. data/data/protein_data.fasta.blast_tabular.raw_seq.idx +0 -4438
  88. data/data/protein_data.fasta.blast_xml +0 -26228
  89. data/data/protein_data.fasta.blast_xml.raw_seq +0 -9803
  90. data/data/protein_data.fasta.blast_xml.raw_seq.idx +0 -1777
  91. data/data/protein_data.fasta.json +0 -1
@@ -15,7 +15,9 @@ module GeneValidator
15
15
 
16
16
  def initialize(short_header, header, description, frames,
17
17
  expected = :yes)
18
- @short_header, @header, @description = short_header, header, description
18
+ @short_header = short_header
19
+ @header = header
20
+ @description = description
19
21
  @frames = frames
20
22
  @expected = expected
21
23
  @result = validation
@@ -70,7 +72,7 @@ module GeneValidator
70
72
  count_p += 1 if x > 0
71
73
  count_n += 1 if x < 0
72
74
  end
73
- (count_p > 1 || count_n > 1) ? :no : :yes
75
+ count_p > 1 || count_n > 1 ? :no : :yes
74
76
  end
75
77
  end
76
78
 
@@ -78,6 +80,9 @@ module GeneValidator
78
80
  # This class contains the methods necessary for
79
81
  # reading frame validation based on BLAST output
80
82
  class BlastReadingFrameValidation < ValidationTest
83
+ extend Forwardable
84
+ def_delegators GeneValidator, :opt
85
+
81
86
  def initialize(type, prediction, hits = nil)
82
87
  super
83
88
  @short_header = 'ReadingFrame'
@@ -100,8 +105,8 @@ module GeneValidator
100
105
  return @validation_report
101
106
  end
102
107
 
103
- fail NotEnoughHitsError unless hits.length >= 5
104
- fail unless prediction.is_a?(Query) && hits[0].is_a?(Query)
108
+ raise NotEnoughHitsError if hits.length < opt[:min_blast_hits]
109
+ raise unless prediction.is_a?(Query) && hits[0].is_a?(Query)
105
110
 
106
111
  start = Time.now
107
112
 
@@ -116,12 +121,11 @@ module GeneValidator
116
121
  @description, frames)
117
122
  @validation_report.run_time = Time.now - start
118
123
  @validation_report
119
-
120
124
  rescue NotEnoughHitsError
121
- @validation_report = ValidationReport.new('Not enough evidence',
122
- :warning, @short_header,
123
- @header, @description)
124
- rescue
125
+ @validation_report = ValidationReport.new('Not enough evidence',
126
+ :warning, @short_header,
127
+ @header, @description)
128
+ rescue StandardError
125
129
  @validation_report = ValidationReport.new('Unexpected error', :error,
126
130
  @short_header, @header,
127
131
  @description)
@@ -19,7 +19,9 @@ module GeneValidator
19
19
 
20
20
  def initialize(short_header, header, description, pvalue, averages,
21
21
  threshold = 0.05, expected = :yes)
22
- @short_header, @header, @description = short_header, header, description
22
+ @short_header = short_header
23
+ @header = header
24
+ @description = description
23
25
  @pvalue = pvalue
24
26
  @threshold = threshold
25
27
  @result = validation
@@ -36,7 +38,7 @@ module GeneValidator
36
38
 
37
39
  def explain
38
40
  "The Wilcoxon test produced a p-value of #{prettify_evalue(@pvalue)}" \
39
- "#{(@result == :no) ? " (average = #{@average.round(2)})." : '.'}"
41
+ "#{@result == :no ? " (average = #{@average.round(2)})." : '.'}"
40
42
  end
41
43
 
42
44
  def conclude
@@ -50,15 +52,15 @@ module GeneValidator
50
52
  end
51
53
 
52
54
  def print
53
- "#{@pvalue.round(2)}"
55
+ @pvalue.round(2).to_s
54
56
  end
55
57
 
56
58
  def validation
57
- (@pvalue > @threshold) ? :yes : :no
59
+ @pvalue > @threshold ? :yes : :no
58
60
  end
59
61
 
60
62
  def color
61
- (validation == :yes) ? 'success' : 'danger'
63
+ validation == :yes ? 'success' : 'danger'
62
64
  end
63
65
 
64
66
  private
@@ -97,41 +99,33 @@ module GeneValidator
97
99
  @index_file_name = config[:raw_seq_file_index]
98
100
  @raw_seq_file_load = config[:raw_seq_file_load]
99
101
  @db = opt[:db]
100
- @num_threads = opt[:num_threads]
102
+ @num_threads = opt[:mafft_threads]
101
103
  @type = config[:type]
102
104
  end
103
105
 
104
- def in_range?(ranges, idx)
105
- ranges.each do |range|
106
- return (range.member?(idx)) ? true : false
107
- end
108
- false
109
- end
110
-
111
106
  ##
112
107
  # Check duplication in the first n hits
113
108
  # Output:
114
109
  # +DuplicationValidationOutput+ object
115
110
  def run(n = 10)
116
- fail NotEnoughHitsError unless hits.length >= 5
117
- fail unless prediction.is_a?(Query) && !prediction.raw_sequence.nil? &&
118
- hits[0].is_a?(Query)
111
+ raise NotEnoughHitsError if hits.length < opt[:min_blast_hits]
112
+ raise unless prediction.is_a?(Query) && !prediction.raw_sequence.nil? &&
113
+ hits[0].is_a?(Query)
119
114
 
120
115
  start = Time.new
121
116
  # get the first n hits
122
- less_hits = @hits[0..[n - 1, @hits.length].min]
123
- useless_hits = []
117
+ n_hits = [n - 1, @hits.length].min
118
+ less_hits = @hits[0..n_hits]
124
119
  # get raw sequences for less_hits
125
- less_hits.map do |hit|
126
- next unless hit.raw_sequence.nil?
127
- hit.raw_sequence = FetchRawSequences.run(hit.identifier,
128
- hit.accession_no)
129
- useless_hits.push(hit) if hit.raw_sequence.nil?
120
+ less_hits.delete_if do |hit|
121
+ if hit.raw_sequence.nil?
122
+ hit.raw_sequence = FetchRawSequences.run(hit.identifier,
123
+ hit.accession_no)
124
+ end
125
+ hit.raw_sequence.nil? ? true : false
130
126
  end
131
127
 
132
- useless_hits.each { |hit| less_hits.delete(hit) }
133
-
134
- fail NoInternetError if less_hits.length == 0
128
+ raise NoInternetError if less_hits.length.zero?
135
129
 
136
130
  averages = []
137
131
 
@@ -146,62 +140,17 @@ module GeneValidator
146
140
  hit_alignment = hsp.hit_alignment
147
141
  query_alignment = hsp.query_alignment
148
142
  else
149
- # indexing in blast starts from 1
150
- hit_local = hit.raw_sequence[hsp.hit_from - 1..hsp.hit_to - 1]
151
- query_local = prediction.raw_sequence[hsp.match_query_from -
152
- 1..hsp.match_query_to - 1]
153
-
154
- # in case of nucleotide prediction sequence translate into protein
155
- # use translate with reading frame 1 because
156
- # to/from coordinates of the hsp already correspond to the
157
- # reading frame in which the prediction was read to match this hsp
158
- if @type == :nucleotide
159
- s = Bio::Sequence::NA.new(query_local)
160
- query_local = s.translate
161
- end
162
-
163
- # local alignment for hit and query
164
- seqs = [hit_local, query_local]
165
-
166
- begin
167
- options = ['--maxiterate', '1000', '--localpair', '--anysymbol',
168
- '--quiet', '--thread', "#{@num_threads}"]
169
- mafft = Bio::MAFFT.new('mafft', options)
170
-
171
- report = mafft.query_align(seqs)
172
- raw_align = report.alignment
173
- align = []
174
-
175
- raw_align.each { |seq| align.push(seq.to_s) }
176
- hit_alignment = align[0]
177
- query_alignment = align[1]
178
- rescue
179
- raise NoMafftInstallationError
180
- end
143
+ align = find_local_alignment(hit, prediction, hsp)
144
+ hit_alignment = align[0]
145
+ query_alignment = align[1]
181
146
  end
182
147
 
183
- # check multiple coverage
184
-
185
- # for each hsp of the curent hit
186
- # iterate through the alignment and count the matching residues
187
- [*(0..hit_alignment.length - 1)].each do |i|
188
- residue_hit = hit_alignment[i]
189
- residue_query = query_alignment[i]
190
- next if residue_hit == ' ' || residue_hit == '+' ||
191
- residue_hit == '-' || residue_hit != residue_query
192
- # indexing in blast starts from 1
193
- idx_hit = i + (hsp.hit_from - 1) -
194
- hit_alignment[0..i].scan(/-/).length
195
- idx_query = i + (hsp.match_query_from - 1) -
196
- query_alignment[0..i].scan(/-/).length
197
- unless in_range?(ranges_prediction, idx_query)
198
- coverage[idx_hit] += 1
199
- end
200
- end
148
+ coverage = check_multiple_coverage(hit_alignment, query_alignment,
149
+ hsp, coverage, ranges_prediction)
201
150
 
202
- ranges_prediction.push((hsp.match_query_from..hsp.match_query_to))
151
+ ranges_prediction << (hsp.match_query_from..hsp.match_query_to)
203
152
  end
204
- overlap = coverage.reject { |x| x == 0 }
153
+ overlap = coverage.reject(&:zero?)
205
154
  if overlap != []
206
155
  averages.push((overlap.inject(:+) / (overlap.length + 0.0)).round(2))
207
156
  end
@@ -225,7 +174,6 @@ module GeneValidator
225
174
  averages)
226
175
  @run_time = Time.now - start
227
176
  @validation_report
228
-
229
177
  rescue NotEnoughHitsError
230
178
  @validation_report = ValidationReport.new('Not enough evidence', :warning,
231
179
  @short_header, @header,
@@ -240,22 +188,75 @@ module GeneValidator
240
188
  @short_header, @header,
241
189
  @description)
242
190
  @validation_report.errors.push NoInternetError
243
- rescue
191
+ rescue StandardError
244
192
  @validation_report = ValidationReport.new('Unexpected error', :error,
245
193
  @short_header, @header,
246
194
  @description)
247
195
  @validation_report.errors.push 'Unexpected Error'
248
196
  end
249
197
 
198
+ # Only run if the BLAST output does not contain hit alignmment
199
+ def find_local_alignment(hit, prediction, hsp)
200
+ # indexing in blast starts from 1
201
+ hit_local = hit.raw_sequence[hsp.hit_from - 1..hsp.hit_to - 1]
202
+ query_local = prediction.raw_sequence[hsp.match_query_from -
203
+ 1..hsp.match_query_to - 1]
204
+
205
+ # in case of nucleotide prediction sequence translate into protein
206
+ # use translate with reading frame 1 because
207
+ # to/from coordinates of the hsp already correspond to the
208
+ # reading frame in which the prediction was read to match this hsp
209
+ if @type == :nucleotide
210
+ s = Bio::Sequence::NA.new(query_local)
211
+ query_local = s.translate
212
+ end
213
+
214
+ opt = ['--maxiterate', '1000', '--localpair', '--anysymbol', '--quiet',
215
+ '--thread', @num_threads.to_s]
216
+ mafft = Bio::MAFFT.new('mafft', opt)
217
+
218
+ # local alignment for hit and query
219
+ seqs = [hit_local, query_local]
220
+ report = mafft.query_align(seqs)
221
+ report.alignment.map(&:to_s)
222
+ rescue StandardError
223
+ raise NoMafftInstallationError
224
+ end
225
+
226
+ def check_multiple_coverage(hit_alignment, query_alignment, hsp, coverage,
227
+ ranges_prediction)
228
+ # for each hsp of the curent hit
229
+ # iterate through the alignment and count the matching residues
230
+ [*(0..hit_alignment.length - 1)].each do |i|
231
+ residue_hit = hit_alignment[i]
232
+ residue_query = query_alignment[i]
233
+ next if [' ', '+', '-'].include?(residue_hit)
234
+ next if residue_hit != residue_query
235
+ # indexing in blast starts from 1
236
+ idx_hit = i + (hsp.hit_from - 1) -
237
+ hit_alignment[0..i].scan(/-/).length
238
+ idx_query = i + (hsp.match_query_from - 1) -
239
+ query_alignment[0..i].scan(/-/).length
240
+ coverage[idx_hit] += 1 unless in_range?(ranges_prediction, idx_query)
241
+ end
242
+ coverage
243
+ end
244
+
245
+ def in_range?(ranges, idx)
246
+ ranges.each { |range| return true if range.member?(idx) }
247
+ false
248
+ end
249
+
250
250
  ##
251
251
  # wilcox test implementation from statsample ruby gem
252
252
  # many thanks to Claudio for helping us with the implementation!
253
253
  def wilcox_test(averages)
254
- wilcox = Statsample::Test.wilcoxon_signed_rank(Daru::Vector.new(averages),
255
- Daru::Vector.new(Array.new(averages.length,
256
- 1)))
254
+ wilcox = Statsample::Test.wilcoxon_signed_rank(
255
+ Daru::Vector.new(averages),
256
+ Daru::Vector.new(Array.new(averages.length, 1))
257
+ )
257
258
 
258
- (averages.length < 15) ? wilcox.probability_exact : wilcox.probability_z
259
+ averages.length < 15 ? wilcox.probability_exact : wilcox.probability_z
259
260
  end
260
261
  end
261
262
  end
@@ -22,7 +22,9 @@ module GeneValidator
22
22
 
23
23
  def initialize(short_header, header, description, slope, unimodality,
24
24
  expected = :no)
25
- @short_header, @header, @description = short_header, header, description
25
+ @short_header = short_header
26
+ @header = header
27
+ @description = description
26
28
  @slope = slope.round(1)
27
29
  @slope = @slope.abs if @slope == -0.0
28
30
  @unimodality = unimodality
@@ -56,30 +58,30 @@ module GeneValidator
56
58
  if @unimodality
57
59
  'This suggest that the query sequence represents a single gene.'
58
60
  else
59
- diff = (@result == :yes) ? ' within' : ' outside'
61
+ diff = @result == :yes ? ' within' : ' outside'
60
62
  t = "This slope is #{diff} our empirically calculated thresholds" \
61
63
  ' (0.4 and 1.2).'
62
- if @result == :yes
63
- t << ' This suggests the query contains sequence from two or more' \
64
- ' different genes.'
65
- else
66
- t << ' There is no evidence that the query contains sequence from' \
67
- ' multiple genes.'
68
- end
64
+ t << if @result == :yes
65
+ ' This suggests the query contains sequence from two or more' \
66
+ ' different genes.'
67
+ else
68
+ ' There is no evidence that the query contains sequence from' \
69
+ ' multiple genes.'
70
+ end
69
71
  t
70
72
  end
71
73
  end
72
74
 
73
75
  def print
74
- (@slope.nan?) ? 'Inf' : "#{@slope}"
76
+ @slope.nan? ? 'Inf' : @slope.to_s
75
77
  end
76
78
 
77
79
  def validation
78
- (@slope > threshold_down && @slope < threshold_up) ? :yes : :no
80
+ @slope > threshold_down && @slope < threshold_up ? :yes : :no
79
81
  end
80
82
 
81
83
  def color
82
- (validation == :no) ? 'success' : 'danger'
84
+ validation == :no ? 'success' : 'danger'
83
85
  end
84
86
  end
85
87
 
@@ -88,6 +90,9 @@ module GeneValidator
88
90
  # checking whether there is evidence that the
89
91
  # prediction is a merge of multiple genes
90
92
  class GeneMergeValidation < ValidationTest
93
+ extend Forwardable
94
+ def_delegators GeneValidator, :opt
95
+
91
96
  attr_reader :prediction
92
97
  attr_reader :hits
93
98
 
@@ -113,18 +118,20 @@ module GeneValidator
113
118
  # Output:
114
119
  # +GeneMergeValidationOutput+ object
115
120
  def run
116
- fail NotEnoughHitsError unless hits.length >= 5
117
- fail unless prediction.is_a?(Query) && hits[0].is_a?(Query)
121
+ raise NotEnoughHitsError if hits.length < opt[:min_blast_hits]
122
+ raise unless prediction.is_a?(Query) && hits[0].is_a?(Query)
118
123
 
119
124
  start = Time.now
120
125
 
121
- pairs = hits.map { |hit| Pair.new(hit.hsp_list.map{ |hsp| hsp.match_query_from }.min,
122
- hit.hsp_list.map{ |hsp| hsp.match_query_to }.max) }
126
+ pairs = hits.map do |hit|
127
+ Pair.new(hit.hsp_list.map(&:match_query_from).min,
128
+ hit.hsp_list.map(&:match_query_to).max)
129
+ end
123
130
  xx_0 = pairs.map(&:x)
124
131
  yy_0 = pairs.map(&:y)
125
132
 
126
133
  # minimum start shoud be at 'boundary' residues
127
- xx = xx_0.map { |x| (x < @boundary) ? @boundary : x }
134
+ xx = xx_0.map { |x| x < @boundary ? @boundary : x }
128
135
 
129
136
  # maximum end should be at length - 'boundary' residues
130
137
  yy = yy_0.map do |y|
@@ -151,23 +158,22 @@ module GeneValidator
151
158
  @validation_report = GeneMergeValidationOutput.new(@short_header, @header,
152
159
  @description, lm_slope,
153
160
  unimodality)
154
- if unimodality
155
- plot1 = plot_2d_start_from
156
- else
157
- plot1 = plot_2d_start_from(lm_slope, y_intercept)
158
- end
161
+ plot1 = if unimodality
162
+ plot_2d_start_from
163
+ else
164
+ plot_2d_start_from(lm_slope, y_intercept)
165
+ end
159
166
 
160
167
  @validation_report.plot_files.push(plot1)
161
168
  plot2 = plot_matched_regions
162
169
  @validation_report.plot_files.push(plot2)
163
170
  @validation_report.run_time = Time.now - start
164
171
  @validation_report
165
-
166
172
  rescue NotEnoughHitsError
167
173
  @validation_report = ValidationReport.new('Not enough evidence', :warning,
168
174
  @short_header, @header,
169
175
  @description)
170
- rescue
176
+ rescue StandardError
171
177
  @validation_report = ValidationReport.new('Unexpected error', :error,
172
178
  @short_header, @header,
173
179
  @description)
@@ -186,18 +192,21 @@ module GeneValidator
186
192
 
187
193
  hits_less = hits[0..[no_lines, hits.length - 1].min]
188
194
 
189
- data = hits_less.each_with_index.map { |hit, i|
195
+ data = hits_less.each_with_index.map do |hit, i|
190
196
  { 'y' => i,
191
197
  'start' => hit.hsp_list.map(&:match_query_from).min,
192
198
  'stop' => hit.hsp_list.map(&:match_query_to).max,
193
199
  'color' => 'black',
194
- 'dotted' => 'true' } }.flatten +
195
- hits_less.each_with_index.map { |hit, i|
196
- hit.hsp_list.map { |hsp|
197
- { 'y' => i,
198
- 'start' => hsp.match_query_from,
199
- 'stop' => hsp.match_query_to,
200
- 'color' => 'orange' } } }.flatten
200
+ 'dotted' => 'true' }
201
+ end .flatten +
202
+ hits_less.each_with_index.map do |hit, i|
203
+ hit.hsp_list.map do |hsp|
204
+ { 'y' => i,
205
+ 'start' => hsp.match_query_from,
206
+ 'stop' => hsp.match_query_to,
207
+ 'color' => 'orange' }
208
+ end
209
+ end .flatten
201
210
 
202
211
  Plot.new(data,
203
212
  :lines,
@@ -223,9 +232,11 @@ module GeneValidator
223
232
  hit.hsp_list.map(&:match_query_to).max)
224
233
  end
225
234
 
226
- data = hits.map { |hit| { 'x' => hit.hsp_list.map(&:match_query_from).min,
227
- 'y' => hit.hsp_list.map(&:match_query_to).max,
228
- 'color' => 'red' } }
235
+ data = hits.map do |hit|
236
+ { 'x' => hit.hsp_list.map(&:match_query_from).min,
237
+ 'y' => hit.hsp_list.map(&:match_query_to).max,
238
+ 'color' => 'red' }
239
+ end
229
240
 
230
241
  Plot.new(data,
231
242
  :scatter,