Mercurial > repos > mahtabm > ensembl
comparison variant_effect_predictor/Bio/Tree/Node.pm @ 0:1f6dce3d34e0
Uploaded
author | mahtabm |
---|---|
date | Thu, 11 Apr 2013 02:01:53 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1f6dce3d34e0 |
---|---|
1 # $Id: Node.pm,v 1.17.2.3 2003/09/14 19:00:35 jason Exp $ | |
2 # | |
3 # BioPerl module for Bio::Tree::Node | |
4 # | |
5 # Cared for by Jason Stajich <jason@bioperl.org> | |
6 # | |
7 # Copyright Jason Stajich | |
8 # | |
9 # You may distribute this module under the same terms as perl itself | |
10 | |
11 # POD documentation - main docs before the code | |
12 | |
13 =head1 NAME | |
14 | |
15 Bio::Tree::Node - A Simple Tree Node | |
16 | |
17 =head1 SYNOPSIS | |
18 | |
19 use Bio::Tree::Node; | |
20 my $nodeA = new Bio::Tree::Node(); | |
21 my $nodeL = new Bio::Tree::Node(); | |
22 my $nodeR = new Bio::Tree::Node(); | |
23 | |
24 my $node = new Bio::Tree::Node(); | |
25 $node->add_Descendent($nodeL); | |
26 $node->add_Descendent($nodeR); | |
27 | |
28 print "node is not a leaf \n" if( $node->is_leaf); | |
29 | |
30 =head1 DESCRIPTION | |
31 | |
32 Makes a Tree Node suitable for building a Tree. | |
33 | |
34 =head1 FEEDBACK | |
35 | |
36 =head2 Mailing Lists | |
37 | |
38 User feedback is an integral part of the evolution of this and other | |
39 Bioperl modules. Send your comments and suggestions preferably to | |
40 the Bioperl mailing list. Your participation is much appreciated. | |
41 | |
42 bioperl-l@bioperl.org - General discussion | |
43 http://bioperl.org/MailList.shtml - About the mailing lists | |
44 | |
45 =head2 Reporting Bugs | |
46 | |
47 Report bugs to the Bioperl bug tracking system to help us keep track | |
48 of the bugs and their resolution. Bug reports can be submitted via | |
49 the web: | |
50 | |
51 http://bugzilla.bioperl.org/ | |
52 | |
53 =head1 AUTHOR - Jason Stajich | |
54 | |
55 Email jason@bioperl.org | |
56 | |
57 =head1 CONTRIBUTORS | |
58 | |
59 Aaron Mackey amackey@virginia.edu | |
60 | |
61 =head1 APPENDIX | |
62 | |
63 The rest of the documentation details each of the object methods. | |
64 Internal methods are usually preceded with a _ | |
65 | |
66 =cut | |
67 | |
68 | |
69 # Let the code begin... | |
70 | |
71 package Bio::Tree::Node; | |
72 use vars qw(@ISA $CREATIONORDER); | |
73 use strict; | |
74 | |
75 use Bio::Root::Root; | |
76 use Bio::Tree::NodeI; | |
77 | |
78 @ISA = qw(Bio::Root::Root Bio::Tree::NodeI); | |
79 | |
80 BEGIN { | |
81 $CREATIONORDER = 0; | |
82 } | |
83 | |
84 | |
85 =head2 new | |
86 | |
87 Title : new | |
88 Usage : my $obj = new Bio::Tree::Node(); | |
89 Function: Builds a new Bio::Tree::Node object | |
90 Returns : Bio::Tree::Node | |
91 Args : -left => pointer to Left descendent (optional) | |
92 -right => pointer to Right descenent (optional) | |
93 -branch_length => branch length [integer] (optional) | |
94 -bootstrap => value bootstrap value (string) | |
95 -description => description of node | |
96 -id => human readable id for node | |
97 | |
98 =cut | |
99 | |
100 sub new { | |
101 my($class,@args) = @_; | |
102 | |
103 my $self = $class->SUPER::new(@args); | |
104 my ($children, $branchlen,$id, | |
105 $bootstrap, $desc,$d) = $self->_rearrange([qw(DESCENDENTS | |
106 BRANCH_LENGTH | |
107 ID | |
108 BOOTSTRAP | |
109 DESC | |
110 DESCRIPTION | |
111 )], | |
112 @args); | |
113 $self->_register_for_cleanup(\&node_cleanup); | |
114 $self->{'_desc'} = {}; # for descendents | |
115 if( $d && $desc ) { | |
116 $self->warn("can only accept -desc or -description, not both, accepting -description"); | |
117 $desc = $d; | |
118 } elsif( defined $d && ! defined $desc ) { | |
119 $desc = $d; | |
120 } | |
121 defined $desc && $self->description($desc); | |
122 defined $bootstrap && $self->bootstrap($bootstrap); | |
123 defined $id && $self->id($id); | |
124 defined $branchlen && $self->branch_length($branchlen); | |
125 | |
126 if( defined $children ) { | |
127 if( ref($children) !~ /ARRAY/i ) { | |
128 $self->warn("Must specify a valid ARRAY reference to initialize a Node's Descendents"); | |
129 } | |
130 foreach my $c ( @$children ) { | |
131 $self->add_Descendent($c); | |
132 } | |
133 } | |
134 $self->_creation_id($CREATIONORDER++); | |
135 return $self; | |
136 } | |
137 | |
138 =head2 add_Descendent | |
139 | |
140 Title : add_Descendent | |
141 Usage : $node->add_Descendant($node); | |
142 Function: Adds a descendent to a node | |
143 Returns : number of current descendents for this node | |
144 Args : Bio::Node::NodeI | |
145 boolean flag, true if you want to ignore the fact that you are | |
146 adding a second node with the same unique id (typically memory | |
147 location reference in this implementation). default is false and | |
148 will throw an error if you try and overwrite an existing node. | |
149 | |
150 =cut | |
151 | |
152 sub add_Descendent{ | |
153 my ($self,$node,$ignoreoverwrite) = @_; | |
154 return -1 if( ! defined $node ) ; | |
155 if( ! $node->isa('Bio::Tree::NodeI') ) { | |
156 $self->warn("Trying to add a Descendent who is not a Bio::Tree::NodeI"); | |
157 return -1; | |
158 } | |
159 # do we care about order? | |
160 $node->ancestor($self); | |
161 if( $self->{'_desc'}->{$node->internal_id} && ! $ignoreoverwrite ) { | |
162 $self->throw("Going to overwrite a node which is $node that is already stored here, set the ignore overwrite flag (parameter 2) to true to ignore this in the future"); | |
163 } | |
164 | |
165 $self->{'_desc'}->{$node->internal_id} = $node; # is this safely unique - we've tested before at any rate?? | |
166 | |
167 $self->invalidate_height(); | |
168 | |
169 return scalar keys %{$self->{'_desc'}}; | |
170 } | |
171 | |
172 | |
173 =head2 each_Descendent | |
174 | |
175 Title : each_Descendent($sortby) | |
176 Usage : my @nodes = $node->each_Descendent; | |
177 Function: all the descendents for this Node (but not their descendents | |
178 i.e. not a recursive fetchall) | |
179 Returns : Array of Bio::Tree::NodeI objects | |
180 Args : $sortby [optional] "height", "creation" or coderef to be used | |
181 to sort the order of children nodes. | |
182 | |
183 =cut | |
184 | |
185 sub each_Descendent{ | |
186 my ($self, $sortby) = @_; | |
187 | |
188 # order can be based on branch length (and sub branchlength) | |
189 | |
190 $sortby ||= 'height'; | |
191 | |
192 if (ref $sortby eq 'CODE') { | |
193 return sort $sortby values %{$self->{'_desc'}}; | |
194 } else { | |
195 if ($sortby eq 'height') { | |
196 return map { $_->[0] } | |
197 sort { $a->[1] <=> $b->[1] || | |
198 $a->[2] <=> $b->[2] } | |
199 map { [$_, $_->height, $_->internal_id ] } | |
200 values %{$self->{'_desc'}}; | |
201 } else { | |
202 return map { $_->[0] } | |
203 sort { $a->[1] <=> $b->[1] } | |
204 map { [$_, $_->height ] } | |
205 values %{$self->{'_desc'}}; | |
206 } | |
207 } | |
208 } | |
209 | |
210 =head2 remove_Descendent | |
211 | |
212 Title : remove_Descendent | |
213 Usage : $node->remove_Descedent($node_foo); | |
214 Function: Removes a specific node from being a Descendent of this node | |
215 Returns : nothing | |
216 Args : An array of Bio::Node::NodeI objects which have be previously | |
217 passed to the add_Descendent call of this object. | |
218 | |
219 =cut | |
220 | |
221 sub remove_Descendent{ | |
222 my ($self,@nodes) = @_; | |
223 my $c= 0; | |
224 foreach my $n ( @nodes ) { | |
225 if( $self->{'_desc'}->{$n->internal_id} ) { | |
226 $n->ancestor(undef); | |
227 # should be redundant | |
228 $self->{'_desc'}->{$n->internal_id}->ancestor(undef); | |
229 delete $self->{'_desc'}->{$n->internal_id}; | |
230 my $a1 = $self->ancestor; | |
231 # remove unecessary nodes if we have removed the part | |
232 # which branches. | |
233 # if( $a1 ) { | |
234 # my $bl = $self->branch_length || 0; | |
235 # my @d = $self->each_Descendent; | |
236 # if (scalar @d == 1) { | |
237 # $d[0]->branch_length($bl + ($d[0]->branch_length || 0)); | |
238 # $a1->add_Descendent($d[0]); | |
239 # } | |
240 # $a1->remove_Descendent($self); | |
241 #} | |
242 $c++; | |
243 } else { | |
244 if( $self->verbose ) { | |
245 $self->debug(sprintf("no node %s (%s) listed as a descendent in this node %s (%s)\n",$n->id, $n,$self->id,$self)); | |
246 $self->debug("Descendents are " . join(',', keys %{$self->{'_desc'}})."\n"); | |
247 } | |
248 } | |
249 } | |
250 $c; | |
251 } | |
252 | |
253 | |
254 =head2 remove_all_Descendents | |
255 | |
256 Title : remove_all_Descendents | |
257 Usage : $node->remove_All_Descendents() | |
258 Function: Cleanup the node's reference to descendents and reset | |
259 their ancestor pointers to undef, if you don't have a reference | |
260 to these objects after this call they will be cleaned up - so | |
261 a get_nodes from the Tree object would be a safe thing to do first | |
262 Returns : nothing | |
263 Args : none | |
264 | |
265 | |
266 =cut | |
267 | |
268 sub remove_all_Descendents{ | |
269 my ($self) = @_; | |
270 # this won't cleanup the nodes themselves if you also have | |
271 # a copy/pointer of them (I think)... | |
272 while( my ($node,$val) = each %{ $self->{'_desc'} } ) { | |
273 $val->ancestor(undef); | |
274 } | |
275 $self->{'_desc'} = {}; | |
276 1; | |
277 } | |
278 | |
279 =head2 get_all_Descendents | |
280 | |
281 Title : get_all_Descendents | |
282 Usage : my @nodes = $node->get_all_Descendents; | |
283 Function: Recursively fetch all the nodes and their descendents | |
284 *NOTE* This is different from each_Descendent | |
285 Returns : Array or Bio::Tree::NodeI objects | |
286 Args : none | |
287 | |
288 =cut | |
289 | |
290 # implemented in the interface | |
291 | |
292 =head2 ancestor | |
293 | |
294 Title : ancestor | |
295 Usage : $obj->ancestor($newval) | |
296 Function: Set the Ancestor | |
297 Returns : value of ancestor | |
298 Args : newvalue (optional) | |
299 | |
300 =cut | |
301 | |
302 sub ancestor{ | |
303 my $self = shift; | |
304 $self->{'_ancestor'} = shift @_ if @_; | |
305 return $self->{'_ancestor'}; | |
306 } | |
307 | |
308 =head2 branch_length | |
309 | |
310 Title : branch_length | |
311 Usage : $obj->branch_length() | |
312 Function: Get/Set the branch length | |
313 Returns : value of branch_length | |
314 Args : newvalue (optional) | |
315 | |
316 | |
317 =cut | |
318 | |
319 sub branch_length{ | |
320 my $self = shift; | |
321 if( @_ ) { | |
322 my $bl = shift; | |
323 if( defined $bl && | |
324 $bl =~ s/\[(\d+)\]// ) { | |
325 $self->bootstrap($1); | |
326 } | |
327 $self->{'_branch_length'} = $bl; | |
328 } | |
329 return $self->{'_branch_length'}; | |
330 } | |
331 | |
332 | |
333 =head2 bootstrap | |
334 | |
335 Title : bootstrap | |
336 Usage : $obj->bootstrap($newval) | |
337 Function: Get/Set the bootstrap value | |
338 Returns : value of bootstrap | |
339 Args : newvalue (optional) | |
340 | |
341 | |
342 =cut | |
343 | |
344 sub bootstrap { | |
345 my $self = shift; | |
346 if( @_ ) { | |
347 if( $self->has_tag('B') ) { | |
348 $self->remove_tag('B'); | |
349 } | |
350 $self->add_tag_value('B',shift); | |
351 } | |
352 return ($self->get_tag_values('B'))[0]; | |
353 } | |
354 | |
355 =head2 description | |
356 | |
357 Title : description | |
358 Usage : $obj->description($newval) | |
359 Function: Get/Set the description string | |
360 Returns : value of description | |
361 Args : newvalue (optional) | |
362 | |
363 | |
364 =cut | |
365 | |
366 sub description{ | |
367 my $self = shift; | |
368 $self->{'_description'} = shift @_ if @_; | |
369 return $self->{'_description'}; | |
370 } | |
371 | |
372 =head2 id | |
373 | |
374 Title : id | |
375 Usage : $obj->id($newval) | |
376 Function: The human readable identifier for the node | |
377 Returns : value of human readable id | |
378 Args : newvalue (optional) | |
379 Note : id cannot contain the chracters '();:' | |
380 | |
381 "A name can be any string of printable characters except blanks, | |
382 colons, semicolons, parentheses, and square brackets. Because you may | |
383 want to include a blank in a name, it is assumed that an underscore | |
384 character ("_") stands for a blank; any of these in a name will be | |
385 converted to a blank when it is read in." | |
386 | |
387 from L<http://evolution.genetics.washington.edu/phylip/newicktree.html> | |
388 | |
389 =cut | |
390 | |
391 sub id{ | |
392 my ($self, $value) = @_; | |
393 if ($value) { | |
394 $self->warn("Illegal characters ();: and space in the id [$value], converting to _ ") | |
395 if $value =~ /\(\);:/ and $self->verbose >= 0; | |
396 $value =~ s/[\(\);:\s]/_/g; | |
397 $self->{'_id'} = $value; | |
398 } | |
399 return $self->{'_id'}; | |
400 } | |
401 | |
402 =head2 internal_id | |
403 | |
404 Title : internal_id | |
405 Usage : my $internalid = $node->internal_id | |
406 Function: Returns the internal unique id for this Node | |
407 (a monotonically increasing number for this in-memory implementation | |
408 but could be a database determined unique id in other | |
409 implementations) | |
410 Returns : unique id | |
411 Args : none | |
412 | |
413 =cut | |
414 | |
415 sub internal_id{ | |
416 return $_[0]->_creation_id; | |
417 } | |
418 | |
419 | |
420 =head2 _creation_id | |
421 | |
422 Title : _creation_id | |
423 Usage : $obj->_creation_id($newval) | |
424 Function: a private method signifying the internal creation order | |
425 Returns : value of _creation_id | |
426 Args : newvalue (optional) | |
427 | |
428 | |
429 =cut | |
430 | |
431 sub _creation_id{ | |
432 my $self = shift @_; | |
433 $self->{'_creation_id'} = shift @_ if( @_); | |
434 return $self->{'_creation_id'} || 0; | |
435 } | |
436 | |
437 =head2 Bio::Node::NodeI decorated interface implemented | |
438 | |
439 The following methods are implemented by L<Bio::Node::NodeI> decorated | |
440 interface. | |
441 | |
442 =head2 is_Leaf | |
443 | |
444 Title : is_Leaf | |
445 Usage : if( $node->is_Leaf ) | |
446 Function: Get Leaf status | |
447 Returns : boolean | |
448 Args : none | |
449 | |
450 =cut | |
451 | |
452 sub is_Leaf { | |
453 my ($self) = @_; | |
454 my $isleaf = ! (defined $self->{'_desc'} && | |
455 (keys %{$self->{'_desc'}} > 0) ); | |
456 return $isleaf; | |
457 } | |
458 | |
459 =head2 to_string | |
460 | |
461 Title : to_string | |
462 Usage : my $str = $node->to_string() | |
463 Function: For debugging, provide a node as a string | |
464 Returns : string | |
465 Args : none | |
466 | |
467 =head2 height | |
468 | |
469 Title : height | |
470 Usage : my $len = $node->height | |
471 Function: Returns the height of the tree starting at this | |
472 node. Height is the maximum branchlength. | |
473 Returns : The longest length (weighting branches with branch_length) to a leaf | |
474 Args : none | |
475 | |
476 =cut | |
477 | |
478 sub height { | |
479 my ($self) = @_; | |
480 | |
481 return $self->{'_height'} if( defined $self->{'_height'} ); | |
482 | |
483 if( $self->is_Leaf ) { | |
484 if( !defined $self->branch_length ) { | |
485 $self->debug(sprintf("Trying to calculate height of a node when a Node (%s) has an undefined branch_length\n",$self->id || '?' )); | |
486 return 0; | |
487 } | |
488 return $self->branch_length; | |
489 } | |
490 my $max = 0; | |
491 foreach my $subnode ( $self->each_Descendent ) { | |
492 my $s = $subnode->height; | |
493 if( $s > $max ) { $max = $s; } | |
494 } | |
495 return ($self->{'_height'} = $max + ($self->branch_length || 1)); | |
496 } | |
497 | |
498 | |
499 =head2 invalidate_height | |
500 | |
501 Title : invalidate_height | |
502 Usage : private helper method | |
503 Function: Invalidate our cached value of the node's height in the tree | |
504 Returns : nothing | |
505 Args : none | |
506 | |
507 =cut | |
508 | |
509 #' | |
510 | |
511 sub invalidate_height { | |
512 my ($self) = @_; | |
513 | |
514 $self->{'_height'} = undef; | |
515 if( $self->ancestor ) { | |
516 $self->ancestor->invalidate_height; | |
517 } | |
518 } | |
519 | |
520 =head2 add_tag_value | |
521 | |
522 Title : add_tag_value | |
523 Usage : $node->add_tag_value($tag,$value) | |
524 Function: Adds a tag value to a node | |
525 Returns : number of values stored for this tag | |
526 Args : $tag - tag name | |
527 $value - value to store for the tag | |
528 | |
529 | |
530 =cut | |
531 | |
532 sub add_tag_value{ | |
533 my ($self,$tag,$value) = @_; | |
534 if( ! defined $tag || ! defined $value ) { | |
535 $self->warn("cannot call add_tag_value with an undefined value"); | |
536 } | |
537 push @{$self->{'_tags'}->{$tag}}, $value; | |
538 return scalar @{$self->{'_tags'}->{$tag}}; | |
539 } | |
540 | |
541 =head2 remove_tag | |
542 | |
543 Title : remove_tag | |
544 Usage : $node->remove_tag($tag) | |
545 Function: Remove the tag and all values for this tag | |
546 Returns : boolean representing success (0 if tag does not exist) | |
547 Args : $tag - tagname to remove | |
548 | |
549 | |
550 =cut | |
551 | |
552 sub remove_tag { | |
553 my ($self,$tag) = @_; | |
554 if( exists $self->{'_tags'}->{$tag} ) { | |
555 $self->{'_tags'}->{$tag} = undef; | |
556 delete $self->{'_tags'}->{$tag}; | |
557 return 1; | |
558 } | |
559 return 0; | |
560 } | |
561 | |
562 =head2 remove_all_tags | |
563 | |
564 Title : remove_all_tags | |
565 Usage : $node->remove_all_tags() | |
566 Function: Removes all tags | |
567 Returns : None | |
568 Args : None | |
569 | |
570 | |
571 =cut | |
572 | |
573 sub remove_all_tags{ | |
574 my ($self) = @_; | |
575 $self->{'_tags'} = {}; | |
576 return; | |
577 } | |
578 | |
579 =head2 get_all_tags | |
580 | |
581 Title : get_all_tags | |
582 Usage : my @tags = $node->get_all_tags() | |
583 Function: Gets all the tag names for this Node | |
584 Returns : Array of tagnames | |
585 Args : None | |
586 | |
587 | |
588 =cut | |
589 | |
590 sub get_all_tags{ | |
591 my ($self) = @_; | |
592 return sort keys %{$self->{'_tags'} || {}}; | |
593 } | |
594 | |
595 =head2 get_tag_values | |
596 | |
597 Title : get_tag_values | |
598 Usage : my @values = $node->get_tag_value($tag) | |
599 Function: Gets the values for given tag ($tag) | |
600 Returns : Array of values or empty list if tag does not exist | |
601 Args : $tag - tag name | |
602 | |
603 | |
604 =cut | |
605 | |
606 sub get_tag_values{ | |
607 my ($self,$tag) = @_; | |
608 return @{$self->{'_tags'}->{$tag} || []}; | |
609 } | |
610 | |
611 =head2 has_tag | |
612 | |
613 Title : has_tag | |
614 Usage : $node->has_tag($tag) | |
615 Function: Boolean test if tag exists in the Node | |
616 Returns : Boolean | |
617 Args : $tag - tagname | |
618 | |
619 | |
620 =cut | |
621 | |
622 sub has_tag { | |
623 my ($self,$tag) = @_; | |
624 return exists $self->{'_tags'}->{$tag}; | |
625 } | |
626 | |
627 sub node_cleanup { | |
628 my $self = shift; | |
629 if( defined $self->{'_desc'} && | |
630 ref($self->{'_desc'}) =~ /ARRAY/i ) { | |
631 while( my ($nodeid,$node) = each %{ $self->{'_desc'} } ) { | |
632 $node->ancestor(undef); # insure no circular references | |
633 $node = undef; | |
634 } | |
635 } | |
636 $self->{'_desc'} = {}; | |
637 } | |
638 | |
639 1; |