1 __VERSION__="ete2-2.0rev90"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import os
26 import random
27
28 __all__ = ["Tree", "TreeNode"]
29
30 from ete2.parser.newick import read_newick, write_newick
31
32 DEFAULT_COMPACT = False
33 DEFAULT_SHOWINTERNAL = False
34
36 """Exception class designed for tree."""
40 return repr(self.value)
41
43 """ TreeNode (Tree) class is used to store a tree structure. A tree
44 consists of a collection of TreeNode instances connected in a
45 hierarchical way. Trees can be loaded from the New Hampshire Newick
46 format (newick).
47
48 CONSTRUCTOR ARGUMENTS:
49 ======================
50
51 * newick: Path to the file containing the tree or, alternatively,
52 the text string containing the same information.
53
54 RETURNS:
55 ========
56 The TreeNode object which represents the base (root) of the
57 tree.
58
59 EXAMPLES:
60 =========
61 t1 = Tree() # creates an empty tree
62 t2 = Tree( '(A:1,(B:1,(C:1,D:1):0.5):0.5);' )
63 t3 = Tree( '/home/user/myNewickFile.txt' )
64 """
65
69 try:
70 self._dist = float(value)
71 except ValueError:
72 raise
73
77 try:
78 self._support = float(value)
79 except ValueError:
80 raise
81
85 if type(value) == type(self) or value is None:
86 self._up = value
87 else:
88 raise ValueError, "up: wrong type"
89
93 if type(value) == list and \
94 len(set([type(n)==type(self) for n in value]))<2:
95 self._children = value
96 else:
97 raise ValueError, "children:wrong type"
98
99 dist = property(fget=_get_dist, fset=_set_dist)
100 support = property(fget=_get_support, fset=_set_support)
101 up = property(fget=_get_up, fset=_set_up)
102 children = property(fget=_get_children, fset=_set_children)
103
104 - def __init__(self, newick=None, format=0):
105 self._children = []
106 self._up = None
107 self._dist = 1.0
108 self._support = 1.0
109
110 self.features = set([])
111 self.collapsed = False
112
113 self.add_features(name="NoName")
114 self.features.update(["dist", "support"])
115
116 if newick is not None:
117 read_newick(newick, root_node = self, format=format)
118
120 """ This allows to execute tree&'A' to obtain the descendant node
121 A"""
122 value=str(value)
123 try:
124 first_match = self.iter_search_nodes(name=value).next()
125 return first_match
126 except StopIteration:
127 raise ValueError, "Node not found"
128
130 """ This allows to sum two trees."""
131
132 if type(value) == self.__class__:
133 new_root = self.__class__()
134 new_root.add_child(self)
135 new_root.add_child(value)
136 return new_root
137 else:
138 raise ValueError, "Invalid node type"
139
144
146 """ Check if item belongs to this node. The 'item' argument must
147 be a node instance or its associated name."""
148 if isinstance(item, self.__class__):
149 return item in set(self.get_descendants())
150 elif type(item)==str:
151 return item in set([n.name for n in self.get_descendants()])
152
154 """Node len returns number of children."""
155 return len(self.get_leaves())
156
158 """ Iterator over leaf nodes"""
159 return self.iter_leaves()
160
162 """ Adds or updates a node's feature. """
163 setattr(self, pr_name, pr_value)
164 self.features.add(pr_name)
165
167 """ Adds or updates a node's feature. """
168 for fname, fvalue in features.iteritems():
169 setattr(self, fname, fvalue)
170 self.features.add(fname)
171
173 """ Deletes permanently a node's feature. """
174 if hasattr(self, pr_name):
175 delattr(self, pr_name)
176 self.features.remove(pr_name)
177
178
179 - def add_child(self, child=None, name=None, dist=None, support=None):
180 """
181 Adds a new child to this node. If child node is not suplied
182 as an argument, a new node instance will be created.
183
184 ARGUMENTS:
185 ==========
186
187 * 'child': the node instance to be added as a child.
188 * 'name': the name that will be given to the child.
189 * 'dist': the distance from the node to the child.
190 * 'support': the support value of child partition.
191
192 RETURNS:
193 ========
194
195 The child node instace
196
197 """
198 if child is None:
199 child = self.__class__()
200
201
202
203
204
205
206
207 if name is not None:
208 try:
209 child.add_feature("name", str(name))
210 except ValueError:
211 raise TreeError, "Node's name has to be a string"
212
213 if dist is not None:
214 try:
215 child.add_feature("dist", float(dist))
216 except ValueError:
217 raise TreeError, "Node's dist has must be a float number"
218
219 if support is not None:
220 try:
221 child.add_feature("support", float(support))
222 except ValueError:
223 raise TreeError, "Node's support must be a float number"
224
225 self.children.append(child)
226 child.up = self
227 return child
228
230 """ Removes a child from this node (parent and child
231 nodes still exit but are no longer connected). """
232 try:
233 self.children.remove(child)
234 except ValueError, e:
235 raise TreeError, e
236 else:
237 child.up = None
238 return child
239
240 - def add_sister(self, sister=None, name=None, dist=None):
241 """
242 Adds a sister to this node. If sister node is not supplied
243 as an argument, a new TreeNode instance will be created and
244 returned.
245 """
246 if self.up == None:
247 raise TreeError, "A parent node is required to add a sister"
248 else:
249 return self.up.add_child(child=sister, name=name, dist=dist)
250
252 """
253 Removes a node's sister node. It has the same effect as
254 node.up.remove_child(sister).
255
256 If a sister node is not supplied, the first sister will be deleted
257 and returned.
258
259 ARGUMENTS:
260 ==========
261 'sister': A node instance
262
263 RETURNS:
264 ========
265 The removed node
266
267 """
268 sisters = self.get_sisters()
269 if len(sisters)>0:
270 if sister==None:
271 sister = sisters.pop(0)
272 return self.up.remove_child(sister)
273
274 - def delete(self, prevent_nondicotomic=True):
275 """
276 Deletes node from the tree structure. Notice that this
277 method makes 'disapear' the node from the tree structure. This
278 means that children from the deleted node are transferred to the
279 next available parent.
280
281 EXAMPLE:
282 ========
283 / C
284 root-|
285 | / B
286 \--- H |
287 \ A
288
289 > root.delete(H) will produce this structure:
290
291 / C
292 |
293 root-|--B
294 |
295 \ A
296
297 """
298 parent = self.up
299 if parent:
300 for ch in self.children:
301 parent.add_child(ch)
302 parent.remove_child(self)
303
304
305 if prevent_nondicotomic and parent and\
306 len(parent.children)<2:
307 parent.delete(prevent_nondicotomic=False)
308
309
311 """
312 Detachs this node (and all its descendants) from its parent
313 and returns the referent to itself.
314
315 Detached node conserves all its structure of descendants, and can
316 be attached to another node through the 'add_child' function. This
317 mechanisim can be seen as a cut and paste."""
318
319 if self.up:
320 self.up.children.remove(self)
321 self.up = None
322 return self
323
325 """
326 Prunes the topology of this node in order to conserve only a
327 selected list of leaf or internal nodes. The algorithm deletes
328 nodes until getting a consistent topology with a subset of
329 nodes. Topology relationships among kept nodes is maintained.
330
331 ARGUMENTS:
332 ==========
333 * 'nodes' is a list of node names or node objects that must be kept.
334
335 EXAMPLES:
336 =========
337 t = Tree("(((A:0.1, B:0.01):0.001, C:0.0001):1.0[&&NHX:name=I], (D:0.00001):0.000001[&&NHX:name=J]):2.0[&&NHX:name=root];")
338 node_C = t.search_nodes(name="C")[0]
339 t.prune(["A","D", node_C])
340 print t
341 """
342
343 to_keep = set(_translate_nodes(self, *nodes))
344 to_detach = []
345 for node in self.traverse("postorder"):
346 for c in node.children:
347 if c in to_keep:
348 to_keep.add(node)
349 break
350 if node not in to_keep:
351 to_detach.append(node)
352 for c in node.children:
353 to_detach.remove(c)
354 for node in to_detach:
355 node.detach()
356 for node in to_keep:
357 if len(node.children) == 1:
358 node.delete()
359 if len(self.children)==1:
360 self.children[0].delete()
361
363 """ Returns an iterator over the leaves under this node. """
364 for n in self.traverse(strategy="preorder"):
365 if n.is_leaf():
366 yield n
367
369 """ Returns an iterator over the leaf names under this node. """
370 for n in self.iter_leaves():
371 yield n.name
372
374 """ Returns an iterator over descendant nodes. """
375 for n in self.traverse(strategy=strategy):
376 if n != self:
377 yield n
379 """ Iterator over all desdecendant nodes. """
380 current = self
381 end = self.up
382 visited_childs = set([])
383 while current is not end:
384 childs = False
385 for c in current.children:
386 if c not in visited_childs:
387 childs = True
388 current = c
389 break
390 if not childs:
391 visited_childs.add(current)
392 yield current
393 current = current.up
394
396 """ Iterator over all desdecendant nodes. """
397 tovisit = [self]
398 while len(tovisit)>0:
399 current = tovisit.pop(0)
400 yield current
401 tovisit.extend(current.children)
402
403 - def traverse(self, strategy="preorder"):
404 """
405 Returns an iterator that traverse the tree structure under this
406 node.
407
408 ARGUMENTS:
409 ==========
410
411 'strategy' defines the way in which tree will be
412 traversed. Possible values are: "preorder" (first parent and
413 then children) 'postorder' (first children and the parent).
414
415 """
416 if strategy=="preorder":
417 return self._iter_descendants_preorder()
418 elif strategy=="postorder":
419 return self._iter_descendants_postorder()
421 """
422 Swaps current childs order.
423 """
424 if len(self.children)>1:
425 self.children.reverse()
427 """ Returns an independent list of node's children. """
428 return [ch for ch in self.children]
429
431 """ Returns an indepent list of sister nodes. """
432 if self.up!=None:
433 return [ch for ch in self.up.children if ch!=self]
434 else:
435 return []
436
438 """ Prints general information about this node and its
439 connections."""
440 if len(self.get_tree_root().children)==2:
441 rooting = "Yes"
442 elif len(self.get_tree_root().children)>2:
443 rooting = "No"
444 else:
445 rooting = "Unknown"
446 max_node, max_dis = get_farthest_leaf()
447 print "Number of nodes:\t %d" % len(self.get_descendants())
448 print "Number of leaves:\t %d" % len(self.get_leaves())
449 print "Rooted:", rooting
450 print "Max. lenght to root:"
451 print "The Farthest descendant node is", max_node.name,\
452 "with a branch distance of", max_dist
453
454 - def write(self, features=None, outfile=None, format=0):
455 """ Returns the newick representation of this node
456 topology. Several arguments control the way in which extra
457 data is shown for every node:
458
459 features: a list of feature names that want to be shown
460 (when available) for every node. Extended newick format is
461 used to represent data.
462
463 'format' defines the newick standard used to encode the
464 tree. See tutorial for details.
465
466 Example:
467 t.get_newick(["species","name"], format=1)
468 """
469
470 nw = write_newick(self, features = features, format=format)
471 if outfile is not None:
472 open(outfile, "w").write(nw)
473 return nw
474 else:
475 return nw
476
478 """ Returns the absolute root node of current tree structure. """
479 root = self
480 while root.up is not None:
481 root = root.up
482 return root
483
485 """ Returns the first common ancestor between this node and a given
486 list of 'target_nodes'.
487
488 EXAMPLES:
489 =========
490 t = tree.Tree("(((A:0.1, B:0.01):0.001, C:0.0001):1.0[&&NHX:name=common], (D:0.00001):0.000001):2.0[&&NHX:name=root];")
491 A = t.get_descendants_by_name("A")[0]
492 C = t.get_descendants_by_name("C")[0]
493 common = A.get_common_ancestor(C)
494 print common.name
495
496 """
497
498
499 target_nodes = _translate_nodes(self, *target_nodes)
500
501
502 if type(target_nodes) != list:
503 target_nodes = [target_nodes, self]
504 elif len(target_nodes)==1:
505 target_nodes = tree_nodes.append(self)
506
507 start = target_nodes[-1]
508 targets = set(target_nodes)
509 nodes_bellow = set([start]+start.get_descendants())
510 current = start
511 prev_node = start
512 while current is not None:
513
514 new_nodes = [n for s in current.children for n in s.traverse() \
515 if s is not prev_node]+[current]
516 nodes_bellow.update(new_nodes)
517 if targets.issubset(nodes_bellow):
518 break
519 else:
520 prev_node = current
521 current = current.up
522
523 return current
524
526 """
527 Returns the list of terminal nodes (leaves) under this node.
528 """
529 return [n for n in self.iter_leaves()]
530
532 """
533 Returns the list of terminal node names under the current
534 node.
535 """
536 return [ n.name for n in self.iter_leaves() ]
537
539 """
540 Returns the list of all nodes (leaves and internal) under
541 this node.
542 re buil
543 See iter_descendants method.
544 """
545 return [n for n in self.traverse(strategy="preorder") if n != self]
546
548 for n in self.traverse():
549 conditions_passed = 0
550 for key, value in conditions.iteritems():
551 if hasattr(n, key) and getattr(n, key) == value:
552 conditions_passed +=1
553 if conditions_passed == len(conditions):
554 yield n
555
557 matching_nodes = []
558 for n in self.iter_search_nodes(**conditions):
559 matching_nodes.append(n)
560 return matching_nodes
561
563 """ Returns a list of nodes marching a given name. """
564 return self.search_nodes(name=name, children=[])
565
567 if self.collapsed or len(self.children)==0:
568 return True
569 else:
570 return False
571
573 if self.up is None:
574 return True
575 else:
576 return False
577
582
583
584 - def get_distance(self, target, target2=None, topology_only=False):
585 """
586
587 Returns the distance between two nodes. If only one target is
588 specified, it returns the distance bewtween the target and the
589 current node.
590
591 ARGUMENTS:
592 ==========
593 'target': a node within the same tree structure.
594
595 'target2': a node within the same tree structure. If
596 not specified, current node is used as target2.
597
598 RETURNS:
599 ========
600 the distance between nodes
601
602 """
603
604 if target2 is None:
605 target2 = self
606 root = self.get_tree_root()
607 else:
608
609 root = self
610
611 target, target2 = _translate_nodes(root, target, target2)
612 ancestor = root.get_common_ancestor(target, target2)
613 if ancestor is None:
614 raise TreeError, "Nodes are not connected"
615
616 dist = 0.0
617 for n in [target2, target]:
618 current = n
619 while current != ancestor:
620 if topology_only:
621 if current!=target:
622 dist += 1
623 else:
624 dist += current.dist
625 current = current.up
626 return dist
627
629 """
630 Returns the node's farthest descendant or ancestor node, and the
631 distance to it.
632
633 ARGUMENTS:
634 ==========
635
636 * 'topology_only' [True or False]: defines whether branch node
637 distances should be discarded from analysis or not. If
638 "True", only topological distance (number of steps to get the
639 target node) will be used.
640
641 RETURNS:
642 ========
643 A tuple = (farthest_node, dist_to_farthest_node)
644
645 """
646
647 farthest_node,farthest_dist = self.get_farthest_leaf(topology_only=topology_only)
648 prev = self
649 if topology_only:
650 cdist = 0
651 else:
652 cdist = prev.dist
653 current = prev.up
654 while current is not None:
655 for ch in current.children:
656 if ch != prev:
657 if not ch.is_leaf():
658 fnode, fdist = ch.get_farthest_leaf(topology_only=topology_only)
659 else:
660 fnode = ch
661 fdist = 0
662 if topology_only:
663 fdist += 1.0
664 else:
665 fdist += ch.dist
666 if cdist+fdist > farthest_dist:
667 farthest_dist = cdist + fdist
668 farthest_node = fnode
669 prev = current
670 if topology_only:
671 cdist += 1
672 else:
673 cdist += prev.dist
674 current = prev.up
675 return farthest_node, farthest_dist
676
678 """
679 Returns node's farthest descendant node (which is always a leaf), and the
680 distance to it.
681
682 ARGUMENTS:
683 ==========
684
685 * 'topology_only' [True or False]: defines whether branch node
686 distances should be discarded from analysis or not. If
687 "True", only topological distance (number of steps to get the
688 target node) will be used.
689
690 RETURNS:
691 ========
692 A tuple = (farthest_node, dist_to_farthest_node)
693
694 """
695 max_dist = 0.0
696 max_node = None
697 if self.is_leaf():
698 return self, 0.0
699 else:
700 for ch in self.children:
701 node, d = ch.get_farthest_leaf(topology_only=topology_only)
702 if topology_only:
703 d += 1.0
704 else:
705 d += ch.dist
706 if d>=max_dist:
707 max_dist = d
708 max_node = node
709 return max_node, max_dist
710
712 """
713 Returns the node that divides the current tree into two distance-balanced
714 partitions.
715 """
716
717 root = self.get_tree_root()
718 nA , r2A_dist = root.get_farthest_leaf()
719 nB , A2B_dist = nA.get_farthest_node()
720
721 outgroup = nA
722 middist = A2B_dist / 2.0
723 cdist = 0
724 current = nA
725 while current is not None:
726 cdist += current.dist
727 if cdist > (middist):
728 break
729 else:
730 current = current.up
731 return current
732
733 - def populate(self, size, names_library=[], reuse_names=True):
734 """
735 Populates the partition under this node with a given number
736 of leaves. Internal nodes are added as required.
737
738 ARGUMENTS:
739 ==========
740
741 * 'size' is the number of leaf nodes to add to the current
742 tree structure.
743 """
744
745 charset = "abcdefghijklmnopqrstuvwxyz"
746 prev_size = len(self)
747 terminal_nodes = set(self.get_leaves())
748 silly_nodes = set([n for n in self.traverse() \
749 if len(n)==1 and n.children!=[]])
750
751 if self.is_leaf():
752 size -=1
753 names_library = set(names_library)
754 while len(terminal_nodes) != size+prev_size:
755 try:
756 target = random.sample(silly_nodes, 1)[0]
757 silly_nodes.remove(target)
758 except ValueError:
759 target = random.sample(terminal_nodes, 1)[0]
760 terminal_nodes.remove(target)
761 silly_nodes.add(target)
762 if target is not self:
763 names_library.add(target.name)
764
765
766 if len(names_library)>0:
767 tname = random.sample(names_library,1)[0]
768 if not reuse_names:
769 names_library.remove(tname)
770
771 else:
772 tname = ''.join(random.sample(charset,5))
773 tdist = random.random()
774 new_node = target.add_child( name=tname, dist=tdist )
775 terminal_nodes.add(new_node)
777 """
778 Sets a descendant node as the outgroup of a tree. This function
779 can be used to root a tree or even an internal node.
780
781 ARGUMENTS:
782 ==========
783
784 * 'outgroup' is a leaf or internal node under the current tree
785 structure.
786 """
787
788 outgroup = _translate_nodes(self, outgroup)
789
790 if self == outgroup:
791 raise ValueError, "Cannot set myself as outgroup"
792
793 parent_outgroup = outgroup.up
794
795
796 n = outgroup
797 while n.up is not self:
798 n = n.up
799
800
801
802
803 self.children.remove(n)
804 if len(self.children)>1:
805 down_branch_connector = self.__class__()
806 down_branch_connector.dist = 0.0
807 down_branch_connector.support = n.support
808 for ch in self.get_children():
809 down_branch_connector.children.append(ch)
810 ch.up = down_branch_connector
811 self.children.remove(ch)
812 else:
813 down_branch_connector = self.children[0]
814
815
816 quien_va_ser_padre = parent_outgroup
817 if quien_va_ser_padre is not self:
818
819 quien_va_ser_hijo = quien_va_ser_padre.up
820 quien_fue_padre = None
821 buffered_dist = quien_va_ser_padre.dist
822 buffered_support = quien_va_ser_padre.support
823
824 while quien_va_ser_hijo is not self:
825 quien_va_ser_padre.children.append(quien_va_ser_hijo)
826 quien_va_ser_hijo.children.remove(quien_va_ser_padre)
827
828 buffered_dist2 = quien_va_ser_hijo.dist
829 buffered_support2 = quien_va_ser_hijo.support
830 quien_va_ser_hijo.dist = buffered_dist
831 quien_va_ser_hijo.support = buffered_support
832 buffered_dist = buffered_dist2
833 buffered_support = buffered_support2
834
835 quien_va_ser_padre.up = quien_fue_padre
836 quien_fue_padre = quien_va_ser_padre
837
838 quien_va_ser_padre = quien_va_ser_hijo
839 quien_va_ser_hijo = quien_va_ser_padre.up
840
841 quien_va_ser_padre.children.append(down_branch_connector)
842 down_branch_connector.up = quien_va_ser_padre
843 quien_va_ser_padre.up = quien_fue_padre
844
845 down_branch_connector.dist += buffered_dist
846 outgroup2 = parent_outgroup
847 parent_outgroup.children.remove(outgroup)
848 outgroup2.dist = 0
849
850 else:
851 outgroup2 = down_branch_connector
852
853 outgroup.up = self
854 outgroup2.up = self
855 self.children = [outgroup,outgroup2]
856 middist = (outgroup2.dist + outgroup.dist)/2
857 outgroup.dist = middist
858 outgroup2.dist = middist
859 outgroup2.support = outgroup.support
860 self.children.sort()
861
863 """ Unroots this node. This function is intented to be used over
864 the absolute tree root node, but it can be also be applied to any
865 other internal node. """
866
867 if not self.is_root():
868 print >>sys.stderr, "Warning. You are unrooting an internal node.!!"
869 if len(self.children)==2:
870 if not self.children[0].is_leaf():
871 self.children[0].delete()
872 elif not self.children[1].is_leaf():
873 self.children[1].delete()
874 else:
875 raise TreeError, "Cannot unroot a tree with only two leaves"
876
877 - def show(self, layout=None, \
878 image_properties=None):
879 """ Begins an interative session to visualize this node
880 structure."""
881 try:
882 from ete2.treeview import drawer
883 except ImportError, e:
884 print "'treeview' module could not be loaded.\n",e
885 print "\n\n"
886 print self
887 else:
888 drawer.show_tree(self,layout,image_properties)
889
890 - def render(self, file_name, layout=None, w=None, h=None, \
891 img_properties=None, header=None):
892 """ Renders the tree structure into an image file. """
893 try:
894 from ete2.treeview import drawer
895 except ImportError, e:
896 print "'treeview' module could not be loaded.\n",e
897 print "\n\n"
898 print self
899 print e
900 else:
901 drawer.render_tree(self, file_name, w=w, h=h, style=layout, \
902 img_properties=img_properties, \
903 header=header)
904
905 - def _asciiArt(self, char1='-', show_internal=True, compact=False):
906 """
907 Returns the ASCII representation of the tree. Code taken from the
908 PyCogent GPL project.
909 """
910
911 LEN = 5
912 PAD = ' ' * LEN
913 PA = ' ' * (LEN-1)
914 if not self.is_leaf():
915 mids = []
916 result = []
917 for c in self.children:
918 if c is self.children[0]:
919 char2 = '/'
920 elif c is self.children[-1]:
921 char2 = '\\'
922 else:
923 char2 = '-'
924 (clines, mid) = c._asciiArt(char2, show_internal, compact)
925 mids.append(mid+len(result))
926 result.extend(clines)
927 if not compact:
928 result.append('')
929 if not compact:
930 result.pop()
931 (lo, hi, end) = (mids[0], mids[-1], len(result))
932 prefixes = [PAD] * (lo+1) + [PA+'|'] * (hi-lo-1) + [PAD] * (end-hi)
933 mid = (lo + hi) / 2
934 prefixes[mid] = char1 + '-'*(LEN-2) + prefixes[mid][-1]
935 result = [p+l for (p,l) in zip(prefixes, result)]
936 if show_internal:
937 stem = result[mid]
938 result[mid] = stem[0] + self.name + stem[len(self.name)+1:]
939 return (result, mid)
940 else:
941 return ([char1 + '-' + self.name], 0)
942
943 - def get_ascii(self, show_internal=True, compact=False):
944 """Returns a string containing an ascii drawing of the tree.
945
946 Arguments:
947 - show_internal: includes internal edge names.
948 - compact: use exactly one line per tip.
949 """
950 (lines, mid) = self._asciiArt(
951 show_internal=show_internal, compact=compact)
952 return '\n'+'\n'.join(lines)
953
954
956 target_nodes = []
957 for n in nodes:
958 if type(n) is str:
959 mnodes = root.search_nodes(name=n)
960 if len(mnodes) == 0:
961 raise ValueError, "Node name not found: "+str(n)
962 elif len(mnodes)>1:
963 raise ValueError, "Ambiguos node name: "+str(n)
964 else:
965 target_nodes.append(mnodes[0])
966 elif type(n) != root.__class__:
967 raise ValueError, "Invalid target node: "+str(n)
968 else:
969 target_nodes.append(n)
970
971 if len(target_nodes) == 1:
972 return target_nodes[0]
973 else:
974 return target_nodes
975
976
978 try:
979 import rpy2.robjects as robjects
980 R = robjects.r
981 except ImportError, e:
982 print e
983 print >>sys.stderr, "RPy >= 2.0 is required to connect"
984 return
985
986 R.library("ape")
987 return Tree( R["write.tree"](R_phylo_tree)[0])
988
990 try:
991 import rpy2.robjects as robjects
992 R = robjects.r
993 except ImportError, e:
994 print e
995 print >>sys.stderr, "RPy >= 2.0 is required to connect"
996 return
997 R.library("ape")
998 return R['read.tree'](text=ETE_tree.write())
999
1000
1001
1002 Tree = TreeNode
1003