Use /usr/bin/perl instead of env even on examples
[bioperl-live.git] / lib / Bio / Annotation / Collection.pm
blobcefb65a8daec89b230db0295e5442669c25fd65b
2 # BioPerl module for Bio::Annotation::Collection.pm
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Ewan Birney <birney@ebi.ac.uk>
8 # Copyright Ewan Birney
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
14 =head1 NAME
16 Bio::Annotation::Collection - Default Perl implementation of
17 AnnotationCollectionI
19 =head1 SYNOPSIS
21 # get an AnnotationCollectionI somehow, eg
23 $ac = $seq->annotation();
25 foreach $key ( $ac->get_all_annotation_keys() ) {
26 @values = $ac->get_Annotations($key);
27 foreach $value ( @values ) {
28 # value is an Bio::AnnotationI, and defines a "as_text" method
29 print "Annotation ",$key," stringified value ",$value->as_text,"\n";
31 # also defined hash_tree method, which allows data orientated
32 # access into this object
33 $hash = $value->hash_tree();
37 =head1 DESCRIPTION
39 Bioperl implementation for Bio::AnnotationCollectionI
41 =head1 FEEDBACK
43 =head2 Mailing Lists
45 User feedback is an integral part of the evolution of this and other
46 Bioperl modules. Send your comments and suggestions preferably to one
47 of the Bioperl mailing lists. Your participation is much appreciated.
49 bioperl-l@bioperl.org - General discussion
50 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
52 =head2 Support
54 Please direct usage questions or support issues to the mailing list:
56 I<bioperl-l@bioperl.org>
58 rather than to the module maintainer directly. Many experienced and
59 reponsive experts will be able look at the problem and quickly
60 address it. Please include a thorough description of the problem
61 with code and data examples if at all possible.
63 =head2 Reporting Bugs
65 Report bugs to the Bioperl bug tracking system to help us keep track
66 the bugs and their resolution. Bug reports can be submitted via
67 the web:
69 https://github.com/bioperl/bioperl-live/issues
71 =head1 AUTHOR - Ewan Birney
73 Email birney@ebi.ac.uk
75 =head1 APPENDIX
77 The rest of the documentation details each of the object
78 methods. Internal methods are usually preceded with a _
80 =cut
83 # Let the code begin...
86 package Bio::Annotation::Collection;
88 use strict;
90 use Carp;
92 # Object preamble - inherits from Bio::Root::Root
94 use Bio::Annotation::TypeManager;
95 use Bio::Annotation::SimpleValue;
98 use base qw(Bio::Root::Root Bio::AnnotationCollectionI Bio::AnnotationI);
101 =head2 new
103 Title : new
104 Usage : $coll = Bio::Annotation::Collection->new()
105 Function: Makes a new Annotation::Collection object.
106 Returns : Bio::Annotation::Collection
107 Args : none
109 =cut
111 sub new{
112 my ($class,@args) = @_;
114 my $self = $class->SUPER::new(@args);
116 $self->{'_annotation'} = {};
117 $self->_typemap(Bio::Annotation::TypeManager->new());
119 return $self;
123 =head1 L<Bio::AnnotationCollectionI> implementing methods
125 =cut
127 =head2 get_all_annotation_keys
129 Title : get_all_annotation_keys
130 Usage : $ac->get_all_annotation_keys()
131 Function: gives back a list of annotation keys, which are simple text strings
132 Returns : list of strings
133 Args : none
135 =cut
137 sub get_all_annotation_keys{
138 my ($self) = @_;
139 return keys %{$self->{'_annotation'}};
142 =head2 get_Annotations
144 Title : get_Annotations
145 Usage : my @annotations = $collection->get_Annotations('key')
146 Function: Retrieves all the Bio::AnnotationI objects for one or more
147 specific key(s).
149 If no key is given, returns all annotation objects.
151 The returned objects will have their tagname() attribute set to
152 the key under which they were attached, unless the tagname was
153 already set.
155 Returns : list of Bio::AnnotationI - empty if no objects stored for a key
156 Args : keys (list of strings) for annotations (optional)
158 =cut
160 sub get_Annotations{
161 my ($self,@keys) = @_;
163 my @anns = ();
164 @keys = $self->get_all_annotation_keys() unless @keys;
165 foreach my $key (@keys) {
166 if(exists($self->{'_annotation'}->{$key})) {
167 push(@anns,
168 map {
169 $_->tagname($key) if ! $_->tagname(); $_;
170 } @{$self->{'_annotation'}->{$key}});
173 return @anns;
177 =head2 get_nested_Annotations
179 Title : get_nested_Annotations
180 Usage : my @annotations = $collection->get_nested_Annotations(
181 '-key' => \@keys,
182 '-recursive => 1);
183 Function: Retrieves all the Bio::AnnotationI objects for one or more
184 specific key(s). If -recursive is set to true, traverses the nested
185 annotation collections recursively and returns all annotations
186 matching the key(s).
188 If no key is given, returns all annotation objects.
190 The returned objects will have their tagname() attribute set to
191 the key under which they were attached, unless the tagname was
192 already set.
194 Returns : list of Bio::AnnotationI - empty if no objects stored for a key
195 Args : -keys => arrayref of keys to search for (optional)
196 -recursive => boolean, whether or not to recursively traverse the
197 nested annotations and return annotations with matching keys.
199 =cut
201 sub get_nested_Annotations {
202 my ($self, @args) = @_;
203 my ($keys, $recursive) = $self->_rearrange([qw(KEYS RECURSIVE)], @args);
204 $self->verbose(1);
206 my @anns = ();
207 # if not recursive behave exactly like get_Annotations()
208 if (!$recursive) {
209 my @keys = $keys? @$keys : $self->get_all_annotation_keys();
210 foreach my $key (@keys) {
211 if(exists($self->{'_annotation'}->{$key})) {
212 push(@anns,
213 map {
214 $_->tagname($key) if ! $_->tagname(); $_;
215 } @{$self->{'_annotation'}->{$key}});
219 # if recursive search for keys recursively
220 else {
221 my @allkeys = $self->get_all_annotation_keys();
222 foreach my $key (@allkeys) {
223 my $keymatch = 0;
224 foreach my $searchkey (@$keys) {
225 if ($key eq $searchkey) { $keymatch = 1;}
227 if ($keymatch) {
228 if(exists($self->{'_annotation'}->{$key})) {
229 push(@anns,
230 map {
231 $_->tagname($key) if ! $_->tagname(); $_;
232 } @{$self->{'_annotation'}->{$key}});
235 else {
236 my @annotations = @{$self->{'_annotation'}->{$key}};
237 foreach (@annotations) {
238 if ($_->isa("Bio::AnnotationCollectionI")) {
239 push (@anns,
240 $_->get_nested_Annotations('-keys' => $keys, '-recursive' => 1)
247 return @anns;
250 =head2 get_all_Annotations
252 Title : get_all_Annotations
253 Usage :
254 Function: Similar to get_Annotations, but traverses and flattens nested
255 annotation collections. This means that collections in the
256 tree will be replaced by their components.
258 Keys will not be passed on to nested collections. I.e., if the
259 tag name of a nested collection matches the key, it will be
260 flattened in its entirety.
262 Hence, for un-nested annotation collections this will be identical
263 to get_Annotations.
264 Example :
265 Returns : an array of L<Bio::AnnotationI> compliant objects
266 Args : keys (list of strings) for annotations (optional)
269 =cut
271 sub get_all_Annotations{
272 my ($self,@keys) = @_;
274 return map {
275 $_->isa("Bio::AnnotationCollectionI") ?
276 $_->get_all_Annotations() : $_;
277 } $self->get_Annotations(@keys);
281 =head2 get_num_of_annotations
283 Title : get_num_of_annotations
284 Usage : my $count = $collection->get_num_of_annotations()
285 Function: Returns the count of all annotations stored in this collection
286 Returns : integer
287 Args : none
290 =cut
292 sub get_num_of_annotations{
293 my ($self) = @_;
294 my $count = 0;
295 map { $count += scalar @$_ } values %{$self->{'_annotation'}};
296 return $count;
299 =head1 Implementation specific functions - mainly for adding
301 =cut
303 =head2 add_Annotation
305 Title : add_Annotation
306 Usage : $self->add_Annotation('reference',$object);
307 $self->add_Annotation($object,'Bio::MyInterface::DiseaseI');
308 $self->add_Annotation($object);
309 $self->add_Annotation('disease',$object,'Bio::MyInterface::DiseaseI');
310 Function: Adds an annotation for a specific key.
312 If the key is omitted, the object to be added must provide a value
313 via its tagname().
315 If the archetype is provided, this and future objects added under
316 that tag have to comply with the archetype and will be rejected
317 otherwise.
319 Returns : none
320 Args : annotation key ('disease', 'dblink', ...)
321 object to store (must be Bio::AnnotationI compliant)
322 [optional] object archetype to map future storage of object
323 of these types to
325 =cut
327 sub add_Annotation{
328 my ($self,$key,$object,$archetype) = @_;
330 # if there's no key we use the tagname() as key
331 if(ref($key) && $key->isa("Bio::AnnotationI") && (!ref($object))) {
332 $archetype = $object if defined($object);
333 $object = $key;
334 $key = $object->tagname();
335 $key = $key->name() if ref($key); # OntologyTermI
336 $self->throw("Annotation object must have a tagname if key omitted")
337 unless $key;
340 if( !defined $object ) {
341 $self->throw("Must have at least key and object in add_Annotation");
344 if( !ref $object ) {
345 $self->throw("Must add an object. Use Bio::Annotation::{Comment,SimpleValue,OntologyTerm} for simple text additions");
348 if( !$object->isa("Bio::AnnotationI") ) {
349 $self->throw("object must be AnnotationI compliant, otherwise we won't add it!");
352 # ok, now we are ready! If we don't have an archetype, set it
353 # from the type of the object
355 if( !defined $archetype ) {
356 $archetype = ref $object;
359 # check typemap, storing if needed.
360 my $stored_map = $self->_typemap->type_for_key($key);
362 if( defined $stored_map ) {
363 # check validity, irregardless of archetype. A little cheeky
364 # this means isa stuff is executed correctly
366 if( !$self->_typemap()->is_valid($key,$object) ) {
367 $self->throw("Object $object was not valid with key $key. ".
368 "If you were adding new keys in, perhaps you want to make use\n".
369 "of the archetype method to allow registration to a more basic type");
371 } else {
372 $self->_typemap->_add_type_map($key,$archetype);
375 # we are ok to store
377 if( !defined $self->{'_annotation'}->{$key} ) {
378 $self->{'_annotation'}->{$key} = [];
381 push(@{$self->{'_annotation'}->{$key}},$object);
383 return 1;
386 =head2 remove_Annotations
388 Title : remove_Annotations
389 Usage :
390 Function: Remove the annotations for the specified key from this collection.
391 Example :
392 Returns : an array Bio::AnnotationI compliant objects which were stored
393 under the given key(s)
394 Args : the key(s) (tag name(s), one or more strings) for which to
395 remove annotations (optional; if none given, flushes all
396 annotations)
399 =cut
401 sub remove_Annotations{
402 my ($self, @keys) = @_;
404 @keys = $self->get_all_annotation_keys() unless @keys;
405 my @anns = $self->get_Annotations(@keys);
406 # flush
407 foreach my $key (@keys) {
408 delete $self->{'_annotation'}->{$key};
409 delete $self->{'_typemap'}->{'_type'}->{$key};
411 return @anns;
414 =head2 flatten_Annotations
416 Title : flatten_Annotations
417 Usage :
418 Function: Flattens part or all of the annotations in this collection.
420 This is a convenience method for getting the flattened
421 annotation for the given keys, removing the annotation for
422 those keys, and adding back the flattened array.
424 This should not change anything for un-nested collections.
425 Example :
426 Returns : an array Bio::AnnotationI compliant objects which were stored
427 under the given key(s)
428 Args : list of keys (strings) the annotation for which to flatten,
429 defaults to all keys if not given
432 =cut
434 sub flatten_Annotations{
435 my ($self,@keys) = @_;
437 my @anns = $self->get_all_Annotations(@keys);
438 my @origanns = $self->remove_Annotations(@keys);
439 foreach (@anns) {
440 $self->add_Annotation($_);
442 return @origanns;
445 =head1 Bio::AnnotationI methods implementations
447 This is to allow nested annotation: you can use a collection as an
448 annotation object for an annotation collection.
450 =cut
452 =head2 as_text
454 Title : as_text
455 Usage :
456 Function: See L<Bio::AnnotationI>
457 Example :
458 Returns : a string
459 Args : none
462 =cut
464 sub as_text{
465 my $self = shift;
467 my $txt = "Collection consisting of ";
468 my @texts = ();
469 foreach my $ann ($self->get_Annotations()) {
470 push(@texts, $ann->as_text());
472 if(@texts) {
473 $txt .= join(", ", map { '['.$_.']'; } @texts);
474 } else {
475 $txt .= "no elements";
477 return $txt;
480 =head2 display_text
482 Title : display_text
483 Usage : my $str = $ann->display_text();
484 Function: returns a string. Unlike as_text(), this method returns a string
485 formatted as would be expected for te specific implementation.
487 One can pass a callback as an argument which allows custom text
488 generation; the callback is passed the current instance and any text
489 returned
490 Example :
491 Returns : a string
492 Args : [optional] callback
494 =cut
497 # this just calls the default display_text output for
498 # any AnnotationI
499 my $DEFAULT_CB = sub {
500 my $obj = shift;
501 my $txt;
502 foreach my $ann ($obj->get_Annotations()) {
503 $txt .= $ann->display_text()."\n";
505 return $txt;
508 sub display_text {
509 my ($self, $cb) = @_;
510 $cb ||= $DEFAULT_CB;
511 $self->throw("") if ref $cb ne 'CODE';
512 return $cb->($self);
517 =head2 hash_tree
519 Title : hash_tree
520 Usage :
521 Function: See L<Bio::AnnotationI>
522 Example :
523 Returns : a hash reference
524 Args : none
527 =cut
529 sub hash_tree{
530 my $self = shift;
531 my $tree = {};
533 foreach my $key ($self->get_all_annotation_keys()) {
534 # all contained objects will support hash_tree()
535 # (they are AnnotationIs)
536 $tree->{$key} = [$self->get_Annotations($key)];
538 return $tree;
541 =head2 tagname
543 Title : tagname
544 Usage : $obj->tagname($newval)
545 Function: Get/set the tagname for this annotation value.
547 Setting this is optional. If set, it obviates the need to
548 provide a tag to Bio::AnnotationCollectionI when adding
549 this object. When obtaining an AnnotationI object from the
550 collection, the collection will set the value to the tag
551 under which it was stored unless the object has a tag
552 stored already.
554 Example :
555 Returns : value of tagname (a scalar)
556 Args : new value (a scalar, optional)
559 =cut
561 sub tagname{
562 my $self = shift;
564 return $self->{'tagname'} = shift if @_;
565 return $self->{'tagname'};
569 =head1 Backward compatible functions
571 Functions put in for backward compatibility with old
572 Bio::Annotation.pm stuff
574 =cut
576 =head2 description
578 Title : description
579 Usage :
580 Function:
581 Example :
582 Returns :
583 Args :
586 =cut
588 sub description{
589 my ($self,$value) = @_;
591 Carp::carp("old style annotation called on new Annotation::Collection object");
593 if( defined $value ) {
594 my $val = Bio::Annotation::SimpleValue->new();
595 $val->value($value);
596 $self->add_Annotation('description',$val);
599 my ($desc) = $self->get_Annotations('description');
601 # If no description tag exists, do not attempt to call value on undef:
602 return $desc ? $desc->value : undef;
606 =head2 add_gene_name
608 Title : add_gene_name
609 Usage :
610 Function:
611 Example :
612 Returns :
613 Args :
616 =cut
618 sub add_gene_name{
619 my ($self,$value) = @_;
621 Carp::carp("Old style add_gene_name called on new style Annotation::Collection");
623 my $val = Bio::Annotation::SimpleValue->new();
624 $val->value($value);
625 $self->add_Annotation('gene_name',$val);
628 =head2 each_gene_name
630 Title : each_gene_name
631 Usage :
632 Function:
633 Example :
634 Returns :
635 Args :
638 =cut
640 sub each_gene_name{
641 my ($self) = @_;
643 Carp::carp("Old style each_gene_name called on new style Annotation::Collection");
645 my @out;
646 my @gene = $self->get_Annotations('gene_name');
648 foreach my $g ( @gene ) {
649 push(@out,$g->value);
652 return @out;
655 =head2 add_Reference
657 Title : add_Reference
658 Usage :
659 Function:
660 Example :
661 Returns :
662 Args :
665 =cut
667 sub add_Reference{
668 my ($self, @values) = @_;
670 Carp::carp("add_Reference (old style Annotation) on new style Annotation::Collection");
672 # Allow multiple (or no) references to be passed, as per old method
673 foreach my $value (@values) {
674 $self->add_Annotation('reference',$value);
678 =head2 each_Reference
680 Title : each_Reference
681 Usage :
682 Function:
683 Example :
684 Returns :
685 Args :
688 =cut
690 sub each_Reference{
691 my ($self) = @_;
693 Carp::carp("each_Reference (old style Annotation) on new style Annotation::Collection");
695 return $self->get_Annotations('reference');
699 =head2 add_Comment
701 Title : add_Comment
702 Usage :
703 Function:
704 Example :
705 Returns :
706 Args :
709 =cut
711 sub add_Comment{
712 my ($self,$value) = @_;
714 Carp::carp("add_Comment (old style Annotation) on new style Annotation::Collection");
716 $self->add_Annotation('comment',$value);
720 =head2 each_Comment
722 Title : each_Comment
723 Usage :
724 Function:
725 Example :
726 Returns :
727 Args :
730 =cut
732 sub each_Comment{
733 my ($self) = @_;
735 Carp::carp("each_Comment (old style Annotation) on new style Annotation::Collection");
737 return $self->get_Annotations('comment');
742 =head2 add_DBLink
744 Title : add_DBLink
745 Usage :
746 Function:
747 Example :
748 Returns :
749 Args :
752 =cut
754 sub add_DBLink{
755 my ($self,$value) = @_;
757 Carp::carp("add_DBLink (old style Annotation) on new style Annotation::Collection");
759 $self->add_Annotation('dblink',$value);
763 =head2 each_DBLink
765 Title : each_DBLink
766 Usage :
767 Function:
768 Example :
769 Returns :
770 Args :
773 =cut
775 sub each_DBLink{
776 my ($self) = @_;
778 Carp::carp("each_DBLink (old style Annotation) on new style Annotation::Collection - use get_Annotations('dblink')");
780 return $self->get_Annotations('dblink');
785 =head1 Implementation management functions
787 =cut
789 =head2 _typemap
791 Title : _typemap
792 Usage : $obj->_typemap($newval)
793 Function:
794 Example :
795 Returns : value of _typemap
796 Args : newvalue (optional)
799 =cut
801 sub _typemap{
802 my ($self,$value) = @_;
803 if( defined $value) {
804 $self->{'_typemap'} = $value;
806 return $self->{'_typemap'};