File Coverage

Bio/Map/Mappable.pm
Criterion Covered Total %
statement 167 186 89.7
branch 69 92 75.0
condition 6 16 37.5
subroutine 16 19 84.2
pod 14 14 100.0
total 272 327 83.1


line stmt bran cond sub pod time code
1             #
2             # BioPerl module for Bio::Map::Mappable
3             #
4             # Please direct questions and support issues to
5             #
6             # Cared for by Sendu Bala
7             #
8             # Copyright Sendu Bala
9             #
10             # You may distribute this module under the same terms as perl itself
11              
12             # POD documentation - main docs before the code
13              
14             =head1 NAME
15              
16             Bio::Map::Mappable - An object representing a generic map element
17             that can have multiple locations in several maps.
18              
19             =head1 SYNOPSIS
20              
21             # a map element in two different positions on the same map
22             $map1 = Bio::Map::SimpleMap->new();
23             $position1 = Bio::Map::Position->new(-map => $map1, -value => 100);
24             $position2 = Bio::Map::Position->new(-map => $map1, -value => 200);
25             $mappable = Bio::Map::Mappable->new(-positions => [$position1, $position2] );
26              
27             # add another position on a different map
28             $map2 = Bio::Map::SimpleMap->new();
29             $position3 = Bio::Map::Position->new(-map => $map2, $value => 50);
30             $mappable->add_position($position3);
31              
32             # get all the places our map element is found, on a particular map of interest
33             foreach $pos ($mappable->get_positions($map1)) {
34             print $pos->value, "\n";
35             }
36              
37             =head1 DESCRIPTION
38              
39             This object handles the notion of a generic map element. Mappables are
40             entities with one or more positions on one or more maps.
41              
42             This object is a pure perl implementation of L. That
43             interface implements some of its own methods so check the docs there for
44             those.
45              
46             =head1 FEEDBACK
47              
48             =head2 Mailing Lists
49              
50             User feedback is an integral part of the evolution of this and other
51             Bioperl modules. Send your comments and suggestions preferably to the
52             Bioperl mailing list. Your participation is much appreciated.
53              
54             bioperl-l@bioperl.org - General discussion
55             http://bioperl.org/wiki/Mailing_lists - About the mailing lists
56              
57             =head2 Support
58              
59             Please direct usage questions or support issues to the mailing list:
60              
61             I
62              
63             rather than to the module maintainer directly. Many experienced and
64             reponsive experts will be able look at the problem and quickly
65             address it. Please include a thorough description of the problem
66             with code and data examples if at all possible.
67              
68             =head2 Reporting Bugs
69              
70             Report bugs to the Bioperl bug tracking system to help us keep track
71             of the bugs and their resolution. Bug reports can be submitted via the
72             web:
73              
74             https://github.com/bioperl/bioperl-live/issues
75              
76             =head1 AUTHOR - Sendu Bala
77              
78             Email bix@sendu.me.uk
79              
80             =head1 APPENDIX
81              
82             The rest of the documentation details each of the object methods.
83             Internal methods are usually preceded with a _
84              
85             =cut
86              
87             # Let the code begin...
88              
89             package Bio::Map::Mappable;
90 9     9   33 use strict;
  9         9  
  9         205  
91 9     9   28 use Bio::Map::Relative;
  9         10  
  9         127  
92 9     9   26 use Bio::Map::Position;
  9         10  
  9         168  
93              
94 9     9   25 use base qw(Bio::Root::Root Bio::Map::MappableI);
  9         10  
  9         2819  
95              
96             =head2 new
97              
98             Title : new
99             Usage : my $mappable = Bio::Map::Mappable->new();
100             Function: Builds a new Bio::Map::Mappable object
101             Returns : Bio::Map::Mappable
102             Args : -name => string : name of the mappable element
103             -id => string : id of the mappable element
104              
105             =cut
106              
107             sub new {
108 114     114 1 168 my ($class, @args) = @_;
109 114         234 my $self = $class->SUPER::new(@args);
110            
111 114         289 my ($name, $id) = $self->_rearrange([qw(NAME ID)], @args);
112 114 100       246 $self->name($name) if $name;
113 114 50       151 $self->id($id) if $id;
114            
115 114         174 return $self;
116             }
117              
118             =head2 name
119              
120             Title : name
121             Usage : $mappable->name($new_name);
122             my $name = $mappable->name();
123             Function: Get/Set the name for this Mappable
124             Returns : A scalar representing the current name of this Mappable
125             Args : none to get
126             string to set
127              
128             =cut
129              
130             sub name {
131 85     85 1 65 my $self = shift;
132 85 100       121 if (@_) { $self->{_name} = shift }
  82         114  
133 85   50     146 return $self->{_name} || '';
134             }
135              
136             =head2 id
137              
138             Title : id
139             Usage : my $id = $mappable->id();
140             $mappable->id($new_id);
141             Function: Get/Set the id for this Mappable.
142             Returns : A scalar representing the current id of this Mappable
143             Args : none to get
144             string to set
145              
146             =cut
147              
148             sub id {
149 0     0 1 0 my $self = shift;
150 0 0       0 if (@_) { $self->{_id} = shift }
  0         0  
151 0   0     0 return $self->{_id} || return;
152             }
153              
154             =head2 in_map
155              
156             Title : in_map
157             Usage : if ($mappable->in_map($map)) {...}
158             Function: Tests if this mappable is found on a specific map
159             Returns : boolean
160             Args : L
161              
162             =cut
163              
164             sub in_map {
165 332     332 1 298 my ($self, $query_map) = @_;
166 332 50       466 $self->throw("Must supply an argument") unless $query_map;
167 332 50       459 $self->throw("This is [$query_map], not an object") unless ref($query_map);
168 332 50       715 $self->throw("This is [$query_map], not a Bio::Map::MapI object") unless $query_map->isa('Bio::Map::MapI');
169            
170 332         488 foreach my $map ($self->known_maps) {
171 513 100       1652 ($map eq $query_map) && return 1;
172             }
173            
174 0         0 return 0;
175             }
176              
177             =head2 Comparison methods
178              
179             =cut
180              
181             =head2 equals
182              
183             Title : equals
184             Usage : if ($mappable->equals($other_mappable)) {...}
185             my @equal_positions = $mappable->equals($other_mappable);
186             Function: Finds the positions in this mappable that are equal to any
187             comparison positions.
188             Returns : array of L objects
189             Args : arg #1 = L OR L to compare
190             this one to (mandatory)
191             arg #2 = optionally, one or more of the key => value pairs below
192             -map => MapI : a Bio::Map::MapI to only consider positions
193             on the given map
194             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
195             of each Position's relative position to the
196             thing described by that Relative
197              
198             =cut
199              
200             sub equals {
201 5     5 1 272 my $self = shift;
202 5         21 return $self->_compare('equals', @_);
203             }
204              
205             =head2 less_than
206              
207             Title : less_than
208             Usage : if ($mappable->less_than($other_mappable)) {...}
209             my @lesser_positions = $mappable->less_than($other_mappable);
210             Function: Finds the positions in this mappable that are less than all
211             comparison positions.
212             Returns : array of L objects
213             Args : arg #1 = L OR L to compare
214             this one to (mandatory)
215             arg #2 = optionally, one or more of the key => value pairs below
216             -map => MapI : a Bio::Map::MapI to only consider positions
217             on the given map
218             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
219             of each Position's relative position to the
220             thing described by that Relative
221              
222             =cut
223              
224             sub less_than {
225 3     3 1 5 my $self = shift;
226 3         9 return $self->_compare('less_than', @_);
227             }
228              
229             =head2 greater_than
230              
231             Title : greater_than
232             Usage : if ($mappable->greater_than($other_mappable)) {...}
233             my @greater_positions = $mappable->greater_than($other_mappable);
234             Function: Finds the positions in this mappable that are greater than all
235             comparison positions.
236             Returns : array of L objects
237             Args : arg #1 = L OR L to compare
238             this one to (mandatory)
239             arg #2 = optionally, one or more of the key => value pairs below
240             -map => MapI : a Bio::Map::MapI to only consider positions
241             on the given map
242             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
243             of each Position's relative position to the
244             thing described by that Relative
245              
246             =cut
247              
248             sub greater_than {
249 4     4 1 6 my $self = shift;
250 4         10 return $self->_compare('greater_than', @_);
251             }
252              
253             =head2 overlaps
254              
255             Title : overlaps
256             Usage : if ($mappable->overlaps($other_mappable)) {...}
257             my @overlapping_positions = $mappable->overlaps($other_mappable);
258             Function: Finds the positions in this mappable that overlap with any
259             comparison positions.
260             Returns : array of L objects
261             Args : arg #1 = L OR L to compare
262             this one to (mandatory)
263             arg #2 = optionally, one or more of the key => value pairs below
264             -map => MapI : a Bio::Map::MapI to only consider positions
265             on the given map
266             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
267             of each Position's relative position to the
268             thing described by that Relative
269              
270             =cut
271              
272             sub overlaps {
273 6     6 1 371 my $self = shift;
274 6         13 return $self->_compare('overlaps', @_);
275             }
276              
277             =head2 contains
278              
279             Title : contains
280             Usage : if ($mappable->contains($other_mappable)) {...}
281             my @container_positions = $mappable->contains($other_mappable);
282             Function: Finds the positions in this mappable that contain any comparison
283             positions.
284             Returns : array of L objects
285             Args : arg #1 = L OR L to compare
286             this one to (mandatory)
287             arg #2 = optionally, one or more of the key => value pairs below
288             -map => MapI : a Bio::Map::MapI to only consider positions
289             on the given map
290             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
291             of each Position's relative position to the
292             thing described by that Relative
293              
294             =cut
295              
296             sub contains {
297 3     3 1 5 my $self = shift;
298 3         8 return $self->_compare('contains', @_);
299             }
300              
301             =head2 overlapping_groups
302              
303             Title : overlapping_groups
304             Usage : my @groups = $mappable->overlapping_groups($other_mappable);
305             my @groups = Bio::Map::Mappable->overlapping_groups(\@mappables);
306             Function: Look at all the positions of all the supplied mappables and group
307             them according to overlap.
308             Returns : array of array refs, each ref containing the Bio::Map::PositionI
309             objects that overlap with each other
310             Args : arg #1 = L OR L to compare
311             this one to, or an array ref of such objects (mandatory)
312             arg #2 = optionally, one or more of the key => value pairs below
313             -map => MapI : a Bio::Map::MapI to only consider positions
314             on the given map
315             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
316             of each Position's relative position to the
317             thing described by that Relative
318             -min_pos_num => int : the minimum number of positions that must
319             be in a group before it will be returned
320             [default is 1]
321             -min_mappables_num => int : the minimum number of different
322             mappables represented by the
323             positions in a group before it
324             will be returned [default is 1]
325             -min_mappables_percent => number : as above, but the minimum
326             percentage of input mappables
327             [default is 0]
328             -min_map_num => int : the minimum number of different
329             maps represented by the positions
330             in a group before it will be
331             returned [default is 1]
332             -min_map_percent => number : as above, but the minimum
333             percentage of maps known by the
334             input mappables [default is 0]
335             -require_self => 1|0 : require that at least one of the
336             calling object's positions be in
337             each group [default is 1, has no
338             effect when the second usage form
339             is used]
340             -required => \@mappables : require that at least one position
341             for each mappable supplied in this
342             array ref be in each group
343              
344             =cut
345              
346             sub overlapping_groups {
347 7     7 1 2017 my $self = shift;
348 7         16 return $self->_compare('overlapping_groups', @_);
349             }
350              
351             =head2 disconnected_intersections
352              
353             Title : disconnected_intersections
354             Usage : @positions = $mappable->disconnected_intersections($other_mappable);
355             @positions = Bio::Map::Mappable->disconnected_intersections(\@mappables);
356             Function: Make the positions that are at the intersection of each group of
357             overlapping positions, considering all the positions of the supplied
358             mappables.
359             Returns : new Bio::Map::Mappable who's positions on maps are the calculated
360             disconnected unions
361             Args : arg #1 = L OR L to compare
362             this one to, or an array ref of such objects (mandatory)
363             arg #2 = optionally, one or more of the key => value pairs below
364             -map => MapI : a Bio::Map::MapI to only consider positions
365             on the given map
366             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
367             of each Position's relative position to the
368             thing described by that Relative
369             -min_pos_num => int : the minimum number of positions that must
370             be in a group before the intersection will
371             be calculated and returned [default is 1]
372             -min_mappables_num => int : the minimum number of different
373             mappables represented by the
374             positions in a group before the
375             intersection will be calculated
376             and returned [default is 1]
377             -min_mappables_percent => number : as above, but the minimum
378             percentage of input mappables
379             [default is 0]
380             -min_map_num => int : the minimum number of different
381             maps represented by the positions
382             in a group before the intersection
383             will be calculated and returned
384             [default is 1]
385             -min_map_percent => number : as above, but the minimum
386             percentage of maps known by the
387             input mappables [default is 0]
388             -require_self => 1|0 : require that at least one of the
389             calling object's positions be in
390             each group [default is 1, has no
391             effect when the second usage form
392             is used]
393             -required => \@mappables : require that at least one position
394             for each mappable supplied in this
395             array ref be in each group
396              
397             =cut
398              
399             sub disconnected_intersections {
400 2     2 1 11 my $self = shift;
401 2         7 return $self->_compare('intersection', @_);
402             }
403              
404             =head2 disconnected_unions
405              
406             Title : disconnected_unions
407             Usage : my @positions = $mappable->disconnected_unions($other_mappable);
408             my @positions = Bio::Map::Mappable->disconnected_unions(\@mappables);
409             Function: Make the positions that are the union of each group of overlapping
410             positions, considering all the positions of the supplied mappables.
411             Returns : new Bio::Map::Mappable who's positions on maps are the calculated
412             disconnected unions
413             Args : arg #1 = L OR L to compare
414             this one to, or an array ref of such objects (mandatory)
415             arg #2 = optionally, one or more of the key => value pairs below
416             -map => MapI : a Bio::Map::MapI to only consider positions
417             on the given map
418             -relative => RelativeI : a Bio::Map::RelativeI to calculate in terms
419             of each Position's relative position to the
420             thing described by that Relative
421             -min_pos_num => int : the minimum number of positions that must
422             be in a group before the union will be
423             calculated and returned [default is 1]
424             -min_mappables_num => int : the minimum number of different
425             mappables represented by the
426             positions in a group before the
427             union will be calculated and
428             returned [default is 1]
429             -min_mappables_percent => number : as above, but the minimum
430             percentage of input mappables
431             [default is 0]
432             -min_map_num => int : the minimum number of different
433             maps represented by the positions
434             in a group before the union will
435             be calculated and returned
436             [default is 1]
437             -min_map_percent => number : as above, but the minimum
438             percentage of maps known by the
439             input mappables [default is 0]
440             -require_self => 1|0 : require that at least one of the
441             calling object's positions be in
442             each group [default is 1, has no
443             effect when the second usage form
444             is used]
445             -required => \@mappables : require that at least one position
446             for each mappable supplied in this
447             array ref be in each group
448              
449             =cut
450              
451             sub disconnected_unions {
452 1     1 1 2 my $self = shift;
453 1         3 return $self->_compare('union', @_);
454             }
455              
456             # do a RangeI-related comparison by calling the corresponding PositionI method
457             # on all the requested Positions of our Mappables
458             sub _compare {
459 31     31   54 my ($self, $method, $input, @extra_args) = @_;
460 31 50       65 $self->throw("Must supply an object or array ref of them") unless ref($input);
461 31 50       67 $self->throw("Wrong number of extra args (should be key => value pairs)") unless @extra_args % 2 == 0;
462 31 100       70 my @compares = ref($input) eq 'ARRAY' ? @{$input} : ($input);
  10         23  
463            
464 31         209 my %args = (-map => undef, -relative => undef, -min_pos_num => 1,
465             -min_mappables_num => 1, -min_mappables_percent => 0,
466             -min_map_num => 1, -min_map_percent => 0,
467             -require_self => 0, -required => undef, -min_overlap_percent => 0, @extra_args);
468 31         40 my $map = $args{-map};
469 31         36 my $rel = $args{-relative};
470 31         38 my $overlap = $args{-min_overlap_percent};
471 31         34 my $min_pos_num = $args{-min_pos_num};
472 31         33 my $min_pables_num = $args{-min_mappables_num};
473 31 100       56 if ($args{-min_mappables_percent}) {
474 3 100       16 my $mn = (@compares + (ref($self) ? 1 : 0)) / 100 * $args{-min_mappables_percent};
475 3 100       9 if ($mn > $min_pables_num) {
476 2         4 $min_pables_num = $mn;
477             }
478             }
479 31         44 my $min_map_num = $args{-min_map_num};
480 31 100       53 if ($args{-min_map_percent}) {
481 1         2 my %known_maps;
482 1 50       4 foreach my $pable (@compares, ref($self) ? ($self) : ()) {
483 2         8 foreach my $known ($pable->known_maps) {
484 9         12 $known_maps{$known->unique_id} = 1;
485             }
486             }
487 1         7 my $mn = scalar(keys %known_maps) / 100 * $args{-min_map_percent};
488 1 50       3 if ($mn > $min_map_num) {
489 1         3 $min_map_num = $mn;
490             }
491             }
492 31 100       69 my %required = map { $_ => 1 } $args{-required} ? @{$args{-required}} : ();
  1         4  
  1         2  
493 31         24 my (@mine, @yours);
494            
495 31 100       54 if (ref($self)) {
496 30         60 @mine = $self->get_positions($map);
497 30 100       70 if ($args{-require_self}) {
498 1 50       3 @mine > 0 or return;
499 1         3 $required{$self} = 1;
500             }
501             }
502 31         48 my @required = sort keys %required;
503            
504 31         54 foreach my $compare (@compares) {
505 59 50       187 if ($compare->isa('Bio::Map::PositionI')) {
    50          
506 0         0 push(@yours, $compare);
507             }
508             elsif ($compare->isa('Bio::Map::MappableI')) {
509 59         79 push(@yours, $compare->get_positions($map));
510             }
511             else {
512 0         0 $self->throw("This is [$compare], not a Bio::Map::MappableI or Bio::Map::PositionI");
513             }
514             }
515 31 50       54 @yours > 0 or return;
516            
517 31         28 my @ok;
518 31         42 SWITCH: for ($method) {
519 31 100       145 /equals|overlaps|contains/ && do {
520 14 50       22 @mine > 0 or return;
521 14         19 foreach my $my_pos (@mine) {
522 14         17 foreach my $your_pos (@yours) {
523 14 100       47 if ($my_pos->$method($your_pos, undef, $rel)) {
524 8         13 push(@ok, $my_pos);
525 8         18 last;
526             }
527             }
528             }
529 14         25 last SWITCH;
530             };
531 17 100       61 /less_than|greater_than/ && do {
532 7 50       14 @mine > 0 or return;
533 7 100       14 if ($method eq 'greater_than') {
534 4         10 @mine = map { $_->[1] }
535 0         0 sort { $b->[0] <=> $a->[0] }
536 4         6 map { [$_->end($_->absolute_relative), $_] }
  4         13  
537             @mine;
538 4         10 @yours = map { $_->[1] }
539 0         0 sort { $b->[0] <=> $a->[0] }
540 4         8 map { [$_->end($_->absolute_relative), $_] }
  4         8  
541             @yours;
542             }
543 7         8 my $test_pos = shift(@yours);
544            
545 7         9 foreach my $my_pos (@mine) {
546 7 100       36 if ($my_pos->$method($test_pos, $rel)) {
547 4         10 push(@ok, $my_pos);
548             }
549             else {
550 3         5 last;
551             }
552             }
553            
554 7 100       16 if ($method eq 'greater_than') {
555 2         6 @ok = map { $_->[1] }
556 0         0 sort { $a->[0] <=> $b->[0] }
557 4         10 map { [$_->sortable, $_] }
  2         11  
558             @ok;
559             }
560            
561 7         23 last SWITCH;
562             };
563 10 50       68 /overlapping_groups|intersection|union/ && do {
564 10         19 my @positions = (@mine, @yours);
565 10         13 my $start_pos = shift(@positions);
566            
567 10   50     39 my $dr_able = $start_pos->disconnected_ranges(\@positions, $rel, $overlap) || return;
568 10         23 my @disconnected_ranges = $dr_able->get_positions;
569            
570             #print "got ", scalar(@disconnected_ranges), " disconnected_ranges, first has range ", $disconnected_ranges[0]->toString, "\n";
571            
572             #use Benchmark qw(:all);
573             #my $t0 = new Benchmark;
574            
575 10         11 my %all_groups;
576             my %done_ranges;
577 10         32 for my $i (0..$#disconnected_ranges) {
578 30         35 my $range = $disconnected_ranges[$i];
579 30         47 my $range_string = $range->toString;
580 30 100       62 next if $done_ranges{$range_string};
581 20         29 $done_ranges{$range_string} = 1;
582            
583 20         31 foreach my $pos ($start_pos, @positions) {
584 110 100       189 if ($pos->overlaps($range, undef, $rel)) {
585 55         149 $all_groups{$range_string}->{$pos} = $pos;
586             }
587             }
588             }
589            
590             #my $t1 = new Benchmark;
591             #my $td = timediff($t1, $t0);
592             #print "grouping took: ",timestr($td),"\n";
593            
594             # purge the temporary working (not $dr_able->purge_positions since
595             # that removes the element from each position, but leaves it on
596             # the map. *** need complete purge that removes position from
597             # memory...
598 10         20 foreach my $pos (@disconnected_ranges) {
599 30   50     44 my $map = $pos->map || next;
600 30         49 $map->purge_positions($pos);
601             }
602            
603 10         13 my @groups;
604 10         35 GROUPS: foreach my $group_range (sort keys %all_groups) {
605 20         20 my $group = $all_groups{$group_range};
606 20         23 my @group = sort values %{$group};
  20         99  
607             #print "* in group $group_range, there are ", scalar(@group), " members\n";
608            
609 20 100       43 @group >= $min_pos_num or next;
610 19 100       42 @group >= $min_pables_num or next; # shortcut before having to work it out properly
611 15 100       22 @group >= $min_map_num or next; # shortcut before having to work it out properly
612            
613 14         14 my %mappables;
614 14         17 foreach my $pos (@group) {
615 48   50     71 my $mappable = $pos->element || next;
616 48         107 $mappables{$mappable} = 1;
617             }
618 14 50       28 keys %mappables >= $min_pables_num || next;
619            
620 14         8 my %maps;
621 14         18 foreach my $pos (@group) {
622 48   50     64 my $map = $pos->map || next;
623 48         72 $maps{$map->unique_id} = 1;
624             }
625 14 50       28 keys %maps >= $min_map_num || next;
626            
627 14         17 foreach my $required (@required) {
628 4 100       12 exists $mappables{$required} or next GROUPS;
629             }
630            
631 46         57 my @sorted = map { $_->[1] }
632 53         54 sort { $a->[0] <=> $b->[0] }
633 12         13 map { [$_->sortable, $_] }
  46         71  
634             @group;
635 12         48 push(@groups, \@sorted);
636             }
637            
638 10 100       24 if ($method eq 'overlapping_groups') {
639 7         81 return @groups;
640             }
641             else {
642 3         5 foreach my $group (@groups) {
643 3         4 my $start_pos = shift(@{$group});
  3         6  
644            
645 3 50       4 unless (@{$group}) {
  3         7  
646             # we'll consider the 'intersection' or 'union' of just
647             # one position as the position itself
648 0         0 push(@ok, Bio::Map::Position->new(-map => $start_pos->map,
649             -start => $start_pos->start,
650             -end => $start_pos->end));
651             }
652             else {
653 3 100       10 my @rel_arg = $method eq 'intersection' ? (undef, $rel) : ($rel);
654 3   50     19 my $result = $start_pos->$method($group, @rel_arg) || next;
655 3         8 push(@ok, $result->get_positions);
656             }
657             }
658            
659             # assign all the positions to a result mappable
660 3         7 my $result = $self->new();
661 3 50       10 $result->add_position(@ok) if @ok; # add_position can actually take a list
662            
663 3         53 return $result;
664             }
665            
666 0         0 last SWITCH;
667             };
668            
669 0         0 $self->throw("Unknown method '$method'");
670             }
671            
672 21         113 return @ok;
673             }
674              
675             =head2 tuple
676              
677             Title : tuple
678             Usage : Do Not Use!
679             Function: tuple was supposed to be a private method; this method no longer
680             does anything
681             Returns : warning
682             Args : none
683             Status : deprecated, will be removed in next version
684              
685             =cut
686              
687             sub tuple {
688 0     0 1   my $self = shift;
689 0           $self->warn("The tuple method was supposed to be a private method, don't call it!");
690             }
691              
692             =head2 annotation
693              
694             Title : annotation
695             Usage : $mappable->annotation($an_col);
696             my $an_col = $mappable->annotation();
697             Function: Get the annotation collection (see Bio::AnnotationCollectionI)
698             for this annotatable object.
699             Returns : a Bio::AnnotationCollectionI implementing object, or undef
700             Args : none to get, OR
701             a Bio::AnnotationCollectionI implementing object to set
702              
703             =cut
704              
705             sub annotation {
706 0     0 1   my $self = shift;
707 0 0         if (@_) { $self->{_annotation} = shift }
  0            
708 0   0       return $self->{_annotation} || return;
709             }
710              
711             1;