t/AlignIO/AlignIO.t: fix number of tests in plan (fixup c523e6bed866)
[bioperl-live.git] / Bio / SeqFeature / AnnotationAdaptor.pm
blob686f5e7e12a30278e02e47951b00ff1f15ab35e2
2 # BioPerl module for Bio::SeqFeature::AnnotationAdaptor
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Hilmar Lapp <hlapp at gmx.net>
8 # Copyright Hilmar Lapp
10 # You may distribute this module under the same terms as perl itself
13 # (c) Hilmar Lapp, hlapp at gmx.net, 2002.
14 # (c) GNF, Genomics Institute of the Novartis Research Foundation, 2002.
16 # You may distribute this module under the same terms as perl itself.
17 # Refer to the Perl Artistic License (see the license accompanying this
18 # software package, or see http://www.perl.com/language/misc/Artistic.html)
19 # for the terms under which you may use, modify, and redistribute this module.
21 # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
22 # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23 # MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 # POD documentation - main docs before the code
28 =head1 NAME
30 Bio::SeqFeature::AnnotationAdaptor - integrates SeqFeatureIs annotation
32 =head1 SYNOPSIS
34 use Bio::SeqFeature::Generic;
35 use Bio::SeqFeature::AnnotationAdaptor;
37 # obtain a SeqFeatureI implementing object somehow
38 my $feat = Bio::SeqFeature::Generic->new(-start => 10, -end => 20);
40 # add tag/value annotation
41 $feat->add_tag_value("mytag", "value of tag mytag");
42 $feat->add_tag_value("mytag", "another value of tag mytag");
44 # Bio::SeqFeature::Generic also provides annotation(), which returns a
45 # Bio::AnnotationCollectionI compliant object
46 $feat->annotation->add_Annotation("dbxref", $dblink);
48 # to integrate tag/value annotation with AnnotationCollectionI
49 # annotation, use this adaptor, which also implements
50 # Bio::AnnotationCollectionI
51 my $anncoll = Bio::SeqFeature::AnnotationAdaptor->new(-feature => $feat);
53 # this will now return tag/value pairs as
54 # Bio::Annotation::SimpleValue objects
55 my @anns = $anncoll->get_Annotations("mytag");
56 # other added before annotation is available too
57 my @dblinks = $anncoll->get_Annotations("dbxref");
59 # also supports transparent adding of tag/value pairs in
60 # Bio::AnnotationI flavor
61 my $tagval = Bio::Annotation::SimpleValue->new(-value => "some value",
62 -tagname => "some tag");
63 $anncoll->add_Annotation($tagval);
64 # this is now also available from the feature's tag/value system
65 my @vals = $feat->get_tag_values("some tag");
67 =head1 DESCRIPTION
69 L<Bio::SeqFeatureI> defines light-weight annotation of features
70 through tag/value pairs. Conversely, L<Bio::AnnotationCollectionI>
71 together with L<Bio::AnnotationI> defines an annotation bag, which is
72 better typed, but more heavy-weight because it contains every single
73 piece of annotation as objects. The frequently used base
74 implementation of Bio::SeqFeatureI, Bio::SeqFeature::Generic, defines
75 an additional slot for AnnotationCollectionI-compliant annotation.
77 This adaptor provides a L<Bio::AnnotationCollectionI> compliant,
78 unified, and integrated view on the annotation of L<Bio::SeqFeatureI>
79 objects, including tag/value pairs, and annotation through the
80 annotation() method, if the object supports it. Code using this
81 adaptor does not need to worry about the different ways of possibly
82 annotating a SeqFeatureI object, but can instead assume that it
83 strictly follows the AnnotationCollectionI scheme. The price to pay is
84 that retrieving and adding annotation will always use objects instead
85 of light-weight tag/value pairs.
87 In other words, this adaptor allows us to keep the best of both
88 worlds. If you create tens of thousands of feature objects, and your
89 only annotation is tag/value pairs, you are best off using the
90 features' native tag/value system. If you create a smaller number of
91 features, but with rich and typed annotation mixed with tag/value
92 pairs, this adaptor may be for you. Since its implementation is by
93 double-composition, you only need to create one instance of the
94 adaptor. In order to transparently annotate a feature object, set the
95 feature using the feature() method. Every annotation you add will be
96 added to the feature object, and hence will not be lost when you set
97 feature() to the next object.
99 =head1 FEEDBACK
101 =head2 Mailing Lists
103 User feedback is an integral part of the evolution of this and other
104 Bioperl modules. Send your comments and suggestions preferably to
105 the Bioperl mailing list. Your participation is much appreciated.
107 bioperl-l@bioperl.org - General discussion
108 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
110 =head2 Support
112 Please direct usage questions or support issues to the mailing list:
114 I<bioperl-l@bioperl.org>
116 rather than to the module maintainer directly. Many experienced and
117 reponsive experts will be able look at the problem and quickly
118 address it. Please include a thorough description of the problem
119 with code and data examples if at all possible.
121 =head2 Reporting Bugs
123 Report bugs to the Bioperl bug tracking system to help us keep track
124 of the bugs and their resolution. Bug reports can be submitted via the
125 web:
127 https://github.com/bioperl/bioperl-live/issues
129 =head1 AUTHOR - Hilmar Lapp
131 Email hlapp at gmx.net
133 =head1 APPENDIX
135 The rest of the documentation details each of the object methods.
136 Internal methods are usually preceded with a _
138 =cut
141 #' Let the code begin...
144 package Bio::SeqFeature::AnnotationAdaptor;
145 use strict;
147 # Object preamble - inherits from Bio::Root::Root
149 use Bio::Annotation::SimpleValue;
151 use base qw(Bio::Root::Root Bio::AnnotationCollectionI Bio::AnnotatableI);
153 =head2 new
155 Title : new
156 Usage : my $obj = Bio::SeqFeature::AnnotationAdaptor->new();
157 Function: Builds a new Bio::SeqFeature::AnnotationAdaptor object
158 Returns : an instance of Bio::SeqFeature::AnnotationAdaptor
159 Args : Named parameters
160 -feature the Bio::SeqFeatureI implementing object to adapt
161 (mandatory to be passed here, or set via feature()
162 before calling other methods)
163 -annotation the Bio::AnnotationCollectionI implementing object
164 for storing richer annotation (this will default to
165 the $feature->annotation() if it supports it)
166 -tagvalue_factory the object factory to use for creating tag/value
167 pair representing objects
170 =cut
172 sub new {
173 my($class,@args) = @_;
175 my $self = $class->SUPER::new(@args);
177 my ($feat,$anncoll,$fact) =
178 $self->_rearrange([qw(FEATURE
179 ANNOTATION
180 TAGVALUE_FACTORY)], @args);
182 $self->feature($feat) if $feat;
183 $self->annotation($anncoll) if $feat;
184 $self->tagvalue_object_factory($fact) if $fact;
186 return $self;
189 =head2 feature
191 Title : feature
192 Usage : $obj->feature($newval)
193 Function: Get/set the feature that this object adapts to an
194 AnnotationCollectionI.
195 Example :
196 Returns : value of feature (a Bio::SeqFeatureI compliant object)
197 Args : new value (a Bio::SeqFeatureI compliant object, optional)
200 =cut
202 sub feature{
203 my ($self,$value) = @_;
204 if( defined $value) {
205 $self->{'feature'} = $value;
207 return $self->{'feature'};
210 =head2 annotation
212 Title : annotation
213 Usage : $obj->annotation($newval)
214 Function: Get/set the AnnotationCollectionI implementing object used by
215 this adaptor to store additional annotation that cannot be stored
216 by the SeqFeatureI itself.
218 If requested before having been set, the value will default to the
219 annotation object of the feature if it has one.
220 Example :
221 Returns : value of annotation (a Bio::AnnotationCollectionI compliant object)
222 Args : new value (a Bio::AnnotationCollectionI compliant object, optional)
225 =cut
227 sub annotation{
228 my ($self,$value) = @_;
230 if( defined $value) {
231 $self->{'annotation'} = $value;
233 if((! exists($self->{'annotation'})) &&
234 $self->feature()->can('annotation')) {
235 return $self->feature()->annotation();
237 return $self->{'annotation'};
240 =head1 AnnotationCollectionI implementing methods
242 =cut
244 =head2 get_all_annotation_keys
246 Title : get_all_annotation_keys
247 Usage : $ac->get_all_annotation_keys()
248 Function: gives back a list of annotation keys, which are simple text strings
249 Returns : list of strings
250 Args : none
252 =cut
254 sub get_all_annotation_keys{
255 my ($self) = @_;
256 my @keys = ();
258 # get the tags from the feature object
259 if ($self->feature()->can('get_all_tags')) {
260 push(@keys, $self->feature()->get_all_tags());
261 } else {
262 push(@keys, $self->feature()->all_tags());
264 # ask the annotation implementation in addition, while avoiding duplicates
265 if($self->annotation()) {
266 push(@keys,
267 grep { ! $self->feature->has_tag($_); }
268 $self->annotation()->get_all_annotation_keys());
270 # done
271 return @keys;
275 =head2 get_Annotations
277 Title : get_Annotations
278 Usage : my @annotations = $collection->get_Annotations('key')
279 Function: Retrieves all the Bio::AnnotationI objects for a specific key
280 Returns : list of Bio::AnnotationI - empty if no objects stored for a key
281 Args : string which is key for annotations
283 =cut
285 sub get_Annotations{
286 my ($self, @keys) = @_;
287 my @anns = ();
289 # we need a annotation object factory
290 my $fact = $self->tagvalue_object_factory();
292 # get all tags if no keys have been provided
293 @keys = $self->feature->all_tags() unless @keys;
295 # build object for each value for each tag
296 foreach my $key (@keys) {
297 # protect against keys that aren't tags
298 next unless $self->feature->has_tag($key);
299 # add each tag/value pair as a SimpleValue object
300 foreach my $val ($self->feature()->get_tag_values($key)) {
301 my $ann;
302 if($fact) {
303 $ann = $fact->create_object(-value => $val, -tagname => $key);
304 } else {
305 $ann = Bio::Annotation::SimpleValue->new(-value => $val,
306 -tagname => $key);
308 push(@anns, $ann);
312 # add what is in the annotation implementation if any
313 if($self->annotation()) {
314 push(@anns, $self->annotation->get_Annotations(@keys));
317 # done
318 return @anns;
321 =head2 get_num_of_annotations
323 Title : get_num_of_annotations
324 Usage : my $count = $collection->get_num_of_annotations()
325 Function: Returns the count of all annotations stored in this collection
326 Returns : integer
327 Args : none
330 =cut
332 sub get_num_of_annotations{
333 my ($self) = @_;
335 # first, count the number of tags on the feature
336 my $num_anns = 0;
338 foreach ($self->feature()->all_tags()) {
339 $num_anns += scalar( $self->feature()->get_tag_values($_));
342 # add from the annotation implementation if any
343 if($self->annotation()) {
344 $num_anns += $self->annotation()->get_num_of_annotations();
347 # done
348 return $num_anns;
351 =head1 Implementation specific functions - to allow adding
353 =cut
355 =head2 add_Annotation
357 Title : add_Annotation
358 Usage : $self->add_Annotation('reference',$object);
359 $self->add_Annotation($object,'Bio::MyInterface::DiseaseI');
360 $self->add_Annotation($object);
361 $self->add_Annotation('disease',$object,'Bio::MyInterface::DiseaseI');
362 Function: Adds an annotation for a specific key.
364 If the key is omitted, the object to be added must provide a value
365 via its tagname().
367 If the archetype is provided, this and future objects added under
368 that tag have to comply with the archetype and will be rejected
369 otherwise.
371 This implementation will add all Bio::Annotation::SimpleValue
372 objects to the adapted features as tag/value pairs. Caveat: this
373 may potentially result in information loss if a derived object
374 is supplied.
376 Returns : none
377 Args : annotation key ('disease', 'dblink', ...)
378 object to store (must be Bio::AnnotationI compliant)
379 [optional] object archetype to map future storage of object
380 of these types to
382 =cut
384 sub add_Annotation{
385 my ($self,$key,$object,$archetype) = @_;
387 # if there's no key we use the tagname() as key
388 if(ref($key) && $key->isa("Bio::AnnotationI") &&
389 (! ($object && ref($object)))) {
390 $archetype = $object if $object;
391 $object = $key;
392 $key = $object->tagname();
393 $key = $key->name() if $key && ref($key); # OntologyTermI
394 $self->throw("Annotation object must have a tagname if key omitted")
395 unless $key;
398 if( !defined $object ) {
399 $self->throw("Must have at least key and object in add_Annotation");
402 if( ! (ref($object) && $object->isa("Bio::AnnotationI")) ) {
403 $self->throw("object must be a Bio::AnnotationI compliant object, otherwise we won't add it!");
406 # ready to add -- if it's a SimpleValue, we add to the feature's tags,
407 # otherwise we'll add to the annotation collection implementation
409 if($object->isa("Bio::Annotation::SimpleValue") &&
410 $self->feature()->can('add_tag_value')) {
411 return $self->feature()->add_tag_value($key, $object->value());
412 } else {
413 my $anncoll = $self->annotation();
414 if(! $anncoll) {
415 $anncoll = Bio::Annotation::Collection->new();
416 $self->annotation($anncoll);
418 if($anncoll->can('add_Annotation')) {
419 return $anncoll->add_Annotation($key,$object,$archetype);
421 $self->throw("Annotation implementation does not allow adding!");
425 =head2 remove_Annotations
427 Title : remove_Annotations
428 Usage :
429 Function: Remove the annotations for the specified key from this
430 collection.
432 If the key happens to be a tag, then the tag is removed
433 from the feature.
435 Example :
436 Returns : an array Bio::AnnotationI compliant objects which were stored
437 under the given key(s)
438 Args : the key(s) (tag name(s), one or more strings) for which to
439 remove annotations (optional; if none given, flushes all
440 annotations)
443 =cut
445 sub remove_Annotations{
446 my ($self, @keys) = @_;
448 # set to all keys if none are supplied
449 @keys = $self->get_all_annotation_keys() unless @keys;
450 # collect existing annotation
451 my @anns = $self->get_Annotations(@keys);
452 # flush
453 foreach my $key (@keys) {
454 # delete the tag if it is one
455 $self->feature->remove_tag($key) if $self->feature->has_tag($key);
456 # and delegate to the annotation implementation
457 my $anncoll = $self->annotation();
458 if($anncoll && $anncoll->can('remove_Annotations')) {
459 $anncoll->remove_Annotations($key);
460 } elsif($anncoll) {
461 $self->warn("Annotation bundle implementation ".ref($anncoll).
462 " does not allow remove!");
465 return @anns;
468 =head1 Additional methods
470 =cut
472 =head2 tagvalue_object_factory
474 Title : tagvalue_object_factory
475 Usage : $obj->tagval_object_factory($newval)
476 Function: Get/set the object factory to use for creating objects that
477 represent tag/value pairs (e.g.,
478 Bio::Annotation::SimpleValue).
480 The object to be created is expected to follow
481 Bio::Annotation::SimpleValue in terms of supported
482 arguments at creation time, and the methods.
484 Example :
485 Returns : A Bio::Factory::ObjectFactoryI compliant object
486 Args : new value (a Bio::Factory::ObjectFactoryI compliant object,
487 optional)
490 =cut
492 sub tagvalue_object_factory{
493 my ($self,$value) = @_;
494 if( defined $value) {
495 $self->{'tagval_object_factory'} = $value;
497 return $self->{'tagval_object_factory'};