Source code for p4.supertreesupport

import sys
import csv
import random
from p4.tree import Tree
from p4.func import read
from p4.var import var
from p4.p4exceptions import P4Error
from p4.reducedstrictconsensus import Intersection, TreeBuilderFromSplits


class SuperTreeInputTrees(object):

    def __init__(self, inputTree, distributionTrees=None):
        """
        SuperTreeInputTrees is a utility to create sets of input trees. 
        The input trees are primarily to be used to evaluate super tree
        construction methods. 

        Invocation removing a fixed number of taxa from each prospective input tree:

            stit = SuperTreeInputTrees(inputTree)
            stit.writeInputTreesToFile = True
            stit.outputFile = 'myInputtrees.tre'
            stit.noTaxaToRemove = 32 
            stit.noOutputTrees = 10
            stit.generateInputTrees()


        Invocation using built in distribution gathered from real world super tree cases::

            stit = SuperTreeInputTrees(inputTree)
            stit.writeInputTreesToFile = True
            stit.outputFile = 'myInputtrees.tre'
            stit.useTaxonDistribution = True
            stit.generateInputTrees()

        The user can generate a distribution of their own by supplying a list of p4 trees or a tree file. 
        The order of the trees is important, supertree and then all other trees. This goes for both list and 
        file. Like so::

            stit = SuperTreeInputTrees(inputTree, distributionTrees='myTreefile.nex')
            stit.writeInputTreesToFile = True
            stit.outputFile = 'myInputtrees.tre'
            stit.useTaxonDistribution = True
            stit.generateInputTrees()

        Placeholders which allow access to data after completed computations::

            stit.outputTrees 
            stit.dist

        """

        self.writeInputTreesToFile = False
        self.outputFile = 'inputtrees.tre'

        # Set to False if you want to have a set number of taxa in the output
        # trees
        self.useTaxonDistribution = False
        # Only meaningful if setting useTaxonDistribution = False
        self.noTaxaToRemove = 32
        self.noOutputTrees = 10

        gm = ['SuperTreeInputTrees()']

        if isinstance(inputTree, Tree):
            self.inputTree = inputTree            # not a list.
        elif isinstance(inputTree, str):
            var.trees = []
            read(inputTree)
            if len(var.trees) > 1:
                gm.append('Sorry, supply only one tree as supertree')
                raise P4Error(gm)
            # this was originally a list, ie [var.trees.pop()]
            self.inputTree = var.trees.pop()
        else:
            gm.append("Input tree was neither a p4 Tree nor a valid filename")
            gm.append("Got %s" % inputTree)
            raise P4Error(gm)

        if not self.inputTree._taxNames:
            self.inputTree._setTaxNamesFromLeaves()

        self.outputTrees = []

        self.normalizedDist = []

        # Distributions gathered from real world supertree input
        # The dists are first a list of input tree taxon set sizes and the supertree taxon set size
        # Using this data we can normalize the dists to fit the size of trees
        # we want

        # BunnyRSVNormal set from Wilkinson et al 2005, Syst Biol 54:823
#        self.dist = [[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 13, 13, 14, 14, 15, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 22, 22, 23, 24, 25, 25, 25, 25, 25, 25, 26, 27, 28, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 37, 38, 38, 40, 40, 41, 47, 51, 51, 52, 52, 52, 68, 70, 78, 78, 79, 80, 80], 80]

        # CanidaeRVS set from Wilkinson et al 2005, Syst Biol 54:823
        #self.dist = [[3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 11, 12, 16, 16, 20, 23, 24, 30, 30, 33, 34, 34, 34, 34, 34], 34]

        # CarnivoraRVS set from Wilkinson et al 2005, Syst Biol 54:823
        #self.dist = [[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12], 12]

        # DavideDinoMRP set from Wilkinson et al 2005, Syst Biol 54:823
        #self.dist = [[4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 17, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 20, 20, 20, 22, 23, 23, 24, 24, 25, 26, 27, 27, 28, 28, 29, 29, 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 33, 33, 33, 33, 36, 37, 37, 38, 38, 39, 42, 45, 47, 48, 50, 53, 53, 66, 70, 71, 74, 74, 75, 75, 76, 78, 78, 80, 86, 86, 92, 94, 96, 100, 101, 102, 102, 103, 105, 110, 111, 111, 139, 148, 149, 153, 173, 199, 204, 217, 240, 269, 270, 271, 272, 272, 273, 273, 273, 273, 274, 275], 277]

        # FelidaeRVS set from Wilkinson et al 2005, Syst Biol 54:823
        self.dist = [[3, 3, 3, 3, 3, 4, 4, 4, 5, 6, 6, 6, 7, 7, 7, 7, 9, 9, 10, 10, 14,
                      16, 17, 24, 25, 28, 29, 29, 30, 30, 32, 34, 36, 36, 36, 36, 36, 36, 36, 36], 36]

        # KennedyPageData set from Wilkinson et al 2005, Syst Biol 54:823
        #self.dist = [[14, 16, 17, 20, 30, 30, 90], 122]

        # ViverridaeRVS set from Wilkinson et al 2005, Syst Biol 54:823
        #self.dist = [[4, 5, 10, 16, 19, 33, 34, 34, 34], 34]

        if distributionTrees:
            self.useTaxonDistribution = True
            if isinstance(distributionTrees, list):
                for t in distributionTrees:
                    if not isinstance(t, Tree):
                        gm.append(
                            "Input trees should be a list of p4 Tree objects. Got %s" % t)
                        raise P4Error(gm)
                superTree = distributionTrees.pop(0)
                inputTrees = distributionTrees
            elif isinstance(distributionTrees, list):
                var.trees = []
                read(distributionTrees)
                if len(var.trees) < 1:
                    gm.append(
                        'Sorry, at least one tree must be supplied as input tree')
                    raise P4Error(gm)
                superTree = var.trees.pop(0)
                inputTrees = var.trees
            self._generateDistribution(superTree, inputTrees)

    def _generateDistribution(self, superTree, inputTrees):

        if not superTree._taxNames:
            superTree._setTaxNamesFromLeaves()

        distribution = []
        for tree in inputTrees:
            if not tree._taxNames:
                tree._setTaxNamesFromLeaves()
            distribution.append(len(tree.taxNames))

        distribution.sort()

        self.dist = [distribution, len(superTree.taxNames)]

#        print [distribution,len(superTree.taxNames)]

    # Prepares the dist by normalizing and changing it to reflect instead the no of taxa to remove.
    # This change is done simply to ease the other calculations
    def _prepareDistribution(self, noOfTaxaInSuperTree):
        #    print 'Supertree taxa:       ',noOfTaxaInSuperTree
        #    print 'Dist supertree taxa:  ',dist[1]
        normalizationIndex = self.dist[1] / float(noOfTaxaInSuperTree)
        #    print 'Normalization index:  ',normalizationIndex
        #    print 'Dist supertree taxa N:',dist[1]/normalizationIndex
        for size in self.dist[0]:
            normalized = size / normalizationIndex
            if int(noOfTaxaInSuperTree - normalized) > 2:
                # print '%s, %s ' % (size, int(noOfTaxaInSuperTree-normalized))
                self.normalizedDist.append(
                    int(noOfTaxaInSuperTree - normalized))

    # Determines how we deal with the no of output trees
    # In the simple case this is a set number, but we can also use a
    # distribution
    def _noOutputTrees(self):
        return self.noOutputTrees

    # Determines how we deal with the no of taxa to remove
    # In the simple case this is a set number, but we can also use a
    # distribution
    def _noTaxaToRemove(self):
        if self.useTaxonDistribution:
            return random.choice(self.normalizedDist)
        else:
            return self.noTaxaToRemove

    # Randomizes a taxon for removal, does so without regard for the shape of
    # the tree
    def _getTaxaToRemove(self, nodes):
        node = nodes[random.randint(0, len(nodes) - 1)]
        if node.isLeaf:
            return node
        else:
            while not node.isLeaf:
                node = nodes[random.randint(0, len(nodes) - 1)]
        return node

    def generateInputTrees(self):
        gm = ['SuperTreeInputTrees.generateInputTrees()']
    # Check if input values are valid
        if not self.useTaxonDistribution:
            if self.noTaxaToRemove >= len(self.inputTree.taxNames) - 2:
                gm.append(
                    'The number of taxa to remove would leave less than 3 taxa in the tree, quite uninformative')
                raise P4Error(gm)

    # Prepare the distribution by normalizing it to the size of the input tree
        if self.useTaxonDistribution:
            self._prepareDistribution(len(self.inputTree.taxNames))

    # Creates the output trees and removes taxa from them accoring to the settings
    # Checks if the output tree has the correct number of taxa as a precation
        for i in range(self._noOutputTrees()):
            tree = self.inputTree.dupe()
            tree.name = 'inputtree' + str(i + 1)
            taxa2Remove = self._noTaxaToRemove()
            for j in range(taxa2Remove):
                tree.removeNode(self._getTaxaToRemove(tree.nodes))

            tree._setTaxNamesFromLeaves()
            if len(tree.taxNames) == len(self.inputTree.taxNames) - taxa2Remove:
                self.outputTrees.append(tree)
            else:
                print('Bugger, the correct number of taxa were not removed, taxa remaining: ', len(tree.taxNames))
                print('Expected: ', len(self.inputTree.taxNames) - taxa2Remove)

        # Writes the trees to file
        if self.writeInputTreesToFile:
            for tree in self.outputTrees:
                #    tree.draw()
                tree. writeNewick(fName=self.outputFile, withTranslation=0,
                                  translationHash=None, doMcmcCommandComments=0, toString=False, append=True)


[docs]class SuperTreeSupport(object): """Supertree support measures Super tree support can be used to calculate a number of support measures for a set of trees and a supertree. The measures can be at split level and placed on the supertree for image production or at tree level with a number of summary measures. The support of the input trees for a supertree is measured by counting the number of input trees that support(S), conflict(Q), permits(P) or are relevant(R) with the splits in the supertree. Supply a supertree and the input trees used to create it. Filenames or trees will do. A single supertree and a list of input trees. For example:: sts = SuperTreeSupport('supertree.nex', 'input.nex') or:: read('input.nex') inputTrees = var.trees sts = SuperTreeSupport('supertree.nex', inputTrees) sts.doSaveDecoratedTree = True sts.decoratedFilename='mytree.nex' sts.doSaveIndexTree=False sts.indexFilename='mytreeIndex.nex' sts.csvFilename='mytreeIndex.csv' sts.doDrawTree=True sts.verbose=1 sts.superTreeSupport() After completing the analysis there are a number of placeholders that allows access to the resulting data:: sts.decoratedSuperTree sts.indexSuperTree sts.csvList sts.T, no. of input trees; sts.L, no. of leaves; sts.C, coverage (average proportion of leaves in the input tree); sts.mean, mean taxon overlap among input trees sts.median, median taxon overlap among input trees sts.SC, number of supertree clades; sts.U, no. of unsupported supertree clades; sts.UC, no. of unsupported supertree clades that conflict with at least one input tree; sts.UCC, no. of unsupported clades conflicting with all relevant input trees; sts.QS, average qualitative support for supertree clades. Figures in parentheses are ranges. sts.S, average support sts.P, average permitted sts.Q, average conflict sts.R, average relevance sts.V, average V for supertree clades V = (s minus q)/(s + q) sts.VV, V+ = (s - q + p)/(s + q + p) sts.Vv, V minus = (s - q - p)/(s + q + p) sts.wV, wV = (ws minus q)/(ws + q) sts.wVV, wVV = (ws minus q +wp)/(ws + q + wp) sts.wVv, wVv = (ws minus q minus wp)/(ws + q + wp) These can be used for further analysis. Examples of support, conflict, relevance and permission: **Support**:: supertree: +--------1:A +--------5:100 | +--------2:B 0 |--------3:C | +--------4:D input tree: +--------1:A +--------5:100 | +--------2:B 0 |--------3:C **Conflict**:: supertree: +--------1:A +--------5:100 | +--------2:B 0 |--------3:C | +--------4:D input tree: +--------1:A +--------5:100 | +--------2:C 0 |--------3:B | +--------4:D **Relevance**, i.e an input tree split that is irrelevant to the supertree split:: supertree: +--------1:A +--------7:50 | +--------2:B | |--------3:C 0 |--------4:D | |--------5:E | +--------6:F input tree: +--------1:E +--------7:50 | +--------2:F | |--------3:C 0 |--------4:D | |--------5:A **Permission**, i.e. an input trees split that permits the supertree split but does not support it:: supertree: +--------1:A +--------7:50 | +--------2:B | |--------3:C 0 |--------4:D | |--------5:E | +--------6:F input tree: +--------1:A +--------7:50 | +--------2:B | | 0 |--------3:C | |--------4:D | |--------5:E The analysed supertree can be decorated in three different ways. I. V = (s minus q)/(s + q) in standard mode, i.e. values between 0 - 100. II. V = (s minus q)/(s + q) in supertree mode, i.e. values between -1 - 1 III. With indices that can be correlated to a csv file holding the support values. This allows for further analysis of the support values and post mapping to the tree. """ def __init__(self, supertree, inputTrees): # There are two ways of decorating the supertree with the support values. # Standard conforms to the consensus tree tradition, i.e. values are presented between # 0 to 100 percent. Non standard adhears to the few supertree papers regarding support values # i.e -1 to 1. self.doStandardDecoration = True # The decorated supertree can be saved to file self.doSaveDecoratedTree = False self.decoratedFilename = 'superTreeSupport.nex' # There is a option to save a supertree decorated with index values instead of support values. # This can then be used with a csv file containing the support values for each index. # Further analysis of the support values can be performed and then matched to the indecies in the # decorated supertree self.doSaveIndexTree = False self.indexFilename = 'supertreeIndex.nex' self.csvFilename = 'supertreeIndex.csv' # Draws the decorated supertree to screen self.doDrawTree = False # Produces output to screen self.verbose = 1 # Placeholders that allows access to the data after completing # calculations self.decoratedSuperTree = None self.indexSuperTree = None self.csvList = None # Keeps track of splits for producing output self.indexIntersections = [] self.csvValues = [] self.intersections = [] # Let t be the number of input trees, # s the number of input trees supporting a supertree clade, # r the number of input trees that are irrelevant to the supertree clade, # q the number of input trees that conflict with the supertree clade, # p the number of input trees that permit the supertree clade, # so that t = p + q + r + s. self.T = 0 # no. of input trees; self.L = 0 # no. of leaves; # coverage (average proportion of leaves in the input tree); self.C = 0.0 self.SC = 0 # number of supertree clades; self.U = 0 # no. of unsupported supertree clades; # no. of unsupported supertree clades that conflict with at least one # input tree; self.UC = 0 # no. of unsupported clades conflicting with all relevant input trees; self.UCC = 0 # average qualitative support for supertree clades. Figures in # parentheses are ranges. self.QS = 0.0 self.S = 0.0 # average support self.P = 0.0 # average permitted self.Q = 0.0 # average conflict self.R = 0.0 # average relevance self.wS = 0.0 # average weighted support self.wP = 0.0 # average weighted permitance self.V = 0.0 # average V for supertree cladesV = (s minus q)/(s + q) self.VV = 0.0 # V+ = (s minus q +p)/(s + q + p) self.Vv = 0.0 # V minus = (s minus q minus p)/(s + q + p) self.wV = 0.0 # wV = (ws minus q)/(ws + q) self.wVV = 0.0 # wVV = (ws minus q +wp)/(ws + q + wp) self.wVv = 0.0 # wVv = (ws minus q minus wp)/(ws + q + wp) gm = ['SuperTreeSupport()'] var.warnReadNoFile = False if isinstance(inputTrees, list): for t in inputTrees: if not isinstance(t, Tree): gm.append( "Input trees should be a list of p4 Tree objects. Got %s" % t) raise P4Error(gm) self.inputTrees = inputTrees elif isinstance(inputTrees, str): var.trees = [] read(inputTrees) if len(var.trees) < 1: gm.append( 'Sorry, at least one tree must be supplied as input tree') raise P4Error(gm) self.inputTrees = var.trees else: gm.append( "Input trees are neither a list of p4 Tree objects nor a valid filename.") raise P4Error(gm) if isinstance(supertree, Tree): self.supertree = supertree # not a list. elif isinstance(supertree, str): var.trees = [] read(supertree) if len(var.trees) > 1: gm.append('Sorry, supply only one tree as supertree') raise P4Error(gm) # this was originally a list, ie [var.trees.pop()] self.supertree = var.trees.pop() else: gm.append("Supertree was neither a p4 Tree nor a valid filename") gm.append("Got %s" % supertree) raise P4Error(gm) for tree in self.inputTrees: if not tree._taxNames: tree._setTaxNamesFromLeaves() # Mean and median overlap of the input trees overlapList = [] meanOverlap = 0.0 index = 0 for i in range(0, len(self.inputTrees) - 1): for j in range(i + 1, len(self.inputTrees)): overlap = len(set(self.inputTrees[i].taxNames).intersection( set(self.inputTrees[j].taxNames))) overlapList.append(overlap) meanOverlap += overlap index += 1 if index == 0: self.mean = 0 self.median = 0 else: self.mean = meanOverlap / index overlapList.sort() self.median = overlapList[len(overlapList) / 2] commonLeafSet = CommonLeafSet() self.splits = commonLeafSet.updateTreesToCommonLeafSet( [self.inputTrees, [self.supertree]]) self.bitkeys = commonLeafSet.getCommonBitkeys() self.taxnames = commonLeafSet.getCommonTaxNames() self.taxa2Bitkey = commonLeafSet.getCommonTaxa2Bitkey()
[docs] def superTreeSupport(self): """ Perform analyses on a number of input trees and the resulting supertree. """ gm = ['superTreeSupport()'] allOnes = 2 ** (len(self.bitkeys)) - 1 inputSplits = self.splits[0] self.T = len(inputSplits) self.L = len(self.bitkeys) # if 'ROOT' in self.taxnames: # self.L -= 1 # if 'mrp_outgroup' in self.taxnames: # self.L -= 1 coverage = 0.0 for splits in inputSplits: t = self.L - self.popcount(splits[0][1], self.bitkeys) if 'ROOT' in self.taxnames and splits[0][1] & self.taxa2Bitkey['ROOT']: t += 1 coverage += t self.C = (coverage / self.T) / self.L # print "self.splits = %s" % self.splits if self.splits[1]: supertreeSplits = self.splits[1][0] else: supertreeSplits = [] self.SC = len(supertreeSplits) if self.verbose > 1: print('Identifying supporting, conflicting and neutral input trees,') sys.stdout.flush() """ A dictionary supertreeDict = {} will keep track of the supertree splits and their support The indeces from the supertreeSplits list will be used to keep track of the splits i.e. supertreeSplits[1] info will be in supertreeDict[1] Each entry in the dict will be a list formated like so [input trees hard support, input trees soft support(entailed), input trees neutral, input trees conflict] """ def isPowerOf2(number): return (not(number & (number - 1))) supertreeDict = {} for i in range(self.SC): # Used to store each supertree clades support values # [S, P, R, Q, WS, WP, V, V+, V-, wV, wV+,wV-] supertreeDict[i] = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] supertreeSplitDict = {} for j in range(self.SC): supertreeSplitDict[j] = -1 for splitSet in inputSplits: supportedSupertreeSplits = [] permittedSupertreeSplits = [] taxSplit = splitSet[0][1] ^ allOnes allSuperTreeSplitsResovled = False for split in splitSet: if allSuperTreeSplitsResovled: break allSuperTreeSplitsResovled = True for i in range(self.SC): if supertreeSplitDict[i] < 0: allSuperTreeSplitsResovled = False workingSplit = ( supertreeSplits[i][0] & splitSet[0][1]) ^ supertreeSplits[i][0] if not self.popcountLimit(taxSplit & workingSplit, 2) or not self.popcountLimit(taxSplit ^ workingSplit, 2): supertreeSplitDict[i] = 2 else: ones = split[0] & workingSplit one1 = 0 if ones > 0: if not isPowerOf2(ones): one1 = 2 else: one1 = 1 # print 'one1: ', one1 zeroOnes = (split[0] ^ workingSplit) & workingSplit zero1 = 0 if zeroOnes > 0: if not isPowerOf2(zeroOnes): zero1 = 2 else: zero1 = 1 # print 'zero1: ', zero1 oneZeroes = (split[0] ^ workingSplit) & split[0] one0 = 0 if oneZeroes > 0: if not isPowerOf2(oneZeroes): one0 = 2 else: one0 = 1 # print 'one0: ', one0 zeroZeroes = ( (workingSplit ^ allOnes) & (split[0] ^ allOnes)) ^ split[1] zero0 = 0 if zeroZeroes > 0: if not isPowerOf2(zeroZeroes): zero0 = 2 else: zero0 = 1 # print 'zero0: ', zero0 if one1 and zero1 and one0 and zero0: supertreeSplitDict[i] = 3 if one1 and zero0 and (not zero1 and not one0): #self.printSplitList([split, supertreeSplits[i]], self.bitkeys) supportedSupertreeSplits.append(i) supertreeSplitDict[i] = 0 if zero1 and one0 and (not one1 and not zero0): #self.printSplitList([split, supertreeSplits[i]], self.bitkeys) supportedSupertreeSplits.append(i) supertreeSplitDict[i] = 0 for i in range(self.SC): if supertreeSplitDict[i] < 0: supertreeDict[i][1] = supertreeDict[i][1] + 1 permittedSupertreeSplits.append(i) supertreeDict[i][supertreeSplitDict[i]] = supertreeDict[ i][supertreeSplitDict[i]] + 1 supertreeSplitDict[i] = -1 if len(permittedSupertreeSplits) > 0: wp = 1.0 / len(permittedSupertreeSplits) for index in permittedSupertreeSplits: supertreeDict[index][5] = supertreeDict[index][5] + wp if len(supportedSupertreeSplits) > 0: ws = 1.0 / len(supportedSupertreeSplits) for index in supportedSupertreeSplits: supertreeDict[index][4] = supertreeDict[index][4] + ws if self.verbose > 1: print('done.') """ How many input trees containing the taxa in the supertree split, conflict, agree, neutral. """ if self.verbose > 1: print('Creating statistics and supertree with support values,') self._calcSupport(supertreeDict) if self.doSaveIndexTree: self.saveIndexTree(supertreeSplits, supertreeDict) if self.doDrawTree or self.doSaveDecoratedTree: self.buildDecoratedTree(supertreeSplits, supertreeDict) if self.doDrawTree: self.decoratedSuperTree.draw() print('') if self.doSaveDecoratedTree: self.decoratedSuperTree.writeNexus(self.decoratedFilename) if self.verbose == 1: self.printReducedOutput() elif self.verbose > 1: self.printReducedOutput(printInstructions=True)
[docs] def buildDecoratedTree(self, supertreeSplits, supertreeDict): for key, value in supertreeDict.items(): inter = Intersection( supertreeSplits[key][0], supertreeSplits[key][1], 0, 0) name = '' if self.doStandardDecoration: name = str(int(round(100.0 * (1.0 + value[9]) / 2.0))) else: name = str(value[9]) inter.name = name self.intersections.append(inter) treeBuilderFromSplits = TreeBuilderFromSplits( self.bitkeys, self.taxnames) self.decoratedSuperTree = treeBuilderFromSplits.buildTreeFromInformativeList( self.intersections, treeName='decoratedSupertree')
[docs] def saveIndexTree(self, supertreeSplits, supertreeDict): for key, value in supertreeDict.items(): inter = Intersection( supertreeSplits[key][0], supertreeSplits[key][1], 0, 0) if self.doStandardDecoration: self.csvValues.append([key, int(round(100.0 * (value[0] / self.T))), int(round(100.0 * (value[1] / self.T))), int(round( 100.0 * (value[2] / self.T))), int(round(100.0 * (value[3] / self.T))), int(round( 100.0 * (value[4] / self.T))), int(round(100.0 * (value[5] / self.T))), value[6], value[7], value[8], value[9], value[10], value[11]]) else: self.csvValues.append([key, value[0] + value[1], value[0], value[1], value[2], value[ 3], value[4], value[5], value[6], value[7], value[8], value[9], value[10], value[11]]) inter.name = str(key) self.indexIntersections.append(inter) treeBuilderFromSplits = TreeBuilderFromSplits( self.bitkeys, self.taxnames) self.indexSuperTree = treeBuilderFromSplits.buildTreeFromInformativeList( self.indexIntersections, treeName='indexSupertree') self.indexSuperTree.writeNexus(self.indexFilename) writer = csv.writer(open(self.csvFilename, "wb")) writer.writerows(self.csvValues)
def _calcSupport(self, supertreeDict): for value in supertreeDict.values(): S = value[0] P = value[1] Q = value[3] R = value[2] # print 'S+P+Q+R: %s, %s, %s, %s' % (S, P, Q, R) wS = value[4] wP = value[5] self.S += S self.P += P self.Q += Q self.R += R self.wS += wS self.wP += wP if S < 1: self.U += 1 if S < 1 and Q > 0: self.UC += 1 if S < 1 and Q > 0 and Q == self.T - R: self.UCC += 1 if S + Q > 0: value[6] = (S - Q) / (S + Q) self.V += value[6] if wS + Q > 0: value[9] = (wS - Q) / (wS + Q) self.wV += value[9] if S + Q + P > 0: value[7] = (S - Q + P) / (S + Q + P) self.VV += value[7] value[8] = (S - Q - P) / (S + Q + P) self.Vv += value[8] if wS + Q + wP > 0: value[10] = (wS - Q + wP) / (wS + Q + wP) self.wVV += value[10] value[11] = (wS - Q - wP) / (wS + Q + wP) self.wVv += value[11] if 0: print("self.SC =", self.SC) print("self.S =", self.S) print("self.P =", self.P) print("self.Q =", self.Q) print("self.R =", self.R) print("self.V =", self.V) print("self.VV =", self.VV) print("self.Vv =", self.Vv) print("self.wV =", self.wV) print("self.wVV =", self.wVV) print("self.wVv =", self.wVv) if self.SC: self.S = self.S / self.SC self.P = self.P / self.SC self.Q = self.Q / self.SC self.R = self.R / self.SC self.V = self.V / self.SC self.VV = self.VV / self.SC self.Vv = self.Vv / self.SC self.wV = self.wV / self.SC self.wVV = self.wVV / self.SC self.wVv = self.wVv / self.SC
[docs] def printReducedOutput(self, printInstructions=False): if printInstructions: print('I = no. of input trees;') print('L = no. of leaves;') print('Mean = mean taxon overlap among input trees') print('Medi = median taxon overlap among input trees') print('C = coverage (average proportion of leaves in the input tree);') print('SC = number of supertree clades;') print('U = no. of unsupported supertree clades;') print('U* = no. of unsupported supertree clades that conflict with at least one input tree;') print('U** = no. of unsupported clades conflicting with all relevant input trees;') print('V = avg of support-conflict / support+conflict;') print('V+ = avg of support-conflict+permitting / support+conflict+permitting ;') print('V- = avg of support-conflict-permitting / support+conflict+permitting ;') print('wV = avg of weighted support-conflict / weighted support+conflict;') print('wV+ = avg of weighted support-conflict+weighted permitting / weighted support+conflict+weighted permitting ;') print('wV- = avg of weighted support-conflict-weighted permitting / weighted support+conflict+weighted permitting ;') print('I L Mean Medi C SC U U* U** V V+ V- wV wV+ wV-') print(repr(self.T).ljust(6)[:5], end=' ') print(repr(self.L).ljust(6)[:5], end=' ') print(repr(self.mean).ljust(6)[:5], end=' ') print(repr(self.median).ljust(6)[:5], end=' ') print(repr(self.C).ljust(6)[:5], end=' ') print(repr(self.SC).ljust(6)[:5], end=' ') print(repr(self.U).ljust(6)[:5], end=' ') print(repr(self.UC).ljust(6)[:5], end=' ') print(repr(self.UCC).ljust(6)[:5], end=' ') print(repr(self.V).ljust(6)[:5], end=' ') print(repr(self.VV).ljust(6)[:5], end=' ') print(repr(self.Vv).ljust(6)[:5], end=' ') print(repr(self.wV).ljust(6)[:5], end=' ') print(repr(self.wVV).ljust(6)[:5], end=' ') print(repr(self.wVv).ljust(6)[:5])
[docs] def popcount(self, n, bitkeys): count = 0 for bk in bitkeys: if n < bk: return count if bk & n: count += 1 return count
[docs] def popcountLimit(self, n, limit): count = 0 for bk in self.bitkeys: if bk & n: count += 1 if n >= limit: return True return False
[docs] def printSplitList(self, list, bitkeys): for split in list: intersection = '' for bk in bitkeys: if bk & split[0]: intersection = intersection + '1' elif bk & split[1]: intersection = intersection + '?' else: intersection = intersection + '*' print('Split: %s' % (intersection)) print(' ')
class CommonLeafSet(object): def updateToCommonLeafSetWithTaxa(self, tfl, dict, bitkeys, taxnames): gm = ['updateToCommonLeafSetWithTaxa(tfl, dict, bitkeys, taxnames)'] uniqueSet = set() for i in range(tfl.nSamples): t = tfl.getTree(i) if not t._taxNames: t._setTaxNamesFromLeaves() for name in t.taxNames: uniqueSet.add(name) list = [] for name in uniqueSet: list.append(name) for name in list: if not name in taxnames: gm.append( 'Found taxa in that does not appear in the supplied taxa list: ' + name) raise P4Error(gm) for name in taxnames: if not name in list: gm.append( 'Found taxa in supplied taxa list that does not appear in the supertree: ' + name) raise P4Error(gm) self.weights = [] splits = [] for i in range(tfl.nSamples): t = tfl.getTree(i) if not t._taxNames: t._setTaxNamesFromLeaves() t.missingTaxa = 0 for name in taxnames: if not t.taxNames.count(name): t.missingTaxa = t.missingTaxa | dict[name] for n in t.iterLeavesNoRoot(): n.br.rc = dict[n.name] t._makeRCSplitKeys() weight = 1.0 if hasattr(t, "weight"): if t.weight != None: weight = t.weight elif hasattr(t, "recipWeight"): if t.recipWeight != None: weight = 1.0 / int(t.recipWeight) self.weights.append(weight) t.splits = [] for n in t.iterInternalsNoRoot(): for m in n.br.rcList: t.splits.append([m, t.missingTaxa]) splits.append(t.splits) return splits def updateTreesToCommonLeafSet(self, trees): """ Creates common leafset Requires input to be a list like so: [[inputtrees][supertree]] """ uniqueSet = set() sampler = float(len(trees)) / 10 index = 0.0 for treeList in trees: for t in treeList: if t.root.getNChildren() <= 2: t.addSibLeaf(t.root, "ROOT") index += 0.5 if not t._taxNames: t._setTaxNamesFromLeaves() for name in t.taxNames: uniqueSet.add(name) if index % sampler == 0: print('%s trees processed ' % (int(index))) sys.stdout.flush() self.list = [] for name in uniqueSet: self.list.append(name) self.list.sort() self.dict = {} self.bitkeys = [] for i in range(len(self.list)): self.bitkeys.append(1 << i) self.dict[self.list[i]] = 1 << i self.weights = [] self.treeNames = [] tflsSplits = [] for treeList in trees: splits = [] for t in treeList: index += 0.5 self.treeNames.append(t.name) if not t._taxNames: t._setTaxNamesFromLeaves() t.missingTaxa = 0 for name in self.list: if not t.taxNames.count(name): t.missingTaxa = t.missingTaxa | self.dict[name] for n in t.iterLeavesNoRoot(): n.br.rc = self.dict[n.name] t._makeRCSplitKeys() weight = 1.0 if hasattr(t, "weight"): if t.weight != None: weight = t.weight elif hasattr(t, "recipWeight"): if t.recipWeight != None: weight = 1.0 / int(t.recipWeight) self.weights.append(weight) t.splits = [] for n in t.iterInternalsNoRoot(): for m in n.br.rcList: t.splits.append([m, t.missingTaxa]) if len(t.splits) > 0: # for split in t.splits: # intersection = '' # for bk in self.bitkeys: # if bk & split[0]: # intersection = intersection + '1' # elif bk & split[1]: # intersection = intersection + '?' # else: # intersection = intersection + '*' # print 'Split: %s' % (intersection) # print '' splits.append(t.splits) if index % sampler == 0: print('%s trees processed ' % (int(index))) sys.stdout.flush() tflsSplits.append(splits) return tflsSplits def updateToCommonLeafSet(self, tfls): uniqueSet = set() trees = 0 for tfl in tfls: trees += tfl.nSamples sampler = float(trees) / 10 index = 0.0 for tfl in tfls: for i in range(tfl.nSamples): index += 0.5 t = tfl.getTree(i) if not t._taxNames: t._setTaxNamesFromLeaves() for name in t.taxNames: uniqueSet.add(name) if index % sampler == 0: print('%s trees processed ' % (int(index))) sys.stdout.flush() self.list = [] for name in uniqueSet: self.list.append(name) self.list.sort() self.dict = {} self.bitkeys = [] for i in range(len(self.list)): self.bitkeys.append(1 << i) self.dict[self.list[i]] = 1 << i self.weights = [] self.treeNames = [] tflsSplits = [] for tfl in tfls: splits = [] for i in range(tfl.nSamples): index += 0.5 t = tfl.getTree(i) self.treeNames.append(t.name) if not t._taxNames: t._setTaxNamesFromLeaves() t.missingTaxa = 0 for name in self.list: if not t.taxNames.count(name): t.missingTaxa = t.missingTaxa | self.dict[name] for n in t.iterLeavesNoRoot(): n.br.rc = self.dict[n.name] t._makeRCSplitKeys() weight = 1.0 if hasattr(t, "weight"): if t.weight != None: weight = t.weight elif hasattr(t, "recipWeight"): if t.recipWeight != None: weight = 1.0 / int(t.recipWeight) self.weights.append(weight) t.splits = [] for n in t.iterInternalsNoRoot(): for m in n.br.rcList: t.splits.append([m, t.missingTaxa]) splits.append(t.splits) if index % sampler == 0: print('%s trees processed ' % (int(index))) sys.stdout.flush() tflsSplits.append(splits) return tflsSplits def getCommonTaxa2Bitkey(self): return self.dict def getCommonTaxNames(self): return self.list def getCommonBitkeys(self): return self.bitkeys def getWeights(self): return self.weights def getTreeNames(self): return self.treeNames