Coverage for /home/deng/Projects/ete4/hackathon/ete4/ete4/nexml/_nexml_tree.py: 23%
113 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-03-21 09:19 +0100
« prev ^ index » next coverage.py v7.2.7, created at 2024-03-21 09:19 +0100
1import sys
2from ._nexml import MixedContainer, FloatTree, TreeFloatEdge, TreeNode, LiteralMeta
3from .. import PhyloTree
4from ..parser.newick import loads
6class Children(list):
7 def append(self, item):
8 list.append(self, item)
9 item.nexml_edge.source = self.node.nexml_node.id
10 item.nexml_edge.target = item.nexml_node.id
12class NexmlTree(PhyloTree):
13 """
14 Special PhyloTree object with nexml support
15 """
17 def __repr__(self):
18 return "NexML ETE tree <%s>" %hex(hash(self))
20 def _get_dist(self):
21 return self.nexml_edge.get_length()
22 def _set_dist(self, value):
23 try:
24 self.nexml_edge.set_length(value)
25 except ValueError:
26 raise
28 def _get_support(self):
29 return self._nexml_support.content
30 def _set_support(self, value):
31 try:
32 self._nexml_support.content = float(value)
33 except ValueError:
34 raise
36 def _get_name(self):
37 return self.nexml_node.get_label()
39 def _set_name(self, value):
40 try:
41 self.nexml_node.set_label(value)
42 except ValueError:
43 raise
45 def _get_children(self):
46 return self._children
47 def _set_children(self, value):
48 if isinstance(value, Children) and \
49 len(set([type(n)==type(self) for n in value]))<2:
50 self._children = value
51 else:
52 raise ValueError("children:wrong type")
54 dist = property(fget=_get_dist, fset=_set_dist)
55 support = property(fget=_get_support, fset=_set_support)
56 children = property(fget=_get_children, fset=_set_children)
57 name = property(fget=_get_name, fset=_set_name)
59 def __init__(self, newick=None, alignment=None, alg_format="fasta", \
60 sp_naming_function=None, parser=0):
62 self.nexml_tree = FloatTree()
63 self.nexml_tree.set_anyAttributes_({'xsi:type': 'FloatTree'})
64 self.nexml_node = TreeNode()
65 self.nexml_edge = TreeFloatEdge()
66 self.nexml_node.id = "node_%s" %hash(self)
67 self.nexml_edge.id = "edge_%s" %hash(self)
68 self.nexml_project = None
69 self._nexml_support = LiteralMeta(datatype="float", property="branch_support", content=1.0)
70 self.nexml_edge.length = 0.0
71 self.nexml_edge.add_meta(self._nexml_support)
73 # Initialize empty PhyloTree
74 super(NexmlTree, self).__init__()
75 self._children = Children()
76 self._children.node = self
78 if alignment:
79 self.link_to_alignment(alignment, alg_format)
80 if newick:
81 tree = loads(newick, parser, self.__class__)
82 self.children = tree.children
83 self.props = tree.props
84 self.set_species_naming_function(sp_naming_function)
86 def set_nexml_project(self, nexml_obj):
87 self.nexml_project = nexml_obj
89 def build(self, node):
90 self.nexml_tree = FloatTree()
91 tree = self.nexml_tree
92 tree.build(node)
94 # This detects the outgroup of the tree even if the root tag
95 # is not set in any node
96 rootid = set([e.source for e in tree.edge]) - set([e.target for e in tree.edge])
98 nodeid2node = {rootid.pop(): self}
99 for xmledge in tree.edge:
100 child = nodeid2node.setdefault(xmledge.target, self.__class__() )
101 parent = nodeid2node.setdefault(xmledge.source, self.__class__() )
102 child.name = xmledge.target
103 child.nexml_node.id = xmledge.target
104 parent.name = xmledge.source
105 parent.nexml_node.id = xmledge.source
106 child.nexml_edge = xmledge
108 if xmledge.length is not None:
109 child.dist = float(xmledge.length)
110 parent.add_child(child)
112 for xmlnode in tree.node:
113 # just a warning. I don't know if this can occur
114 if xmlnode.id not in nodeid2node:
115 print("Unused node", xmlnode.id, file=sys.stderr)
116 continue
118 ete_node = nodeid2node[xmlnode.id]
119 ete_node.nexml_node = xmlnode
121 if xmlnode.label:
122 ete_node.name = xmlnode.label
123 elif xmlnode.id is not None:
124 ete_node.name = xmlnode.id
127 def export(self, outfile=sys.stdout, level=0, namespace_='', name_='FloatTree', namespacedef_=''):
128 if self.nexml_tree:
129 info = [(n.nexml_edge, n.nexml_node) for n in self.traverse()]
130 self.nexml_node.set_root(True)
131 self.nexml_tree.set_edge([i[0] for i in info])
132 self.nexml_tree.set_node([i[1] for i in info])
133 self.nexml_tree.export(outfile=outfile, level=level, name_=name_, namespacedef_=namespacedef_)
136 def exportChildren(self, outfile, level, namespace_='', name_='FloatTree'):
137 sorted_nodes = []
138 sorted_edges = []
139 for n in self.traverse():
140 # process node
141 node_obj = self.mixedclass_(MixedContainer.CategoryComplex,
142 MixedContainer.TypeNone, 'node', n.nexml_node)
143 sorted_nodes.append(node_obj)
145 # process edge
146 if n.nexml_edge:
147 edge_obj = self.mixedclass_(MixedContainer.CategoryComplex,
148 MixedContainer.TypeNone, 'edge', n.nexml_edge)
149 sorted_edges.append(edge_obj)
151 # process the nodes and edges
152 self.tree.content_ = sorted_nodes + sorted_edges
153 for item_ in self.tree.content_:
154 item_.export(outfile, level, item_.name, namespace_)
156# end class AbstractTreeSub
157NexmlNode = NexmlTree