def AddLeafToTree(self, id, diameter): """ Add a single leaf to the tree. The position is guided by the diameter parameter which indicates the precentage of the maximum possible tree diameter to use. """ # Handle the cases where the tree is empty (or a single node) if len(self.__tree.vertices) == 0: Leaf(label=id, tree=self.__tree) elif len(self.__tree.vertices) == 1: Edge(nodes=[ self.__tree.vertices[0], Leaf(label=id, tree=self.__tree) ], tree=self.__tree) else: # Find the edges which will (and will not) increase the diameter (will, willnot) = self.__PartitionEdges() # if no unmarked edges exist or we want to increase diameter # randomly select an edge to split if not len(willnot) or random.random() > (1.0 - diameter): esplit = random.choice(will) else: esplit = random.choice(willnot) # Add new taxa splitting the edge self.__SplitEdge(esplit, id)
def __TreeFromBipartition(self, bp): """Generate an initial non-binary tree from a bipartition""" e = Edge(tree=self.__tree) left = Inner(edges=[e], tree=self.__tree) right = Inner(edges=[e], tree=self.__tree) [ Edge(nodes=[Leaf(label=str(leaf), tree=self.__tree), left], tree=self.__tree) for leaf in bp.left ] [ Edge(nodes=[Leaf(label=str(leaf), tree=self.__tree), right], tree=self.__tree) for leaf in bp.right ]
def __FindAncestors(self, leaves): """ Finds all inner nodes in the path between the leaves. Leaves not found will be added. """ leafIdSet = set(str(l) for l in leaves) # Find any new leafs newLeafIds = leafIdSet.difference(self.__tree.leafSet) assert len(newLeafIds) != len(leafIdSet) oldLeafIds = leafIdSet - newLeafIds oldLeafObjs = [l for l in self.__tree.leaves if str(l) in oldLeafIds] # Only one id, add any nodes to it's parent if len(oldLeafObjs) == 1: parent = oldLeafObjs[0].edges[0].Other(oldLeafObjs[0]) newLeafObjs = [] for l in newLeafIds: leaf = Leaf(edge=Edge(nodes=[parent], tree=self.__tree), label=l, tree=self.__tree) newLeafObjs.append(leaf) inodes = self.__FindInnerNodes(oldLeafObjs + newLeafObjs) # Multiple old id's, find the overall path and add to the common node else: # Get the paths for the existing (old) leafs inodes = self.__FindInnerNodes(oldLeafObjs) assert not len(newLeafIds) or len(inodes) == 1 # Add new nodes to the tree at the inode point [ Leaf(edge=Edge(nodes=[inodes[0]], tree=self.__tree), label=l, tree=self.__tree) for l in newLeafIds ] return inodes
def __SplitEdge(self, edge, id): """ Add a new taxa by splitting an existing edge """ # Disconnect the edge nright = edge.nodes[0] nleft = edge.nodes[1] nright.RemoveEdge(edge) nleft.RemoveEdge(edge) # Connect it all up Leaf(label=id, edge=edge, tree=self.__tree) Inner(edges=[ Edge(nodes=[nleft], tree=self.__tree), Edge(nodes=[nright], tree=self.__tree), edge ], tree=self.__tree)