def plotLines(self): """plot lines of the tree""" # plot tree in dfs manner def plotLines(node_id): node = self.mTree.node(node_id) left = self.mNodeWidthsStart[node_id] right = self.mNodeWidthsEnd[node_id] height = self.mNodeHeights[node_id] if right != left and node_id != self.mTree.root: self.addElements( self.mDecoratorHorizontalBranches.getElements( node_id, self.getHeaderWidth() + left, self.getHeaderWidth() + right, self.getHeaderHeight() + height)) for s in node.succ: new_height = self.mNodeHeights[s] self.addElements( self.mDecoratorVerticalBranches.getElements( node_id, self.getHeaderWidth() + right, self.getHeaderHeight() + height, self.getHeaderHeight() + new_height)) TreeTools.TreeDFS(self.mTree, self.mTree.root, pre_function=plotLines)
def calculateCoordinates(self): self.mNodeHeights = [0] * self.mNNodes self.mNodeWidthsStart = [0] * self.mNNodes self.mNodeWidthsEnd = [0] * self.mNNodes # if no scales are given, try to do best fit if self.mHeightScaleFactor == 0: rescale_height = True self.mHeightScaleFactor = 1 else: rescale_height = False if self.mBranchScaleFactor == 0: rescale_width = True self.mBranchScaleFactor = 100 else: rescale_width = False ########################################################## # Get Vertical coordinates # Label nodes by their height. Terminal nodes have integer coordinates. # Internal nodes have fractional coordinates (the average between the two # children) counter = [0] def updateHeights(node_id): l = len(self.mTree.node(node_id).succ) if l: # set node height for internal node t = 0 for x in self.mTree.node(node_id).succ: t += self.mNodeHeights[x] # used to use use the following to take into account # the height of symbols. This is wrong and better done by # pre-traversal of the tree # self.mNodeHeights[node_id] = float(t) / float(l) + max( self.mDecoratorInternalNodes.getHeight( node_id ), self.mDecoratorHorizontalBranches.getHeight( node_id )) # instead: use uncorrected heights. self.mNodeHeights[node_id] = float(t) / float(l) else: # set node height for external node self.mNodeHeights[node_id] = counter[0] counter[0] += max(self.mDecoratorExternalNodes.getHeight(node_id), self.mDecoratorHorizontalBranches.getHeight( node_id) ) \ * self.mHeightScaleFactor + self.mTerminalLabelSeparator TreeTools.TreeDFS(self.mTree, self.mTree.root, post_function=updateHeights) self.mMaxNodeHeight = counter[0] ########################################################## # Get horizontal coordinates def updateWidths(node_id): node = self.mTree.node(node_id) d = node.data.branchlength # set default branchlength to 0.01 for empty branch lengths # TODO: deal with trees without branch lengths later. if d <= 0.0: d = 0.01 right = self.mNodeWidthsStart[node_id] + int( d * self.mBranchScaleFactor) self.mNodeWidthsEnd[node_id] = right for s in node.succ: self.mNodeWidthsStart[s] = right TreeTools.TreeDFS(self.mTree, self.mTree.root, pre_function=updateWidths) if rescale_height: m = max(self.mNodeHeights) f = float(self.mDefaultHeight) / m if 100 * f < 1: f = 0.01 self.mHeightScaleFactor = 100 * f self.mNodeHeights = map(lambda x: int(x * f), self.mNodeHeights) self.mMaxNodeHeight *= f if rescale_width: m = max(self.mNodeWidthsEnd) f = float(self.mDefaultWidth) / m self.mBranchScaleFactor = 100 * f self.mNodeWidthsStart = map(lambda x: int(x * f), self.mNodeWidthsStart) self.mNodeWidthsEnd = map(lambda x: int(x * f), self.mNodeWidthsEnd) # add a safety margin for decorators writing above the line. This # is a patch and should be changed such that decorators report # their correct height for x in range(self.mNNodes): self.mNodeHeights[x] += 45
def extractSubtrees(tree, extract_species, options): """extract subtrees from tree. Splits a rooted tree at outgroups or at out-paralogs. Returns a list of clusters with its members belonging to each subtree. """ nin = [0] * TreeTools.GetSize(tree) nout = [0] * TreeTools.GetSize(tree) nstop = [False] * TreeTools.GetSize(tree) taxa = [set() for x in range(TreeTools.GetSize(tree))] otus = [set() for x in range(TreeTools.GetSize(tree))] clusters = [] def update_groups(node_id): node = tree.node(node_id) if node.succ == []: taxa[node_id] = set((extract_species(node.data.taxon),)) otus[node_id] = set((node.data.taxon,)) if extract_species(node.data.taxon) in options.outgroup_species: nout[node_id] = 1 else: nin[node_id] = 1 else: a, b = node.succ oa = nout[a] > 0 ob = nout[b] > 0 ia = nin[a] > 0 ib = nin[b] > 0 overlap = len(taxa[a].intersection(taxa[b])) > 0 # merge, if # * both have outgroups but no ingroups # * either have ingroups but no outgroups. # * one has outgroups and ingroups don't overlap merge = False if (oa and ob) and not (ia or ib): merge = True elif (ia or ib) and not (oa or ob): merge = True elif ((oa and not ob) or (ob and not oa)) and not overlap: merge = True # print node_id, a, b, "oa=",oa, "ob=", ob, "ia=", ia, "ib=",ib, # "ovl=",overlap, "merge=",merge if merge: nout[node_id] = sum([nout[x] for x in node.succ]) nin[node_id] = sum([nin[x] for x in node.succ]) taxa[node_id] = taxa[a].union(taxa[b]) otus[node_id] = otus[a].union(otus[b]) else: if ia and oa and ib and ob: # write two complete subtrees nout[node_id] = 0 nin[node_id] = 0 taxa[node_id] = set() otus[node_id] = set() clusters.append(otus[a]) clusters.append(otus[b]) elif ia and oa: # write a, keep b nout[node_id] = nout[b] nin[node_id] = nin[b] taxa[node_id] = taxa[b] otus[node_id] = otus[b] clusters.append(otus[a]) elif ib and ob: # write b, keep a nout[node_id] = nout[a] nin[node_id] = nin[a] taxa[node_id] = taxa[a] otus[node_id] = otus[a] clusters.append(otus[b]) elif not(ia and ib and oa and ob): # two empty subtrees merge nout[node_id] = 0 nin[node_id] = 0 taxa[node_id] = set() otus[node_id] = set() else: tree.display() print node_id, ia, ib, oa, ob raise "sanity check failed: unknown case." TreeTools.TreeDFS(tree, tree.root, post_function=update_groups) # special treatment of root if otus[tree.root]: if clusters: # add to previous cluster if only outgroups or ingroups # in root node oa = nout[tree.root] > 0 ia = nin[tree.root] > 0 if (oa and not ia) or (ia and not oa): clusters[-1] = clusters[-1].union(otus[tree.root]) else: clusters.append(otus[tree.root]) else: clusters.append(otus[tree.root]) return clusters