Bio::DB::TFBS namespace has been moved to its own distribution named after itself
[bioperl-live.git] / Bio / Search / Result / CrossMatchResult.pm
blob7fce586ae86517917338222ffd768a33e7934785
1 package Bio::Search::Result::CrossMatchResult;
3 # BioPerl module for Bio::Search::Result::CrossMatchResult
5 # Please direct questions and support issues to <bioperl-l@bioperl.org>
7 # Cared for by Shin Leong <sleong@watson.wustl.edu>
9 # Copyright Shin Leong
11 # You may distribute this module under the same terms as perl itself
13 # POD documentation - main docs before the code
15 =head1 NAME
17 Bio::Search::Result::CrossMatchResult - CrossMatch-specific subclass of Bio::Search::Result::GenericResult
19 =head1 SYNOPSIS
21 # Working with iterations (CrossMatch results)
23 $result->next_iteration();
24 $result->num_iterations();
25 $result->iteration();
26 $result->iterations();
28 # See Bio::Search::Result::GenericResult for information about working with Results.
30 # See L<Bio::Search::Iteration::IterationI|Bio::Search::Iteration::IterationI>
31 # for details about working with iterations.
33 # TODO:
34 # * Show how to configure a SearchIO stream so that it generates
35 # CrossMatchResult objects.
38 =head1 DESCRIPTION
40 This object is a subclass of Bio::Search::Result::GenericResult
41 and provides some operations that facilitate working with CrossMatch
42 and CrossMatch results.
44 For general information about working with Results, see
45 Bio::Search::Result::GenericResult.
47 =head1 FEEDBACK
49 =head2 Mailing Lists
51 User feedback is an integral part of the evolution of this and other
52 Bioperl modules. Send your comments and suggestions preferably to
53 the Bioperl mailing list. Your participation is much appreciated.
55 bioperl-l@bioperl.org - General discussion
56 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
58 =head2 Support
60 Please direct usage questions or support issues to the mailing list:
62 I<bioperl-l@bioperl.org>
64 rather than to the module maintainer directly. Many experienced and
65 reponsive experts will be able look at the problem and quickly
66 address it. Please include a thorough description of the problem
67 with code and data examples if at all possible.
69 =head2 Reporting Bugs
71 Report bugs to the Bioperl bug tracking system to help us keep track
72 of the bugs and their resolution. Bug reports can be submitted via the
73 web:
75 https://github.com/bioperl/bioperl-live/issues
77 =head1 AUTHOR - Shin Leong
79 Email sleong@watson.wustl.edu
81 =head1 CONTRIBUTORS
83 Additional contributors names and emails here
85 =head1 APPENDIX
87 The rest of the documentation details each of the object methods.
88 Internal methods are usually preceded with a _
90 =cut
93 # Let the code begin...
96 package Bio::Search::Result::CrossMatchResult;
97 use strict;
99 use Bio::Search::Result::GenericResult;
101 use base qw(Bio::Search::Result::GenericResult);
103 =head2 new
105 Title : new
106 Usage : my $obj = Bio::Search::Result::CrossMatchResult->new();
107 Function: Builds a new Bio::Search::Result::CrossMatchResult object
108 Returns : Bio::Search::Result::CrossMatchResult
109 Args : See Bio::Search::Result::GenericResult();
110 The following parameters are specific to CrossMatchResult:
111 -iterations => array ref of Bio::Search::Iteration::IterationI objects
112 -inclusion_threshold => e-value threshold for inclusion in the
113 CrossMatch score matrix model (blastpgp)
115 =cut
117 sub new {
118 my($class,@args) = @_;
120 my $self = $class->SUPER::new(@args);
122 $self->{'_iterations'} = [];
123 $self->{'_iteration_index'} = 0;
124 $self->{'_iteration_count'} = 0;
126 my( $iters, $ithresh ) = $self->_rearrange([qw(ITERATIONS
127 INCLUSION_THRESHOLD)],@args);
129 $self->{'_inclusion_threshold'} = $ithresh; # This is a read-only variable
131 if( defined $iters ) {
132 $self->throw("Must define arrayref of Iterations when initializing a $class\n") unless ref($iters) =~ /array/i;
134 foreach my $i ( @{$iters} ) {
135 $self->add_iteration($i);
138 else {
139 # This shouldn't get called with the new SearchIO::blast.
140 #print STDERR "CrossMatchResult::new(): Not adding iterations.\n";
141 $self->{'_no_iterations'} = 1;
144 #$self->SUPER::algorithm('cross_match');
145 return $self;
149 =head2 hits
151 This method overrides L<Bio::Search::Result::GenericResult::hits> to take
152 into account the possibility of multiple iterations, as occurs in CrossMatch reports.
154 If there are multiple iterations, all 'new' hits for all iterations are returned.
155 These are the hits that did not occur in a previous iteration.
157 See Also: L<Bio::Search::Result::GenericResult::hits>
159 =cut
161 sub hits {
162 my ($self) = shift;
163 if ($self->{'_no_iterations'}) {
164 return $self->SUPER::hits;
166 my @hits = ();
167 foreach my $it ($self->iterations) {
168 push @hits, $it->hits;
170 return @hits;
173 =head2 next_hit
175 This method overrides L<Bio::Search::Result::GenericResult::next_hit> to take
176 into account the possibility of multiple iterations, as occurs in CrossMatch reports.
178 If there are multiple iterations, calling next_hit() traverses the
179 all of the hits, old and new, for each iteration, calling next_hit() on each iteration.
181 See Also: L<Bio::Search::Iteration::GenericIteration::next_hit>
183 =cut
185 sub next_hit {
186 my ($self,@args) = @_;
187 if ($self->{'_no_iterations'}) {
188 return $self->SUPER::next_hit(@args);
191 my $iter_index;
192 if (not defined $self->{'_last_hit'}) {
193 $iter_index = $self->{'_iter_index'} = $self->_next_iteration_index;
194 } else {
195 $iter_index = $self->{'_iter_index'};
198 return if $iter_index >= scalar @{$self->{'_iterations'}};
200 my $it = $self->{'_iterations'}->[$iter_index];
201 my $hit = $self->{'_last_hit'} = $it->next_hit;
203 return defined($hit) ? $hit : $self->next_hit;
207 =head2 num_hits
209 This method overrides L<Bio::Search::Result::GenericResult::num_hits> to take
210 into account the possibility of multiple iterations, as occurs in CrossMatch reports.
212 If there are multiple iterations, calling num_hits() returns the number of
213 'new' hits for each iteration. These are the hits that did not occur
214 in a previous iteration.
216 See Also: L<Bio::Search::Result::GenericResult::num_hits>
218 =cut
220 sub num_hits{
221 my ($self) = shift;
222 if ($self->{'_no_iterations'}) {
223 return $self->SUPER::num_hits;
225 if (not defined $self->{'_iterations'}) {
226 $self->throw("Can't get Hits: data not collected.");
228 return scalar( $self->hits );
231 =head2 add_iteration
233 Title : add_iteration
234 Usage : $report->add_iteration($iteration)
235 Function: Adds a IterationI to the stored list of iterations
236 Returns : Number of IterationI currently stored
237 Args : Bio::Search::Iteration::IterationI
239 =cut
241 sub add_iteration {
242 my ($self,$i) = @_;
243 if( $i->isa('Bio::Search::Iteration::IterationI') ) {
244 push @{$self->{'_iterations'}}, $i;
245 $self->{'_iteration_count'}++;
246 } else {
247 $self->throw("Passed in a " .ref($i).
248 " as a Iteration which is not a Bio::Search::IterationI.");
250 return scalar @{$self->{'_iterations'}};
254 =head2 next_iteration
256 Title : next_iteration
257 Usage : while( $it = $result->next_iteration()) { ... }
258 Function: Returns the next Iteration object, representing all hits
259 found within a given CrossMatch iteration.
260 Returns : a Bio::Search::Iteration::IterationI object or undef if there are no more.
261 Args : none
263 =cut
265 sub next_iteration {
266 my ($self) = @_;
268 unless($self->{'_iter_queue_started'}) {
269 $self->{'_iter_queue'} = [$self->iterations()];
270 $self->{'_iter_queue_started'} = 1;
272 return shift @{$self->{'_iter_queue'}};
275 =head2 iteration
277 Usage : $iteration = $blast->iteration( $number );
278 Purpose : Get an IterationI object for the specified iteration
279 in the search result (CrossMatch).
280 Returns : Bio::Search::Iteration::IterationI object
281 Throws : Bio::Root::NoSuchThing exception if $number is not within
282 range of the number of iterations in this report.
283 Argument : integer (optional, if not specified get the last iteration)
284 First iteration = 1
286 =cut
288 sub iteration {
289 my ($self,$num) = @_;
290 $num = scalar @{$self->{'_iterations'}} unless defined $num;
291 unless ($num >= 1 and $num <= scalar $self->{'_iteration_count'}) {
292 $self->throw(-class=>'Bio::Root::NoSuchThing',
293 -text=>"No such iteration number: $num. Valid range=1-$self->{'_iteration_count'}",
294 -value=>$num);
296 return $self->{'_iterations'}->[$num-1];
299 =head2 num_iterations
301 Usage : $num_iterations = $blast->num_iterations;
302 Purpose : Get the number of iterations in the search result (CrossMatch).
303 Returns : Total number of iterations in the report
304 Argument : none (read-only)
306 =cut
308 sub num_iterations { shift->{'_iteration_count'} }
310 # Methods provided for consistency with BPpsilite.pm (now deprecated);
311 # these are now merely synonyms
313 =head2 number_of_iterations
315 Same as L<num_iterations>.
317 =cut
319 sub number_of_iterations { shift->num_iterations }
321 =head2 round
323 Same as L<iteration>.
325 =cut
327 sub round { shift->iteration(@_) }
330 =head2 iterations
332 Title : iterations
333 Usage : my @iterations = $result->iterations
334 Function: Returns the IterationI objects contained within this Result
335 Returns : Array of L<Bio::Search::Iteration::IterationI> objects
336 Args : none
338 =cut
340 sub iterations {
341 my $self = shift;
342 my @its = ();
343 if( ref($self->{'_iterations'}) =~ /ARRAY/i ) {
344 @its = @{$self->{'_iterations'}};
346 return @its;
349 =head2 no_hits_found
351 Usage : $nohits = $blast->no_hits_found( $iteration_number );
352 Purpose : Get boolean indicator indicating whether or not any hits
353 were present in the report.
355 This is NOT the same as determining the number of hits via
356 the hits() method, which will return zero hits if there were no
357 hits in the report or if all hits were filtered out during the parse.
359 Thus, this method can be used to distinguish these possibilities
360 for hitless reports generated when filtering.
362 Returns : Boolean
363 Argument : (optional) integer indicating the iteration number (CrossMatch)
364 If iteration number is not specified and this is a CrossMatch result,
365 then this method will return true only if all iterations had
366 no hits found.
368 =cut
370 sub no_hits_found {
371 my ($self, $round) = @_;
373 my $result = 0; # final return value of this method.
374 # Watch the double negative!
375 # result = 0 means "yes hits were found"
376 # result = 1 means "no hits were found" (for the indicated iteration or all iterations)
378 # If a iteration was not specified and there were multiple iterations,
379 # this method should return true only if all iterations had no hits found.
380 if( not defined $round ) {
381 if( $self->{'_iterations'} > 1) {
382 $result = 1;
383 foreach my $i( 1..$self->{'_iterations'} ) {
384 if( not defined $self->{"_iteration_$i"}->{'_no_hits_found'} ) {
385 $result = 0;
386 last;
390 else {
391 $result = $self->{"_iteration_1"}->{'_no_hits_found'};
394 else {
395 $result = $self->{"_iteration_$round"}->{'_no_hits_found'};
398 return $result;
402 =head2 set_no_hits_found
404 Usage : $blast->set_no_hits_found( $iteration_number );
405 Purpose : Set boolean indicator indicating whether or not any hits
406 were present in the report.
407 Returns : n/a
408 Argument : (optional) integer indicating the iteration number (CrossMatch)
410 =cut
412 sub set_no_hits_found {
413 my ($self, $round) = @_;
414 $round ||= 1;
415 $self->{"_iteration_$round"}->{'_no_hits_found'} = 1;
418 =head2 _next_iteration_index
420 Title : _next_iteration_index
421 Usage : private
423 =cut
425 sub _next_iteration_index{
426 my ($self,@args) = @_;
427 return $self->{'_iteration_index'}++;
431 =head2 rewind
433 Title : rewind
434 Usage : $result->rewind;
435 Function: Allow one to reset the Iteration iterator to the beginning
436 Since this is an in-memory implementation
437 Returns : none
438 Args : none
440 =cut
442 sub rewind {
443 my $self = shift;
444 $self->SUPER::rewind(@_);
445 $self->{'_iteration_index'} = 0;
446 foreach ($self->iterations) {
447 $_->rewind;
452 =head2 inclusion_threshold
454 Title : inclusion_threshold
455 Usage : my $incl_thresh = $result->inclusion_threshold; (read-only)
456 Function: Gets the e-value threshold for inclusion in the CrossMatch
457 score matrix model (blastpgp) that was used for generating the report
458 being parsed.
459 Returns : number (real) or undef if not a CrossMatch report.
460 Args : none
462 =cut
464 sub inclusion_threshold {
465 my $self = shift;
466 return $self->{'_inclusion_threshold'};
470 sub algorithm_old {
471 my $self = shift;
472 my $value = shift;
473 if($value) {
474 print STDERR "Cannot set the algorightm on this class!\n";
475 return $self->SUPER::algorithm;
476 } else {
477 return $self->SUPER::algorithm;
482 #$Header$