No need to clone Bio-Root
[bioperl-live.git] / Bio / Taxonomy / Tree.pm
blob554f74125b25d6874e1db3d90fba15660e4472a8
2 # BioPerl module for Bio::Taxonomy::Tree
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Dan Kortschak but pilfered extensively from Bio::Tree::Tree by Jason Stajich
8 # You may distribute this module under the same terms as perl itself
10 # POD documentation - main docs before the code
12 =head1 NAME
14 Bio::Taxonomy::Tree - An Organism Level Implementation of TreeI interface.
16 =head1 SYNOPSIS
18 # NB: This module is deprecated. Use Bio::Taxon in combination with
19 # Bio::Tree::Tree instead
21 # like from a TreeIO
22 my $treeio = Bio::TreeIO->new(-format => 'newick', -file => 'treefile.dnd');
23 my $tree = $treeio->next_tree;
24 my @nodes = $tree->get_nodes;
25 my $root = $tree->get_root_node;
26 my @leaves = $tree->get_leaves;
29 =head1 DESCRIPTION
31 This object holds handles to Taxonomic Nodes which make up a tree.
33 =head1 EXAMPLES
35 use Bio::Species;
36 use Bio::Taxonomy::Tree;
38 my $human=Bio::Species->new();
39 my $chimp=Bio::Species->new();
40 my $bonobo=Bio::Species->new();
42 $human->classification(qw( sapiens Homo Hominidae
43 Catarrhini Primates Eutheria
44 Mammalia Euteleostomi Vertebrata
45 Craniata Chordata
46 Metazoa Eukaryota ));
47 $chimp->classification(qw( troglodytes Pan Hominidae
48 Catarrhini Primates Eutheria
49 Mammalia Euteleostomi Vertebrata
50 Craniata Chordata
51 Metazoa Eukaryota ));
52 $bonobo->classification(qw( paniscus Pan Hominidae
53 Catarrhini Primates Eutheria
54 Mammalia Euteleostomi Vertebrata
55 Craniata Chordata
56 Metazoa Eukaryota ));
58 # ranks passed to $taxonomy match ranks of species
59 my @ranks = ('superkingdom','kingdom','phylum','subphylum',
60 'no rank 1','no rank 2','class','no rank 3','order',
61 'suborder','family','genus','species');
63 my $taxonomy=Bio::Taxonomy->new(-ranks => \@ranks,
64 -method => 'trust',
65 -order => -1);
68 my $tree1=Bio::Taxonomy::Tree->new();
69 my $tree2=Bio::Taxonomy::Tree->new();
71 $tree1->make_species_branch($human,$taxonomy);
72 $tree2->make_species_branch($chimp,$taxonomy);
74 my ($homo_sapiens)=$tree1->get_leaves;
76 $tree1->splice($tree2);
78 $tree1->add_species($bonobo,$taxonomy);
80 my @taxa;
81 foreach my $leaf ($tree1->get_leaves) {
82 push @taxa,$leaf->taxon;
84 print join(", ",@taxa)."\n";
86 @taxa=();
87 $tree1->remove_branch($homo_sapiens);
88 foreach my $leaf ($tree1->get_leaves) {
89 push @taxa,$leaf->taxon;
91 print join(", ",@taxa)."\n";
93 =head1 FEEDBACK
95 See AUTHOR
97 =head1 AUTHOR - Dan Kortschak
99 Email kortschak@rsbs.anu.edu.au
101 =head1 CONTRIBUTORS
103 Mainly Jason Stajich
105 =head1 APPENDIX
107 The rest of the documentation details each of the object methods.
108 Internal methods are usually preceded with a _
110 =cut
113 # Code begins...
116 package Bio::Taxonomy::Tree;
117 use strict;
119 # Object preamble - inherits from Bio::Root::Root
121 use Bio::Taxonomy::Taxon;
123 # Import rank information from Bio::Taxonomy.pm
124 use vars qw(@RANK %RANK);
126 use base qw(Bio::Root::Root Bio::Tree::TreeI Bio::Tree::TreeFunctionsI);
128 =head2 new
130 Title : new
131 Usage : my $obj = Bio::Taxonomy::Tree->new();
132 Function: Builds a new Bio::Taxonomy::Tree object
133 Returns : Bio::Taxonomy::Tree
134 Args :
137 =cut
139 sub new {
140 my($class,@args) = @_;
142 my $self = $class->SUPER::new(@args);
143 $self->warn("Bio::Taxonomy::Tree is deprecated. Use Bio::Taxon in combination with Bio::Tree::Tree instead.");
145 $self->{'_rootnode'} = undef;
146 $self->{'_maxbranchlen'} = 0;
148 my ($root)= $self->_rearrange([qw(ROOT)], @args);
149 if( $root ) { $self->set_root_node($root); }
150 return $self;
154 =head2 get_nodes
156 Title : get_nodes
157 Usage : my @nodes = $tree->get_nodes()
158 Function: Return list of Bio::Taxonomy::Taxon objects
159 Returns : array of Bio::Taxonomy::Taxon objects
160 Args : (named values) hash with one value
161 order => 'b|breadth' first order or 'd|depth' first order
163 =cut
165 sub get_nodes{
166 my ($self, @args) = @_;
168 my ($order, $sortby) = $self->_rearrange([qw(ORDER SORTBY)],@args);
169 $order ||= 'depth';
170 $sortby ||= 'height';
172 if ($order =~ m/^b|(breadth)$/oi) {
173 my $node = $self->get_root_node;
174 my @children = ($node);
175 for (@children) {
176 push @children, $_->each_Descendent($sortby);
178 return @children;
181 if ($order =~ m/^d|(depth)$/oi) {
182 # this is depth-first search I believe
183 my $node = $self->get_root_node;
184 my @children = ($node,$node->get_Descendents($sortby));
185 return @children;
189 =head2 get_root_node
191 Title : get_root_node
192 Usage : my $node = $tree->get_root_node();
193 Function: Get the Top Node in the tree, in this implementation
194 Trees only have one top node.
195 Returns : Bio::Taxonomy::Taxon object
196 Args : none
198 =cut
201 sub get_root_node{
202 my ($self) = @_;
203 return $self->{'_rootnode'};
206 =head2 set_root_node
208 Title : set_root_node
209 Usage : $tree->set_root_node($node)
210 Function: Set the Root Node for the Tree
211 Returns : Bio::Taxonomy::Taxon
212 Args : Bio::Taxonomy::Taxon
214 =cut
217 sub set_root_node{
218 my ($self,$value) = @_;
219 if( defined $value ) {
220 if( ! $value->isa('Bio::Taxonomy::Taxon') ) {
221 $self->warn("Trying to set the root node to $value which is not a Bio::Taxonomy::Taxon");
222 return $self->get_root_node;
224 $self->{'_rootnode'} = $value;
226 return $self->get_root_node;
230 =head2 get_leaves
232 Title : get_leaves
233 Usage : my @nodes = $tree->get_leaves()
234 Function: Return list of Bio::Taxonomy::Taxon objects
235 Returns : array of Bio::Taxonomy::Taxon objects
236 Args :
238 =cut
241 sub get_leaves{
242 my ($self) = @_;
244 my $node = $self->get_root_node;
245 my @leaves;
246 my @children = ($node);
247 for (@children) {
248 push @children, $_->each_Descendent();
250 for (@children) {
251 push @leaves, $_ if $_->is_Leaf;
253 return @leaves;
256 =head2 make_species_branch
258 Title : make_species_branch
259 Usage : @nodes = $tree->make_species_branch($species,$taxonomy)
260 Function: Return list of Bio::Taxonomy::Taxon objects based on a Bio::Species object
261 Returns : array of Bio::Taxonomy::Taxon objects
262 Args : Bio::Species and Bio::Taxonomy objects
264 =cut
266 # I'm not happy that make_species_branch and make_branch are seperate routines
267 # should be able to just make_branch and have it sort things out
269 sub make_species_branch{
270 my ($self,$species,$taxonomy) = @_;
272 if (! $species->isa('Bio::Species') ) {
273 $self->throw("Trying to classify $species which is not a Bio::Species object");
275 if (! $taxonomy->isa('Bio::Taxonomy') ) {
276 $self->throw("Trying to classify with $taxonomy which is not a Bio::Taxonomy object");
279 # this is done to make sure we aren't duplicating a path (let God sort them out)
280 if (defined $self->get_root_node) {
281 $self->get_root_node->remove_all_Descendents;
284 my @nodes;
286 # nb taxa in [i][0] and ranks in [i][1]
287 my @taxa=$taxonomy->classify($species);
289 for (my $i = 0; $i < @taxa; $i++) {
290 $nodes[$i]=Bio::Taxonomy::Taxon->new(-taxon => $taxa[$i][0],
291 -rank => $taxa[$i][1]);
294 for (my $i = 0; $i < @taxa-1; $i++) {
295 $nodes[$i]->add_Descendent($nodes[$i+1]);
298 $self->set_root_node($nodes[0]);
300 return @nodes;
304 =head2 make_branch
306 Title : make_branch
307 Usage : $tree->make_branch($node)
308 Function: Make a linear Bio::Taxonomy::Tree object from a leafish node
309 Returns :
310 Args : Bio::Taxonomy::Taxon object
312 =cut
315 sub make_branch{
316 my ($self,$node) = @_;
318 # this is done to make sure we aren't duplicating a path (let God sort them out)
319 # note that if you are using a linked set of node which include node
320 # already in the tree, this will break
321 $self->get_root_node->remove_all_Descendents;
323 while (defined $node->ancestor) {
324 $self->set_root_node($node);
325 $node=$node->ancestor;
330 =head2 splice
332 Title : splice
333 Usage : @nodes = $tree->splice($tree)
334 Function: Return a of Bio::Taxonomy::Tree object that is a fusion of two
335 Returns : array of Bio::Taxonomy::Taxon added to tree
336 Args : Bio::Taxonomy::Tree object
338 =cut
341 sub splice{
342 my ($self,$tree) = @_;
344 my @nodes;
346 my @newleaves = $tree->get_leaves;
347 foreach my $leaf (@newleaves) {
348 push @nodes,$self->add_branch($leaf);
351 return @nodes;
354 =head2 add_species
356 Title : add_species
357 Usage : @nodes = $tree->add_species($species,$taxonomy)
358 Function: Return a of Bio::Taxonomy::Tree object with a new species added
359 Returns : array of Bio::Taxonomy::Taxon added to tree
360 Args : Bio::Species object
362 =cut
365 sub add_species{
366 my ($self,$species,$taxonomy) = @_;
368 my $branch=Bio::Taxonomy::Tree->new;
369 my @nodes=$branch->make_species_branch($species,$taxonomy);
371 my ($newleaf)=$branch->get_leaves;
373 return $self->add_branch($newleaf);
376 =head2 add_branch
378 Title : add_branch
379 Usage : $tree->add_branch($node,boolean)
380 Function: Return a of Bio::Taxonomy::Tree object with a new branch added
381 Returns : array of Bio::Taxonomy::Taxon objects of the resulting tree
382 Args : Bio::Taxonomy::Taxon object
383 boolean flag to force overwrite of descendent
384 (see Bio::Node->add_Descendent)
386 =cut
389 sub add_branch {
390 my ($self,$node,$force) = @_;
392 my $best_node_level=0;
393 my ($best_node,@nodes,$common);
395 my @leaves=$self->get_leaves;
396 foreach my $leaf (@leaves) {
397 $common=$node->recent_common_ancestor($leaf); # the root of the part to add
398 if (defined $common && ($common->distance_to_root > $best_node_level)) {
399 $best_node_level = $common->distance_to_root;
400 $best_node = $common;
404 return unless defined $best_node;
406 push @nodes,($self->get_root_node,$self->get_root_node->get_Descendents);
407 foreach my $node (@nodes) {
408 if ((defined $best_node->id && $best_node->id == $node->id) ||
409 ($best_node->rank eq $node->rank && $best_node->taxon eq $node->taxon) &&
410 ($best_node->rank ne 'no rank')) {
411 foreach my $descendent ($common->each_Descendent) {
412 $node->add_Descendent($descendent,$force);
416 $self->set_root_node($node) if $node->distance_to_root==0;
419 return ($common->get_Descendents);
422 =head2 remove_branch
424 Title : remove_branch
425 Usage : $tree->remove_branch($node)
426 Function: remove a branch up to the next multifurcation
427 Returns :
428 Args : Bio::Taxonomy::Taxon object
430 =cut
433 sub remove_branch{
434 my ($self,$node) = @_;
436 # we can define a branch at any point along it
438 while (defined $node->ancestor) {
439 last if $node->ancestor->each_Descendent > 1;
440 $node=$node->ancestor;
442 $node->remove_all_Descendents; # I'm not sure if this is necessary,
443 # but I don't see that remove_Descendent
444 # has the side effect of deleting
445 # descendent nodes of the deletee
446 $node->ancestor->remove_Descendent($node);