File Coverage

blib/lib/Bio/Phylo/Taxa.pm
Criterion Covered Total %
statement 51 108 47.2
branch 3 22 13.6
condition 4 7 57.1
subroutine 12 20 60.0
pod 11 11 100.0
total 81 168 48.2


line stmt bran cond sub pod time code
1             package Bio::Phylo::Taxa;
2 15     15   107918 use strict;
  15         31  
  15         456  
3 15     15   77 use base 'Bio::Phylo::Listable';
  15         26  
  15         3768  
4 15     15   91 use Bio::Phylo::Util::CONSTANT qw':objecttypes /looks_like/ :namespaces';
  15         25  
  15         4546  
5 15     15   95 use Bio::Phylo::Util::Exceptions 'throw';
  15         29  
  15         589  
6 15     15   76 use Bio::Phylo::Mediators::TaxaMediator;
  15         25  
  15         338  
7 15     15   62 use Bio::Phylo::Factory;
  15         27  
  15         82  
8              
9             =begin comment
10              
11             This class has no internal state, no cleanup is necessary.
12              
13             =end comment
14              
15             =cut
16              
17             {
18             my $logger = __PACKAGE__->get_logger;
19             my $mediator = 'Bio::Phylo::Mediators::TaxaMediator';
20             my $factory = Bio::Phylo::Factory->new;
21             my $CONTAINER = _PROJECT_;
22             my $TYPE = _TAXA_;
23             my $MATRIX = _MATRIX_;
24             my $FOREST = _FOREST_;
25              
26             =head1 NAME
27              
28             Bio::Phylo::Taxa - Container of taxon objects
29              
30             =head1 SYNOPSIS
31              
32             use Bio::Phylo::Factory;
33             my $fac = Bio::Phylo::Factory->new;
34              
35             # A mesquite-style default
36             # taxa block for 10 taxa.
37             my $taxa = $fac->create_taxa;
38             for my $i ( 1 .. 10 ) {
39             $taxa->insert( $fac->create_taxon( '-name' => "taxon_${i}" ) );
40             }
41            
42             # prints a taxa block in nexus format
43             print $taxa->to_nexus;
44              
45             =head1 DESCRIPTION
46              
47             The Bio::Phylo::Taxa object models a set of operational taxonomic units. The
48             object subclasses the Bio::Phylo::Listable object, and so the filtering
49             methods of that class are available.
50              
51             A taxa object can link to multiple forest and matrix objects.
52              
53             =head1 METHODS
54              
55             =head2 CONSTRUCTOR
56              
57             =over
58              
59             =item new()
60              
61             Taxa constructor.
62              
63             Type : Constructor
64             Title : new
65             Usage : my $taxa = Bio::Phylo::Taxa->new;
66             Function: Instantiates a Bio::Phylo::Taxa object.
67             Returns : A Bio::Phylo::Taxa object.
68             Args : none.
69              
70             =cut
71              
72             # sub new {
73             # # could be child class
74             # my $class = shift;
75             #
76             # # notify user
77             # $logger->info("constructor called for '$class'");
78             #
79             # # recurse up inheritance tree, get ID
80             # my $self = $class->SUPER::new( '-tag' => __PACKAGE__->_tag, @_ );
81             #
82             # # local fields would be set here
83             #
84             # return $self;
85             # }
86              
87             =back
88              
89             =head2 MUTATORS
90              
91             =over
92              
93             =item set_forest()
94              
95             Sets associated Bio::Phylo::Forest object.
96              
97             Type : Mutator
98             Title : set_forest
99             Usage : $taxa->set_forest( $forest );
100             Function: Associates forest with the
101             invocant taxa object (i.e.
102             creates reference).
103             Returns : Modified object.
104             Args : A Bio::Phylo::Forest object
105             Comments: A taxa object can link to multiple
106             forest and matrix objects.
107              
108             =cut
109              
110             sub set_forest {
111 0     0 1 0 my ( $self, $forest ) = @_;
112 0         0 $logger->debug("setting forest $forest");
113 0 0       0 if ( looks_like_object $forest, $FOREST ) {
114 0         0 $forest->set_taxa($self);
115             }
116 0         0 return $self;
117             }
118              
119             =item set_matrix()
120              
121             Sets associated Bio::Phylo::Matrices::Matrix object.
122              
123             Type : Mutator
124             Title : set_matrix
125             Usage : $taxa->set_matrix($matrix);
126             Function: Associates matrix with the
127             invocant taxa object (i.e.
128             creates reference).
129             Returns : Modified object.
130             Args : A Bio::Phylo::Matrices::Matrix object
131             Comments: A taxa object can link to multiple
132             forest and matrix objects.
133              
134             =cut
135              
136             sub set_matrix {
137 0     0 1 0 my ( $self, $matrix ) = @_;
138 0         0 $logger->debug("setting matrix $matrix");
139 0 0       0 if ( looks_like_object $matrix, $MATRIX ) {
140 0         0 $matrix->set_taxa($self);
141             }
142 0         0 return $self;
143             }
144              
145             =item unset_forest()
146              
147             Removes association with argument Bio::Phylo::Forest object.
148              
149             Type : Mutator
150             Title : unset_forest
151             Usage : $taxa->unset_forest($forest);
152             Function: Disassociates forest from the
153             invocant taxa object (i.e.
154             removes reference).
155             Returns : Modified object.
156             Args : A Bio::Phylo::Forest object
157              
158             =cut
159              
160             sub unset_forest {
161 0     0 1 0 my ( $self, $forest ) = @_;
162 0         0 $logger->debug("unsetting forest $forest");
163 0 0       0 if ( looks_like_object $forest, $FOREST ) {
164 0         0 $forest->unset_taxa();
165             }
166 0         0 return $self;
167             }
168              
169             =item unset_matrix()
170              
171             Removes association with Bio::Phylo::Matrices::Matrix object.
172              
173             Type : Mutator
174             Title : unset_matrix
175             Usage : $taxa->unset_matrix($matrix);
176             Function: Disassociates matrix from the
177             invocant taxa object (i.e.
178             removes reference).
179             Returns : Modified object.
180             Args : A Bio::Phylo::Matrices::Matrix object
181              
182             =cut
183              
184             sub unset_matrix {
185 0     0 1 0 my ( $self, $matrix ) = @_;
186 0         0 $logger->debug("unsetting matrix $matrix");
187 0 0       0 if ( looks_like_object $matrix, $MATRIX ) {
188 0         0 $matrix->unset_taxa();
189             }
190 0         0 return $self;
191             }
192              
193             =back
194              
195             =head2 ACCESSORS
196              
197             =over
198              
199             =item get_forests()
200              
201             Gets all associated Bio::Phylo::Forest objects.
202              
203             Type : Accessor
204             Title : get_forests
205             Usage : @forests = @{ $taxa->get_forests };
206             Function: Retrieves forests associated
207             with the current taxa object.
208             Returns : An ARRAY reference of
209             Bio::Phylo::Forest objects.
210             Args : None.
211              
212             =cut
213              
214             sub get_forests {
215 0     0 1 0 my $self = shift;
216 0         0 return $mediator->get_link(
217             '-source' => $self,
218             '-type' => $FOREST,
219             );
220             }
221              
222             =item get_matrices()
223              
224             Gets all associated Bio::Phylo::Matrices::Matrix objects.
225              
226             Type : Accessor
227             Title : get_matrices
228             Usage : @matrices = @{ $taxa->get_matrices };
229             Function: Retrieves matrices associated
230             with the current taxa object.
231             Returns : An ARRAY reference of
232             Bio::Phylo::Matrices::Matrix objects.
233             Args : None.
234              
235             =cut
236              
237             sub get_matrices {
238 0     0 1 0 my $self = shift;
239 0         0 return $mediator->get_link(
240             '-source' => $self,
241             '-type' => $MATRIX,
242             );
243             }
244              
245             =item get_ntax()
246              
247             Gets number of contained Bio::Phylo::Taxa::Taxon objects.
248              
249             Type : Accessor
250             Title : get_ntax
251             Usage : my $ntax = $taxa->get_ntax;
252             Function: Retrieves the number of taxa for the invocant.
253             Returns : INT
254             Args : None.
255             Comments:
256              
257             =cut
258              
259             sub get_ntax {
260 22     22 1 43 my $self = shift;
261 22         42 return scalar @{ $self->get_entities };
  22         82  
262             }
263              
264             =back
265              
266             =head2 METHODS
267              
268             =over
269              
270             =item merge_by_name()
271              
272             Merges argument Bio::Phylo::Taxa object with invocant.
273              
274             Type : Method
275             Title : merge_by_name
276             Usage : $merged = $taxa->merge_by_name($other_taxa);
277             Function: Merges two or more taxa objects such that
278             internally different taxon objects
279             with the same name become a single
280             object with the combined references
281             to datum objects and node objects
282             contained by the two.
283             Returns : A merged Bio::Phylo::Taxa object.
284             Args : Bio::Phylo::Taxa objects.
285              
286             =cut
287              
288             sub merge_by_name {
289 0     0 1 0 my $merged = $factory->create_taxa( '-name' => 'Merged' );
290 0         0 for my $taxa (@_) {
291            
292             # build a hash of what we have so far
293 0         0 my %taxon_by_name = map { $_->get_name => $_ } @{ $merged->get_entities };
  0         0  
  0         0  
294            
295             # iterate over focal taxa block
296 0         0 for my $taxon ( @{ $taxa->get_entities } ) {
  0         0  
297 0         0 my $name = $taxon->get_name;
298            
299             # retrieve or create target taxon
300 0         0 my $target;
301 0 0       0 if ( $taxon_by_name{$name} ) {
302 0         0 $target = $taxon_by_name{$name};
303             }
304             else {
305 0         0 $target = $factory->create_taxon( '-name' => $name );
306 0         0 $merged->insert($target);
307 0         0 $taxon_by_name{$name} = $target;
308             }
309            
310             # copy over data, metadata and node links
311 0         0 $_->set_taxon($target) for @{ $taxon->get_data };
  0         0  
312 0         0 $_->set_taxon($target) for @{ $taxon->get_nodes };
  0         0  
313 0         0 $target->add_meta($_) for @{ $taxon->get_meta };
  0         0  
314             }
315             }
316 0         0 return $merged;
317             }
318              
319             =item merge_by_meta()
320              
321             Merges argument Bio::Phylo::Taxa object with invocant.
322              
323             Type : Method
324             Title : merge_by_meta
325             Usage : $taxa->merge_by_name('dc:identifier',$other_taxa);
326             Function: Merges two taxa objects such that
327             internally different taxon objects
328             with the same annotation value become
329             a single object with the combined references
330             to datum objects, node objects and
331             metadata annotations contained by
332             the two.
333             Returns : A merged Bio::Phylo::Taxa object.
334             Args : a CURIE predicate and Bio::Phylo::Taxa objects.
335              
336             =cut
337              
338             sub merge_by_meta {
339 1     1 1 8 my ( $self, $predicate, @others ) = @_;
340 1         3 push @others, $self;
341 1         6 my $merged = $factory->create_taxa;
342 1         4 for my $taxa ( @others ) {
343            
344             my %object_by_value =
345 10         23 map { $_->get_meta_object($predicate) => $_ }
346 2         3 @{ $merged->get_entities };
  2         5  
347            
348 2         5 for my $taxon ( @{ $taxa->get_entities } ) {
  2         5  
349            
350             # instantiate or fetch taxon based on predicate value
351 20         45 my $value = $taxon->get_meta_object($predicate);
352 20   66     75 my $target = $object_by_value{$value} || $factory->create_taxon();
353            
354             # copy links and metadata
355 20         23 $_->set_taxon($target) for @{ $taxon->get_data };
  20         42  
356 20         28 $_->set_taxon($target) for @{ $taxon->get_nodes };
  20         40  
357 20         24 $target->add_meta($_) for @{ $taxon->get_meta };
  20         42  
358            
359             # copy name to bp:contributing_name
360 20 50       46 if ( my $name = $taxon->get_name ) {
361 0         0 $target->add_meta(
362             $factory->create_meta(
363             '-namespaces' => { 'bp' => _NS_BIOPHYLO_ },
364             '-triple' => { 'bp:contributing_name' => $name }
365             )
366             );
367             }
368            
369             # add to hash and block if newly created
370 20 100       41 if ( not exists $object_by_value{$value} ) {
371 10         30 $merged->insert($target);
372 10         25 $object_by_value{$value} = $target;
373             }
374             }
375             }
376 1         6 return $merged;
377             }
378              
379             =item prune_taxa()
380              
381             Removes taxa by name or object
382              
383             Type : Method
384             Title : prune_taxa
385             Usage : $taxa->prune_taxa([$t1, $t2]);
386             Function: Prunes taxa from the taxa object
387             Returns : A pruned Bio::Phylo::Taxa object.
388             Args : An array reference of taxa, either by name or as taxon objects
389              
390             =cut
391              
392             sub prune_taxa {
393 0     0 1 0 my ( $self, $arrayref ) = @_;
394 0 0       0 if ( ref($arrayref) eq 'ARRAY' ) {
395 0         0 for my $t ( @{ $arrayref } ) {
  0         0  
396 0 0       0 if ( not ref $t ) {
    0          
397 0 0       0 if ( my $obj = $self->get_by_name($t) ) {
398 0         0 $self->delete($obj);
399             }
400             else {
401 0         0 $logger->warn("Couldn't find taxon with name '$t'");
402             }
403             }
404             elsif ( looks_like_object $t, _TAXON_ ) {
405 0         0 $self->delete($t);
406             }
407             }
408             }
409             else {
410 0         0 throw 'BadArgs' => 'Argument is not an array reference';
411             }
412 0         0 return $self;
413             }
414              
415              
416             =item to_nexus()
417              
418             Serializes invocant to nexus format.
419              
420             Type : Format convertor
421             Title : to_nexus
422             Usage : my $block = $taxa->to_nexus;
423             Function: Converts $taxa into a nexus taxa block.
424             Returns : Nexus taxa block (SCALAR).
425             Args : -links => 1 (optional, adds 'TITLE' token)
426             Comments:
427              
428             =cut
429              
430             sub to_nexus {
431 2     2 1 11 my ( $self, %args ) = @_;
432             my %m = (
433             'header' => ( $args{'-header'} && '#NEXUS' ) || '',
434             'title' =>
435             ( $args{'-links'} && sprintf 'TITLE %s;', $self->get_nexus_name )
436             || '',
437             'version' => $self->VERSION,
438             'ntax' => $self->get_ntax,
439             'class' => ref $self,
440             'time' => my $time = localtime(),
441             'taxlabels' => join "\n\t\t",
442 2   50     39 map { $_->get_nexus_name } @{ $self->get_entities }
  22   50     47  
  2         9  
443             );
444 2         38 return <<TEMPLATE;
445             $m{header}
446             BEGIN TAXA;
447             [! Taxa block written by $m{class} $m{version} on $m{time} ]
448             $m{title}
449             DIMENSIONS NTAX=$m{ntax};
450             TAXLABELS
451             $m{taxlabels}
452             ;
453             END;
454             TEMPLATE
455             }
456              
457             =begin comment
458              
459             Type : Internal method
460             Title : _container
461             Usage : $taxa->_container;
462             Function:
463             Returns : CONSTANT
464             Args :
465              
466             =end comment
467              
468             =cut
469              
470 23     23   40 sub _container { $CONTAINER }
471              
472             =begin comment
473              
474             Type : Internal method
475             Title : _type
476             Usage : $taxa->_type;
477             Function:
478             Returns : SCALAR
479             Args :
480              
481             =end comment
482              
483             =cut
484              
485 565     565   926 sub _type { $TYPE }
486 1     1   3 sub _tag { 'otus' }
487              
488             =back
489              
490             =cut
491              
492             # podinherit_insert_token
493              
494             =head1 SEE ALSO
495              
496             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
497             for any user or developer questions and discussions.
498              
499             =over
500              
501             =item L<Bio::Phylo::Listable>
502              
503             The L<Bio::Phylo::Taxa> object inherits from the L<Bio::Phylo::Listable>
504             object. Look there for more methods applicable to the taxa object.
505              
506             =item L<Bio::Phylo::Manual>
507              
508             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
509              
510             =back
511              
512             =head1 CITATION
513              
514             If you use Bio::Phylo in published research, please cite it:
515              
516             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
517             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
518             I<BMC Bioinformatics> B<12>:63.
519             L<http://dx.doi.org/10.1186/1471-2105-12-63>
520              
521             =cut
522              
523             }
524             1;