Beispiel #1
0
    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)
Beispiel #2
0
    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
Beispiel #3
0
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