PKC?Iphyltr/__init__.pyPKPJ9 0EEphyltr/utils/cladeprob.pyfrom __future__ import division import math class CladeProbabilities: def __init__(self): self.tree_count = 0 self.clade_counts = {} self.clade_ages = {} self.clade_attributes = {} self.caches ={} def add_tree(self, tree): """Record clade counts for the given tree.""" cache = tree.get_cached_content() self.tree_count += 1 for subtree in tree.traverse(): leaves = [leaf.name for leaf in cache[subtree]] if len(leaves) == 1: continue clade = ",".join(sorted(leaves)) self.clade_counts[clade] = self.clade_counts.get(clade,0) + 1 leaf, age = subtree.get_farthest_leaf() if clade in self.clade_ages: self.clade_ages[clade].append(age) else: self.clade_ages[clade] = [age] extra_features = [f for f in subtree.features if f not in ("name","dist","support")] for f in extra_features: value = getattr(subtree, f) try: value = float(value) if f not in self.clade_attributes: self.clade_attributes[f] = {} if clade in self.clade_attributes[f]: self.clade_attributes[f][clade].append(value) else: self.clade_attributes[f][clade] = [value] except ValueError: continue self.caches[tree] = cache def compute_probabilities(self): """Populate the self.clade_probs dictionary with probability values, based on the current clade and tree counts.""" self.clade_probs = dict((c, self.clade_counts[c] / self.tree_count) for c in self.clade_counts) def get_tree_prob(self, t): """Compute the probability of a tree, as the product of the probabilities of all of its constituent clades according to the current self.clade_probs values.""" cache = self.caches.get(t,t.get_cached_content()) prob = 0 for node in t.traverse(): if node == t: continue leaves = [leaf.name for leaf in cache[node]] if len(leaves) == 1: continue clade = ",".join(sorted(leaves)) prob += math.log(self.clade_probs[clade]) return prob def annotate_tree(self, tree): """Set the support attribute of the nodes in tree using the current self.clade_probs values.""" cache = self.caches.get(tree,tree.get_cached_content()) for node in tree.traverse(): leaves = [leaf.name for leaf in cache[node]] if len(leaves) == 1: continue clade = ",".join(sorted(leaves)) node.support = self.clade_probs[clade] def save_clade_report(self, filename, threshold=0.0, age=False): clade_probs = [(self.clade_probs[c], c) for c in self.clade_probs] if threshold < 1.0: clade_probs = [(p, c) for (p, c) in clade_probs if p >= threshold] # Sort by clade string, ignoring case... clade_probs.sort(key=lambda x:x[1].lower()) # ...then by clade probability # (this results in a list sorted by probability and then name) clade_probs.sort(key=lambda x:x[0],reverse=True) fp = open(filename, "w") for p, c in clade_probs: if age: ages = self.clade_ages[c] mean = sum(ages)/len(ages) ages.sort() lower, median, upper = [ages[int(x*len(ages))] for x in 0.05,0.5,0.95] line = "%.4f, %.2f (%.2f-%.2f) [%s]\n" % (p, mean, lower, upper, c) else: line = "%.4f, [%s]\n" % (p, c) fp.write(line) fp.close() PKI9phyltr/utils/treestream_io.pyimport dendropy def read_tree(string): t = dendropy.Tree.get_from_string(line,schema="newick") def write_tree(t): print t.as_string(schema="newick", suppress_rooting=True,suppress_annotations=False).strip() PKC?I@]]phyltr/utils/phyoptparse.pyfrom optparse import OptionParser as StdOptionParser import sys class OptionParser(StdOptionParser): def __init__(self, help_msg, *args, **kwargs): kwargs["add_help_option"] = False StdOptionParser.__init__(self, *args, **kwargs) self.help_msg = help_msg self.add_option('-h', '--help', action="store_true", dest="help", default=False) def parse_args(self, *args, **kwargs): options, files = StdOptionParser.parse_args(self, *args, **kwargs) if options.help: print self.help_msg sys.exit(0) return options, files PKC?Iphyltr/utils/__init__.pyPKPJ(Jphyltr/commands/consensus.py"""Usage: phyltr consensus [] [] Produce a majority rules consensus tree for the tree stream. OPTIONS: -f, --frequency Minimum clade frequency to include in the consensus tree (default 0.t) files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse import phyltr.utils.cladeprob def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-f', '--frequency', type="float",dest="frequency", default=0.5, help="Minimum clade support to include in tree.") options, files = parser.parse_args() # Read trees and compute clade probabilities cp = phyltr.utils.cladeprob.CladeProbabilities() for line in fileinput.input(files): t = ete2.Tree(line) cp.add_tree(t) cp.compute_probabilities() # Build consensus tree t = build_consensus_tree(cp, options.frequency) # Output print t.write(features=[]) # Done return 0 def build_consensus_tree(cp, threshold): # Build a list of all clades in the treestream with frequency above the # requested threshold, sorted first by size and then by frequency. Do not # include the trivial clade of all leaves. clades = [] for clade, p in cp.clade_probs.items(): if p >= threshold: clade = clade.split(",") clades.append((len(clade), p, set(clade))) clades.sort() junk, trash, all_leaves = clades.pop() clades.reverse() # Start out with a tree in which all leaves are joined in one big polytomy t = ete2.Tree() for l in all_leaves: t.add_child(name=l) # Now recursively resolve the polytomy by greedily grouping clades t = recursive_builder(t, clades) cache = t.get_cached_content() # Add age annotations for clade in t.traverse("postorder"): if clade.is_leaf(): continue clade_key = ",".join(sorted([l.name for l in cache[clade]])) ages = cp.clade_ages[clade_key] mean = sum(ages)/len(ages) for c in clade.get_children(): leaf, age = c.get_farthest_leaf() c.dist = mean - age ages.sort() lower, median, upper = [ages[int(x*len(ages))] for x in 0.05,0.5,0.95] clade.add_feature("age_mean", mean) clade.add_feature("age_median", median) clade.add_feature("age_HPD", "{%f-%f}" % (lower,upper)) for f in cp.clade_attributes: values = cp.clade_attributes[f][clade_key] mean = sum(values)/len(values) values.sort() lower, median, upper = [values[int(x*len(values))] for x in 0.025,0.5,0.975] clade.add_feature("%s_mean" % f, mean) clade.add_feature("%s_median" % f, median) clade.add_feature("%s_HPD" % f, "{%f-%f}" % (lower,upper)) return t def recursive_builder(t, clades): # Get a list of all my children children = set([c.name for c in t.get_children()]) # For as long as it's possible... while True: matched = False # ...find the largest clade which is a subset of my children for length, p, clade in clades: if len(clade) == 1: continue if clade.issubset(children): matched = True break if not matched: break # ...remove the children in that clade and add them under a new child clades.remove((length, p, clade)) clade_nodes = set([t.get_leaves_by_name(l)[0] for l in clade]) for l in clade_nodes: t.remove_child(l) child = t.add_child() child.support = p for l in clade_nodes: child.add_child(l) # ...remove the children in the clade I just grouped from the list of # children which I still need to group children -= clade if not children: break # Resolve polytomies one level down for child in t.get_children(): recursive_builder(child, clades) return t PKPJ,phyltr/commands/dedupe.py"""Usage: phyltr dedupe [] [] Remove duplicate taxa (i.e. taxa with the same name) from each tree in the treestream. OPTIONS: files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import random import sys import ete2 import phyltr.utils.phyoptparse as optparse def run(): parser = optparse.OptionParser(__doc__) options, files = parser.parse_args() for line in fileinput.input(files): t = ete2.Tree(line) leaf_names = [l.name for l in t.get_leaves() if l.name] dupes = set([n for n in leaf_names if leaf_names.count(n) > 1]) if not dupes: print t.write(features=[],format_root_node=True) continue # Remove dupes one at a time for dupe in dupes: dupe_taxa = t.get_leaves_by_name(dupe) assert all([d.is_leaf() for d in dupe_taxa]) # First try to collapse monophyletic dupes is_mono, junk, trash = t.check_monophyly([dupe],"name") if is_mono: mrca = t.get_common_ancestor(dupe_taxa) mrca.name = dupe for child in mrca.get_children(): child.detach() # If the dupe is non-monophyletic, kill at random else: victims = random.sample(dupe_taxa,len(dupe_taxa)-1) t.prune([l for l in t.get_leaves() if l not in victims]) # for v in victims: # v.detach() print t.write(features=[],format_root_node=True) # Done return 0 PKI]5]phyltr/commands/height.py"""Usage: phyltr height [] Print the heights of each tree in a stream. OPTIONS: files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) options, files = parser.parse_args() # Read trees for line in fileinput.input(): t = ete2.Tree(line) print(t.get_farthest_leaf()[1]) return 0 PKC?IB* * phyltr/commands/uniq.py"""Usage: phyltr uniq [] [] Merge all sets of trees with identical topologies in a tree stream into single trees. The branch lengths of the merged trees are computed from those of all the trees with that topology. Mean lengths are used by default. OPTIONS: -l, --length Specifies the method used to compute branch lengths when trees with identical topologies are merged. Must be one of: "max", "mean", "median", or "min". Default is mean. files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import itertools import ete2 import phyltr.utils.cladeprob import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-l', '--lengths', action="store", dest="lengths", default="mean") options, files = parser.parse_args() # Read trees and compute clade probabilities topologies = {} for line in fileinput.input(files): t = ete2.Tree(line) # Compare this tree to all topology exemplars. If we find a match, # add it to the record and move on to the next tree. matched = False for exemplar in topologies: if t.robinson_foulds(exemplar)[0] == 0.0: matched = True topologies[exemplar].append(t) break if not matched: topologies[t] = [t] for equ_class in topologies.values(): for nodes in itertools.izip(*[t.traverse() for t in equ_class]): dists = [n.dist for n in nodes] if options.lengths == "max": dist = max(dists) elif options.lengths == "mean": dist = sum(dists) / len(dists) elif options.lengths == "median": dists.sort() l = len(dists) if l % 2 == 0: dist = 0.5*(dists[l/2]+dists[l/2-1]) else: dist = dists[l/2] elif options.lengths == "min": dist = min(dists) nodes[0].dist = dist print equ_class[0].write() # Done return 0 PKi F?P/JJphyltr/commands/delete.py"""Usage: phyltr delete taxa [] Delete a specified set of leaf nodes from a treestream. OPTIONS: taxa A comma-separated list of leaf taxon names files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import sys import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-t', '--taxa', action="store", dest="taxa") options, files = parser.parse_args() # Get set of targets if not options.taxa: targets = [] else: targets = set(options.taxa.split(",")) first = True for line in fileinput.input(files): t = ete2.Tree(line) if first: leaves = [l.name for l in t.get_leaves()] survivors = set(leaves) - targets first = False t.prune(survivors) print t.write() # Done return 0 PKIaoophyltr/commands/support.py"""Usage: phyltr support [] [] Annotate a treestream with clade support probabilities, and optionally save clade support information to a file OPTIONS: -s, --sort Reorder tree stream to print trees in order from highest to lowest product of clade credibilities. -o, --output Filename to save a clade credibility report to -f, --frequency Minimum clade frequency to include in output (default 0.0, i.e. all clades are included) files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.cladeprob import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-a', '--age', action="store_true", dest="age", default=False, help="Include age information in report.") parser.add_option('-f', '--frequency', type="float", dest="frequency", default=1.0, help='Minimum clade frequency to report.') parser.add_option("-o", "--output", action="store", dest="filename", help="save clades to FILE", metavar="FILE") parser.add_option('-s', '--sort', action="store_true", dest="sort", default=False) options, files = parser.parse_args() # Read trees and compute clade probabilities trees = [] cp = phyltr.utils.cladeprob.CladeProbabilities() for line in fileinput.input(files): t = ete2.Tree(line) trees.append(t) cp.add_tree(t) cp.compute_probabilities() # Save clade probabilities if options.filename: cp.save_clade_report(options.filename, options.frequency, options.age) # Annotate trees for t in trees: cp.annotate_tree(t) # Sort if options.sort: trees = [(cp.get_tree_prob(t),t) for t in trees] trees.sort() trees.reverse() trees = [t for (p,t) in trees] # Output for t in trees: print t.write() # Done return 0 PKPJBbbphyltr/commands/clades.py"""Usage: phyltr clades [] [] Produce a list showing all clades in a treestream and the proportion of trees in the stream which contain each clade. The format of the output is identical to that produced by the 'phyltr support' command when using the '-o' option, and some of the same options are available. OPTIONS: -a, --ages Whether or not to include clade age information (mean and 95% HPD interval in output) -f, --frequency Minimum clade frequency to include in output (default 0.0, i.e. all clades are included) files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse import phyltr.utils.cladeprob def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-a', '--ages', action="store_true", dest="age", default=False, help="Include age information in report.") parser.add_option('-f', '--frequency', type="float", dest="frequency", default=1.0, help='Minimum clade frequency to report.') options, files = parser.parse_args() # Read trees and compute clade probabilities cp = phyltr.utils.cladeprob.CladeProbabilities() for line in fileinput.input(files): t = ete2.Tree(line) cp.add_tree(t) cp.compute_probabilities() # Output cp.save_clade_report("/dev/stdout", options.frequency, options.age) # Done return 0 PKIWuJJphyltr/commands/pretty.py"""Usage: phyltr pretty [] [] Print an "ASCII art" representation of a treestream. OPTIONS: -c, --compress Compress highly supported clades to a single node files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-c', '--compress', action="store_true", dest="compress", default=False) options, files = parser.parse_args() # Read trees for line in fileinput.input(files): t = ete2.Tree(line) # Add support to interior nodes for node in t.traverse(): if not node.is_leaf(): node.name = "%.2f" % node.support # Collapse high probability clades if options.compress: dead_nodes = [] for node in t.traverse("preorder"): if node in dead_nodes or node.is_leaf(): continue desc = node.get_descendants() desc.append(node) if all([n.support >=0.9 for n in desc]): dead_nodes.extend(desc) node.name = "(%.2f) %s" % (n.support, "+".join(sorted([l.name for l in node.get_leaves()]))) for child in node.get_children(): child.detach() print t.get_ascii() return 0 PKC?I b@@phyltr/commands/nexus.py"""Usage: phyltr nexus [] Convert a treestream to a file in the NEXUS forma. The NEXUS output is printed to stdout, where it can be redirected to a file. OPTIONS: files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) options, files = parser.parse_args() # Read trees first = True for count, line in enumerate(fileinput.input(files),1): t = ete2.Tree(line) leaves = t.get_leaves() # If first tree, get names if first: names = sorted([l.name for l in leaves]) print_middle(names) first = False for l in leaves: if l.name in names: l.name = str(names.index(l.name)+1) # Print tree line print "TREE tree_%d = %s" % (count, t.write()) print_footer() # Done return 0 def print_header(): print "#NEXUS\n" def print_middle(names): print "Begin taxa;" print "\tDimensions ntax=%d;" % len(names) print "\t\tTaxlabels" for name in names: print "\t\t\t%s" % name print "\t\t\t;" print "End;" print "Begin trees;" print "\tTranslate" for count, name in enumerate(names,1): print "\t\t%d %s," % (count, name) print "\t\t;" def print_footer(): print "End;" PKPJ`,phyltr/commands/cat.py"""Usage: phyltr cat [] [] Extract phylogenetic trees from the specified files and print them as a treestream. The trees may contain trees formatted as a phyltr treestream or a NEXUS file. OPTIONS: -b, --burnin Percentage of trees from each file to discard as "burnin". Default is 0. -s, --subsample Frequency at which to subsample trees, i.e. "-s 10" will include only every 10th tree in the treestream. Default is 1. files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import re import sys import ete2 import phyltr.utils.phyoptparse as optparse _BEAST_ANNOTATION_REGEX = "([a-zA-Z0-9_ \-]*?):(\[&.*?\])([0-9\.]+)([Ee])?(\-)?([0-9])*" _BEAST_ANNOTATION_REGEX_2 = "([a-zA-Z0-9_ \-]*?)(\[&.*?\]):([0-9\.]+)([Ee])?(\-)?([0-9])*" regex1 = re.compile(_BEAST_ANNOTATION_REGEX) regex2 = re.compile(_BEAST_ANNOTATION_REGEX_2) def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-b', '--burnin', action="store", dest="burnin", type="int", default=0) parser.add_option('-s', '--subsample', action="store", dest="subsample", type="int", default=1) parser.add_option('--no-annotations', action="store_true", dest="no_annotations", default=False) options, files = parser.parse_args() if not files: files = ["-"] # Read files for filename in files: if filename == "-": fp = sys.stdin else: fp = open(filename, "r") tree_strings = [] firstline = True for line in fp: # Skip blank lines if not line: continue # Detect Nexus file format by checking first line if firstline: if line.strip() == "#NEXUS": isNexus = True inTranslate = False nexus_trans = {} else: isNexus = False firstline = False # Detect beginning of Nexus translate block if isNexus and "translate" in line.lower(): inTranslate = True continue # Handle Nexus translate block if isNexus and inTranslate: # Detect ending of translate block... if line.strip() == ";": inTranslate = False # ...or handle a line of translate block else: if line.strip().endswith(";"): line = line[:-1] inTranslate = False index, name = line.strip().split() if name.endswith(","): name = name[:-1] nexus_trans[index] = name # Try to find a likely tree on this line and extract it if ( ")" in line and ";" in line and line.count("(") == line.count(")") ): # Smells like a tree! start = line.index("(") end = line.rindex(";") + 1 tree_strings.append(line[start:end]) burnin = int(round((options.burnin/100.0)*len(tree_strings))) tree_strings = tree_strings[burnin::options.subsample] while tree_strings: tree_string = tree_strings.pop(0) t = get_tree(tree_string) if not t: continue if isNexus and nexus_trans: for node in t.traverse(): if node.name and node.name in nexus_trans: node.name = nexus_trans[node.name] if options.no_annotations: print t.write(format_root_node=True) else: print t.write(features=[],format_root_node=True) # Done return 0 def get_tree(tree_string): # FIXME # Make this much more elegant # Also, once a successful parse is achieved, remember the strategy and avoid brute force on subsequent trees # Do we need regex magic? if "[&" in tree_string and "&&NHX" not in tree_string: tree_string = regex1.sub(repl, tree_string) if "NHX" not in tree_string: tree_string = regex2.sub(repl, tree_string) # Try to parse tree as is try: t = ete2.Tree(tree_string) return t except (ValueError,ete2.parser.newick.NewickError): pass # Try to parse tree with internal node labels try: t = ete2.Tree(tree_string, format=1) return t except (ValueError,ete2.parser.newick.NewickError): # That didn't fix it. Give up return None def repl(m): name, annotation, dist = m.groups()[0:3] if len(m.groups()) > 3: # Exponential notation dist += "".join([str(x) for x in m.groups()[3:] if x]) dist = float(dist) if annotation: bits = annotation[2:-1].split(",") # Handle BEAST's "vector annotations" # (comma-separated elements inside {}s) # by replacing the commas with pipes # (this approach subject to change?) newbits = [] inside = False for bit in bits: if inside: newbits[-1] += "|" + bit if "}" in bit: inside = False else: newbits.append(bit) if "{" in bit: inside = True annotation = "[&&NHX:%s]" % ":".join(newbits) return "%s:%f%s" % (name, dist, annotation) PKPJx)phyltr/commands/scale.py"""Usage: phyltr scale [] [] Scale the branch lengths in a treestream by a constant factor. OPTIONS: -s, --scale The factor to scale by, expressed in floating point notation. files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-s', '--scale', type="float", default=1.0, help='Scaling factor.') options, files = parser.parse_args() # Read trees for line in fileinput.input(files): t = ete2.Tree(line) # Scale branches for node in t.traverse(): node.dist *= options.scale # Output print t.write() # Done return 0 PKPJ TVophyltr/commands/subtree.py"""Usage: phyltr subtree taxa [] [] Replace each tree with the minimal subtree containing the specified taxa. OPTIONS: taxa A comma-separated list of leaf taxa to keep in the tree files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import ete2 import fileinput import sys import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-a', '--attribute', default=None) parser.add_option('-f', '--file', dest="filename", help='Specifies a file from which to read taxa') parser.add_option('-v', '--value', default=None) options, files = parser.parse_args() if options.filename: fp = open(options.filename, "r") taxa = [t.strip() for t in fp.readlines()] elif not (options.attribute and options.value): if files: taxa = set(files[0].split(",")) files = files[1:] else: # Improper usage sys.stderr.write("Must specify a list of taxa.\n") sys.exit(1) first = True for line in fileinput.input(files): t = ete2.Tree(line) if options.attribute and options.value: mrca = list(t.get_monophyletic([options.value], options.attribute))[0] assert mrca != t t = mrca else: leaves = [l for l in t.get_leaves() if l.name in taxa] mrca = leaves[0].get_common_ancestor(leaves[1:]) t = mrca print t.write(features=[],format_root_node=True) # Done return 0 PK#_I3nnphyltr/commands/fastcat.py"""Usage: phyltr cat [] [] Extract phylogenetic trees from the specified files and print them as a treestream. The trees may contain trees formatted as a phyltr treestream or a NEXUS file. OPTIONS: -b, --burnin Percentage of trees from each file to discard as "burnin". Default is 0. -s, --subsample Frequency at which to subsample trees, i.e. "-s 10" will include only every 10th tree in the treestream. Default is 1. files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import re import sys import ete2 import phyltr.utils.phyoptparse as optparse _BEAST_ANNOTATION_REGEX = "([a-zA-Z0-9_ \-]*?):(\[&.*?\])([0-9\.]+)([Ee])?(\-)?([0-9])*" _BEAST_ANNOTATION_REGEX_2 = "([a-zA-Z0-9_ \-]*?)(\[&.*?\]):([0-9\.]+)([Ee])?(\-)?([0-9])*" regex1 = re.compile(_BEAST_ANNOTATION_REGEX) regex2 = re.compile(_BEAST_ANNOTATION_REGEX_2) def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-b', '--burnin', action="store", dest="burnin", type="int", default=0) parser.add_option('-s', '--subsample', action="store", dest="subsample", type="int", default=1) options, files = parser.parse_args() if not files: files = ["-"] # Read files for filename in files: if filename == "-": fp = sys.stdin else: fp = open(filename, "r") # Get tree count if we're doing burnin if options.burnin: N = 0 for line in fp: # Skip blank lines if not line: continue # Does this look like a tree? if ( ")" in line and ";" in line and line.count("(") == line.count(")") ): N += 1 fp.seek(0) print("Peeked at file, found %d trees" % N) burnin = int(round((options.burnin/100.0)*N)) print("Set burnin to %d" % burnin) can_be_fast = (not options.burnin) or filename != "-" tree_strings = [] firstline = True for n, line in enumerate(fp): # Skip blank lines if not line: continue # Detect Nexus file format by checking first line if firstline: if line.strip() == "#NEXUS": isNexus = True inTranslate = False nexus_trans = {} else: isNexus = False firstline = False # Detect beginning of Nexus translate block if isNexus and "translate" in line.lower(): inTranslate = True continue # Handle Nexus translate block if isNexus and inTranslate: # Detect ending of translate block... if line.strip() == ";": inTranslate = False # ...or handle a line of translate block else: if line.strip().endswith(";"): line = line[:-1] inTranslate = False index, name = line.strip().split() if name.endswith(","): name = name[:-1] nexus_trans[index] = name # Try to find a likely tree on this line and extract it if ( ")" in line and ";" in line and line.count("(") == line.count(")") ): # Smells like a tree! start = line.index("(") end = line.rindex(";") + 1 tree_string = line[start:end] if can_be_fast: if n > burnin and (n-burnin)%options.subsample == 0: # HAndle t = get_tree(tree_string) if not t: continue if isNexus and nexus_trans: for node in t.traverse(): if node.name and node.name in nexus_trans: node.name = nexus_trans[node.name] print t.write(features=[],format_root_node=True) print("TREE %d" % n) else: # Skip print("Skipping tree %d" % n) pass else: tree_strings.append(tree_string) if not can_be_fast: burnin = int(round((options.burnin/100.0)*len(tree_strings))) tree_strings = tree_strings[burnin::options.subsample] while tree_strings: tree_string = tree_strings.pop(0) t = get_tree(tree_string) if not t: continue if isNexus and nexus_trans: for node in t.traverse(): if node.name and node.name in nexus_trans: node.name = nexus_trans[node.name] print t.write(features=[],format_root_node=True) # Done return 0 def get_tree(tree_string): # FIXME # Make this much more elegant # Also, once a successful parse is achieved, remember the strategy and avoid brute force on subsequent trees # Do we need regex magic? if "[&" in tree_string and "&&NHX" not in tree_string: tree_string = regex1.sub(repl, tree_string) if "NHX" not in tree_string: tree_string = regex2.sub(repl, tree_string) # Try to parse tree as is try: t = ete2.Tree(tree_string) return t except (ValueError,ete2.parser.newick.NewickError): pass # Try to parse tree with internal node labels try: t = ete2.Tree(tree_string, format=1) return t except (ValueError,ete2.parser.newick.NewickError): # That didn't fix it. Give up return None def repl(m): name, annotation, dist = m.groups()[0:3] if len(m.groups()) > 3: # Exponential notation dist += "".join([str(x) for x in m.groups()[3:] if x]) dist = float(dist) if annotation: bits = annotation[2:-1].split(",") # Handle BEAST's "vector annotations" # (comma-separated elements inside {}s) # by replacing the commas with pipes # (this approach subject to change?) newbits = [] inside = False for bit in bits: if inside: newbits[-1] += "|" + bit if "}" in bit: inside = False else: newbits.append(bit) if "{" in bit: inside = True annotation = "[&&NHX:%s]" % ":".join(newbits) return "%s:%f%s" % (name, dist, annotation) PKPJnphyltr/commands/annotate.py"""Usage: phyltr annotate [] [] Annotate a the trees in a tree stream with information from a file OPTIONS: -f, --file File to read annotations from files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import csv import fileinput import sys import ete2 import phyltr.utils.phyoptparse as optparse def read_annotation_file(filename, key): annotations = {} fp = open(filename, "r") dialect = csv.Sniffer().sniff(fp.read(1024)) fp.seek(0) dr = csv.DictReader(fp, dialect=dialect) assert key in dr.fieldnames for row in dr: this_key = row.pop(key) annotations[this_key] = row fp.close() return annotations def annotate_tree(t, annotations): for node in t.traverse(): if node.name in annotations: for key, value in annotations[node.name].items(): node.add_feature(key, value) def extract_annotations(t, filename, tree_no=None): if filename == "-" or not filename: fp = sys.stdout else: if tree_no and tree_no > 1: fp = open(filename, "a") else: fp = open(filename, "w") features = [] for node in t.traverse(): for f in node.features: if f not in ["dist", "support", "name"] and f not in features: features.append(f) features.sort() fieldnames = ["name"] if tree_no: fieldnames.append("tree_number") fieldnames.extend(features) writer = csv.DictWriter(fp, fieldnames=fieldnames) if tree_no in (None, 1): writer.writeheader() for node in t.traverse(): # Only include the root node or nodes with names if not node.name and node.up: continue if any([hasattr(node,f) for f in features]): if not node.name: # Temporarily give the node a name node.name = "root" fix_root_name = True else: fix_root_name = False rowdict = {f:getattr(node, f, "?") for f in fieldnames} if tree_no: rowdict["tree_number"] = tree_no writer.writerow(rowdict) if fix_root_name: node.name = None if filename == "-" or not filename: pass else: fp.close() def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-e', '--extract', action="store_true", help="Extract data from annotated tree to file.") parser.add_option('-f', '--file', dest="filename", help="File to read/write annotation data from/to.") parser.add_option('-k', '--key', dest="key", help="Name of column in annotation file to match against taxon names") parser.add_option('-m', '--multiple', default=False, action="store_true") options, files = parser.parse_args() # Read annotation file if not options.extract: annotations = read_annotation_file(options.filename, options.key) # Read trees and annotate them for n, line in enumerate(fileinput.input(files)): t = ete2.Tree(line) if options.extract: if options.multiple: extract_annotations(t, options.filename, n+1) else: extract_annotations(t, options.filename) else: annotate_tree(t, annotations) if options.extract: if not options.multiple: return 0 if options.filename == "-": # Suppress output continue print t.write(features=[],format_root_node=True) # Done return 0 PKC?I6''phyltr/commands/stat.py"""Usage: phyltr stat [] Print basic properties of a tree stream, such as the number of trees and taxa. OPTIONS: files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) options, files = parser.parse_args() # Go tree_count = 0 taxa_count = 0 ultrametric = False topologically_unique_trees = [] tree_ages = [] firsttree = True # Read trees for line in fileinput.input(): t = ete2.Tree(line) cache = t.get_cached_content() tree_leaves = cache[t] tree_count += 1 if firsttree: taxa_count = len(tree_leaves) taxa_names = [l.name for l in tree_leaves] topologically_unique_trees.append(t) leave_ages = [t.get_distance(l) for l in tree_leaves] if abs(max(leave_ages) - min(leave_ages)) < max(leave_ages)/1000.0: ultrametric = True firsttree = False tree_ages.append(t.get_farthest_leaf()[1]) unique = True for u in topologically_unique_trees: if u.robinson_foulds(t)[0] == 0.0: unique = False break if unique: topologically_unique_trees.append(t) # Output print "Total taxa: %d" % taxa_count print "Total trees: %d" % tree_count print "Unique topologies: %d" % len(topologically_unique_trees) print "Are trees ultrametric? ", str(ultrametric) print "Mean tree age: %f" % (sum(tree_ages) / tree_count) # Done return 0 PKPJ'phyltr/commands/taxa.py"""Usage: phyltr taxa [] Extract the taxa names from the first tree in a stream. OPTIONS: files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) options, files = parser.parse_args() # Read trees for line in fileinput.input(): t = ete2.Tree(line) names = [n.name for n in t.traverse() if n.name] for n in sorted(names): print(n) return 0 PKC?Ijphyltr/commands/ages.py"""Usage: phyltr ages [] taxa [] Print the age(s) of particular nodes in a treestream. The nodes are either leaf nodes, or the most recent common ancestor (MRCA) of a set of leaf nodes. Ages are measured from the root of the tree. If multiple taxa are provided and the MRCA option is not enabled, the output will be a tab-separated list of ages for the individual taxa. OPTIONS: taxa A comma-separated list of leaf taxon names to print ages for -m, --mrca Output ages of the MRCA of the specified taxa files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import sys import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-m', '--mrca', action="store_true", dest="mrca", default=False) options, positional = parser.parse_args() taxa = positional[0].split(",") files = positional[1:] if len(positional) > 1 else [] for line in fileinput.input(files): t = ete2.Tree(line) if options.mrca: mrca = t.get_common_ancestor(taxa) print t.get_distance(mrca) else: taxa = [t.get_leaves_by_name(name=taxon)[0] for taxon in taxa] dists = [t.get_distance(n) for n in taxa] print "\t".join(map(str,dists)) # Done return 0 PK>F$9phyltr/commands/com.pyimport fileinput import phyltr.utils.cladeprob import ete2 def run(): for line in fileinput.input(): t = ete2.Tree(line) dead_nodes = [] for node in t.traverse("preorder"): if node in dead_nodes: continue desc = node.get_descendants() desc.append(node) if all([n.support >=0.5 for n in desc]): dead_nodes.extend(desc) node.name = "+".join([l.name for l in node.get_leaves()]) for child in node.get_children(): child.detach() print t.write() # Done return 0 PKPJ4Fo o phyltr/commands/plot.py"""Usage: phyltr plot [] [] Plot each tree in a treestream graphically. OPTIONS: -a, --attribute Specify the name of an attribute to colour leaves by files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import os.path import ete2 import phyltr.utils.phyoptparse as optparse colours = ((240,163,255),(0,117,220),(153,63,0),(76,0,92),(25,25,25),(0,92,49),(43,206,72),(255,204,153),(128,128,128),(148,255,181),(143,124,0),(157,204,0),(194,0,136),(0,51,128),(255,164,5),(255,168,187),(66,102,0),(255,0,16),(94,241,242),(0,153,143),(224,255,102),(116,10,255),(153,0,0),(255,255,128),(255,255,0),(255,80,5),(0,255,255)) colours = ['#%02x%02x%02x' % c for c in colours] def get_colour_set(n): if n <= len(colours): return colours[0:n] def ultrametric(node): node.img_style["vt_line_width"]=0 if node.is_leaf(): node.img_style["size"]=5 else: node.img_style["size"]=0 def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-a', '--attribute', dest="attribute", default=None) parser.add_option('-d', '--dpi', type="int", default=None) parser.add_option('-H', '--height', type="int", dest="h", default=None) parser.add_option('-l', '--label', default="name") parser.add_option('-m', '--multiple', default=False, action="store_true") parser.add_option('-o', '--output', default=None) parser.add_option('-u', '--units', default="px") parser.add_option('-w', '--width', type="int", dest="w", default=None) options, files = parser.parse_args() # Setup TreeStyle ts = ete2.TreeStyle() ts.show_scale = False ts.show_branch_support = True # Read trees for n, line in enumerate(fileinput.input(files)): t = ete2.Tree(line) # Add faces if options.attribute: values = set([getattr(l, options.attribute) for l in t.get_leaves()]) colours = get_colour_set(len(values)) colour_map = dict(zip(values, colours)) for l in t.iter_leaves(): mycolour = colour_map[getattr(l,options.attribute)] l.add_face(ete2.CircleFace(radius=10,color=mycolour, style="sphere"), 0) for l in t.iter_leaves(): l.add_face(ete2.TextFace(getattr(l, options.label)), 1) # Plot or save if options.output: kw = {} if options.h or options.w: for o in ("h","w","units","dpi"): if getattr(options, o): kw[o] = getattr(options, o) if options.multiple: base, ext = os.path.splitext(options.output) filename = base + ("_%06d" % (n+1)) + ext else: filename = options.output t.render(filename, ultrametric, tree_style=ts, **kw) else: t.show(ultrametric, tree_style=ts) if not options.multiple: return 0 return 0 PKPJl TU U phyltr/commands/prune.py"""Usage: phyltr prune taxa [] [] Delete a specified set of nodes from the tree. OPTIONS: taxa A comma-separated list of leaf taxon to delete from the tree -i, --inverse Specify an "inverse prune": delete all taxa *except* those given in the taxa option. files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import sys import ete2 import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-a', '--attribute', default=None) parser.add_option('-f', '--file', dest="filename", help='Specifies a file from which to read taxa') parser.add_option('-i', '--inverse', action="store_true", default=False, dest="inverse") parser.add_option('-v', '--value', default=None) options, files = parser.parse_args() if options.attribute and options.value: by_attribute = True elif options.filename: fp = open(options.filename, "r") taxa = [t.strip() for t in fp.readlines()] by_attribute = False elif files: taxa = set(files[0].split(",")) files = files[1:] by_attribute = False else: # Improper usage sys.stderr.write("Must specify either a list of taxa, a file of taxa, or an attribute and value.\n") sys.exit(1) first = True for line in fileinput.input(files): t = ete2.Tree(line) # Decide which leaves to prune if by_attribute: if options.inverse: pruning_taxa = [l for l in t.get_leaves() if hasattr(l,options.attribute) and getattr(l,options.attribute) == options.value] else: pruning_taxa = [l for l in t.get_leaves() if hasattr(l,options.attribute) and getattr(l,options.attribute) != options.value] else: if options.inverse: pruning_taxa = [l for l in t.get_leaves() if l.name in taxa] else: pruning_taxa = [l for l in t.get_leaves() if l.name not in taxa] # Do the deed t.prune(pruning_taxa) print t.write(features=[],format_root_node=True) # Done return 0 PKC?IOq( phyltr/commands/rogue.py"""Usage: phyltr rogue [] [] Remove rogue taxa which assume many contradictory locations in a treestream, lowering clade supports. OPTIONS: -n The number of rogue taxa to remove. -g, --guard A comma-separated list of taxa names which should be guarded from removal by the rogue searching algorithm files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import sys import ete2 import phyltr.utils.cladeprob import phyltr.utils.phyoptparse as optparse def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-n', action="store", dest="iterations", type="int", default=1) parser.add_option('-g', "--guard", action="store", dest="guarded") options, files = parser.parse_args() # Get list of guarded taxa if options.guarded: guarded_taxa = options.guarded.split(",") else: guarded_taxa = [] # Read trees trees = [] for line in fileinput.input(files): t = ete2.Tree(line) trees.append(t) # Remove rogue nodes for i in range(0, options.iterations): rogue = remove_rogue(trees, guarded_taxa) sys.stderr.write("Removing %s as rogue\n" % rogue) # Output for t in trees: print t.write() # Done return 0 def remove_rogue(trees, guarded): leaves = trees[0].get_leaves() candidates = [l for l in leaves if l.name not in guarded] scores = [] # Compute maximum clade credibility for each candidate rogue for candidate in candidates: # Make a list of trees which have had candidate removed pruned_trees = [t.copy() for t in trees] survivors = set(leaves) - set(candidate) for pruned in pruned_trees: pruned.prune([s.name for s in survivors]) # Compute clade probs cp = phyltr.utils.cladeprob.CladeProbabilities() for t in pruned_trees: cp.add_tree(t) cp.compute_probabilities() # Find max clade prob tree max_prob = -sys.float_info.max for t in pruned_trees: prob = cp.get_tree_prob(t) if prob > max_prob: max_prob = prob # Record scores.append((max_prob,candidate)) # Find the candidate with the highest maximum clade credibility scores.sort() scores.reverse() rogue = scores[0][1] # Prune trees for t in trees: leaves = t.get_leaves() rogue = t.get_leaves_by_name(rogue.name)[0] survivors = set(leaves) - set(rogue) t.prune(survivors) return rogue.name PKF|A,phyltr/commands/con.pyimport fileinput import sys import phyltr.utils.cladeprob import ete2 def run(): # Read trees and compute clade probabilities trees = [] cp = phyltr.utils.cladeprob.CladeProbabilities() for line in fileinput.input(): t = ete2.Tree(line) trees.append(t) cp.add_tree(t) cp.compute_probabilities() # Find max clade prob tree max_prob = -sys.float_info.max for t in trees: prob = cp.get_tree_prob(t) if prob > max_prob: max_prob = prob best_tree = t # Annotate max clade prob tree with clade supports cp.annotate_tree(best_tree) # Output print best_tree.write() # Done return 0 PKPJ~qBBphyltr/commands/collapse.py"""Usage: phyltr collapse [] [] Collapse monophyletic sets of leaf nodes, by turning their MRCA into a leaf, and giving the newly formed leaf a specified label. OPTIONS: -t, --translate The filename of the translate file. Each line of the translate file should be of the format: "label:taxa1,taxa2,taxa3,...." The MRCA of the specified taxa will be replaced by a leaf named "label". files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import sys import ete2 import phyltr.utils.phyoptparse as optparse def read_clade_file(filename): """Read a file of names and clade definitions and return a dictionary of this data.""" trans = [] fp = open(filename, "r") for line in fp: name, clade = line.strip().split(":") clade = clade.strip().split(",") trans.append((clade, name)) fp.close() return trans def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-a', '--attribute', dest="attribute", default=None) parser.add_option('-t', '--translate', help='Specifies the translation file.',default=None) options, files = parser.parse_args() # Read translation file if options.translate: try: trans = read_clade_file(options.translate) except IOError: return 1 # Read trees for line in fileinput.input(files): t = ete2.Tree(line) if options.translate: collapse_from_file(t, trans) else: collapse_by_attribute(t, options.attribute) # Output print t.write(features=[],format_root_node=True) # Done return 0 def collapse_by_attribute(t, attribute): values = set([getattr(n,attribute) for n in t.traverse() if hasattr(n,attribute)]) if not t.check_monophyly(values, attribute, ignore_missing=True): sys.stderr.write("Monophyly failure for attribute: %s" % attribute) return 1 for v in values: mrca = list(t.get_monophyletic([v], attribute))[0] mrca.name = v mrca.add_feature(attribute, v) leaf, dist = mrca.get_farthest_leaf() mrca.dist += dist for child in mrca.get_children(): child.detach() def collapse_from_file(t, trans): cache = t.get_cached_content() tree_leaves = cache[t] for clade, name in trans: # Get a list of leaves in this tree clade_leaves = [l for l in tree_leaves if l.name in clade] if not clade_leaves: continue # Check monophyly if len(clade_leaves) == 1: mrca = clade_leaves[0] # .get_common_ancestor works oddly for singletons else: mrca = t.get_common_ancestor(clade_leaves) mrca_leaves = cache[mrca] if set(mrca_leaves) == set(clade_leaves): # Clade is monophyletic, so rename and prune # But don't mess up distances mrca.name = name leaf, dist = mrca.get_farthest_leaf() mrca.dist += dist for child in mrca.get_children(): child.detach() else: # Clade is not monophyletic. We can't collapse it. sys.stderr.write("Monophyly failure for clade: %s\n" % name) sys.stderr.write("Interlopers: %s\n" % ",".join([n.name for n in set(mrca_leaves) - set(clade_leaves)])) return 1 PKPJD dphyltr/commands/rename.py"""Usage: phyltr rename [] [] Rename the nodes in a treestream. The mapping from old to new names is read from a file. OPTIONS: -f, --file The filename of the translation file. Each line of the translate file should be of the format: "old:new" files A whitespace-separated list of filenames to read treestreams from. Use a filename of "-" to read from stdin. If no filenames are specified, the treestream will be read from stdin. """ import fileinput import ete2 import phyltr.utils.phyoptparse as optparse def read_rename_file(filename): """Read a file of names and their desired replacements and return a dictionary of this data.""" rename = {} fp = open(filename, "r") for line in fp: old, new = line.strip().split(":") rename[old.strip()] = new.strip() fp.close() return rename def run(): # Parse options parser = optparse.OptionParser(__doc__) parser.add_option('-f', '--file', dest="filename", help='Specifies the translation file.') options, files = parser.parse_args() # Read translation file try: rename = read_rename_file(options.filename) except IOError: return 1 # Read trees for line in fileinput.input(files): t = ete2.Tree(line) # Rename nodes for node in t.traverse(): if node.name in rename: node.name = rename[node.name] # Output print t.write() # Done return 0 PKC?Iphyltr/commands/__init__.pyPK,PJtK= = phyltr-0.3.0.data/scripts/phyltr#!python """Phyltr Usage: phyltr [] The available phyltr commands are: annotate Annotate nodes with metadata from .csv file cat Convert file(s) to tree streams clades List clade supports collapse Collapse clades to named taxa consensus Build majority rules consensus tree dedupe Remove duplicate taxa (by name) height Print the height of each tree in a tree stream nexus Convert tree stream to NEXUS file plot Plot tree using ETE interactive viewer, or to file pretty Pretty print a tree (ASCII art) prune Prune specified taxa from a tree rename Rename specified taxa rogue Remove rogue taxon or taxons scale Scale branch lengths of a set of trees stat Summary statistics on a set of trees support Add clade support information to a tree stream subtree Extract minimal subtrees containing specified taxa taxa Extract taxa names from a tree uniq Merge trees with matching topologies All commands can be abbreviated to their first three letters, e.g. running "phyltr col" is the same as running "phyltr collapse". Command specific help is availble via "phyltr --help". """ import sys from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE,SIG_DFL) def usage(): print __doc__ def main(): if len(sys.argv) > 1: command = sys.argv.pop(1) else: command = "usage" if command in ("ann", "annotate"): import phyltr.commands.annotate as comm elif command == "cat": import phyltr.commands.cat as comm elif command in ("cla", "clades"): import phyltr.commands.clades as comm elif command in ("col", "collapse"): import phyltr.commands.collapse as comm elif command in ("con", "consensus"): import phyltr.commands.consensus as comm elif command in ("ded", "dedupe"): import phyltr.commands.dedupe as comm elif command in ("hei", "height"): import phyltr.commands.height as comm elif command in ("nex", "nexus"): import phyltr.commands.nexus as comm elif command in ("plo", "plot"): import phyltr.commands.plot as comm elif command in ("pre", "pretty"): import phyltr.commands.pretty as comm elif command in ("pru", "prune"): import phyltr.commands.prune as comm elif command in ("ren", "rename"): import phyltr.commands.rename as comm elif command in ("rog", "rogue"): import phyltr.commands.rogue as comm elif command in ("sca", "scale"): import phyltr.commands.scale as comm elif command in ("sta", "stat"): import phyltr.commands.stat as comm elif command in ("sup", "support"): import phyltr.commands.support as comm elif command in ("sub", "subtree"): import phyltr.commands.subtree as comm elif command in ("tax", "taxa"): import phyltr.commands.taxa as comm elif command in ("uni", "uniq"): import phyltr.commands.uniq as comm elif command in ("--help", "help", "--usage", "usage"): usage() sys.exit(0) else: sys.stderr.write("phyltr: '%s' is not a phyltr command. See 'phyltr --help'.\n" % command) sys.exit(0) sys.exit(comm.run()) if __name__ == "__main__": main() PK,PJ^- &phyltr-0.3.0.dist-info/DESCRIPTION.rstUNKNOWN PK,PJO$phyltr-0.3.0.dist-info/metadata.json{"classifiers": ["Programming Language :: Python", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)"], "extensions": {"python.details": {"contacts": [{"email": "luke@maurits.id.au", "name": "Luke Maurits", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/lmaurits/phyltr"}}}, "extras": [], "generator": "bdist_wheel (0.28.0)", "license": "GPL3", "metadata_version": "2.0", "name": "phyltr", "requires": "ete2", "run_requires": [{"requires": ["ete2"]}], "summary": "Unix filters for manipulating and analysing (samples of) phylogenetic trees represented in the Newick format", "version": "0.3.0"}PK,PJ8$$$phyltr-0.3.0.dist-info/top_level.txtphyltr phyltr/commands phyltr/utils PK,PJ#M\\phyltr-0.3.0.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.28.0) Root-Is-Purelib: true Tag: py2-none-any PK,PJ|phyltr-0.3.0.dist-info/METADATAMetadata-Version: 2.0 Name: phyltr Version: 0.3.0 Summary: Unix filters for manipulating and analysing (samples of) phylogenetic trees represented in the Newick format Home-page: https://github.com/lmaurits/phyltr Author: Luke Maurits Author-email: luke@maurits.id.au License: GPL3 Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) Requires: ete2 Requires-Dist: ete2 UNKNOWN PK,PJt> phyltr-0.3.0.dist-info/RECORDphyltr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 phyltr/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 phyltr/commands/ages.py,sha256=Luc0K0xtMIa5_45cIqKaQhgWJPEN0DyDG8ezpwsXdLU,1558 phyltr/commands/annotate.py,sha256=7SLFN29v8Y9rJdCqGzHGXYrApGKjfq4dmPrd2bZ6_Fk,3799 phyltr/commands/cat.py,sha256=A90RmXIB6eT9Ma07Wej9GGNab9Fsc6ouxRT8nhnA-dQ,5780 phyltr/commands/clades.py,sha256=vU47TeLyaQd55v2JLe2x9_1hRVydhDiMO9XAS51lFxE,1634 phyltr/commands/collapse.py,sha256=Fcx38fBNOy_rWb4blV-m7IYN9e1Xw3MP9yzytbrXc_g,3650 phyltr/commands/com.py,sha256=LZiWJZ2DjsgWIqcPcNSte13aL-yvn9jug5lwE5oHEpM,639 phyltr/commands/con.py,sha256=Jm-ayMXewVtc28AgBiUfs4lKfEFdCbfMxo0sP53l8rk,702 phyltr/commands/consensus.py,sha256=tjwJ4Fcl1Jv-gKriWU1Z-hLIV5UslXXPdRBILiknWos,4258 phyltr/commands/dedupe.py,sha256=NgGPdk_JHYoeMo9Qq9195A0REq5c07M7CVugOnZ8LY0,1739 phyltr/commands/delete.py,sha256=Km_FSlc4OmBI91n1bmW_FusRqBti5_QvJ1PoDRoPjeI,1098 phyltr/commands/fastcat.py,sha256=jO2oNlHt6g24ZtzSgyQ4WUb1EunWBCFbO59lWFbrF6g,7278 phyltr/commands/height.py,sha256=7IVEiJHWSQc65HgK76C21p-Q2IdhGOlQ51N7J4lrPvs,642 phyltr/commands/nexus.py,sha256=WTnwVPo9EW2YW0Ne2yz1btN1A2vZRSRM4F2QOKxtc0E,1600 phyltr/commands/plot.py,sha256=ueIUxpXeY7IcOOGYwWhgm9kRRb-nM7aYmSrGxAwcIwg,3183 phyltr/commands/pretty.py,sha256=cTetQiHKaAWuLFPKOFXQXwDCH8539X9otNkPF9rrtyw,1610 phyltr/commands/prune.py,sha256=7euWQJRIePKb1cODZ48XOuLbPIok6o4_kWH-k32FKmw,2389 phyltr/commands/rename.py,sha256=A9QEHGhlJYThYaDgp-PlF_dmOj4DvvV3D6UNVacUkew,1567 phyltr/commands/rogue.py,sha256=5Y-ktxb7PKmBp08o-l5eXfEtTi4fgji5M2TdiO3ecsU,2796 phyltr/commands/scale.py,sha256=EBGLZunawKPe1qn5FF-ur9jbznkUjH9pPLjMcdkv1-I,980 phyltr/commands/stat.py,sha256=iah2coeCn4c8k14bmJhawpkUuwYZpLsZRgncxXS2Mds,1831 phyltr/commands/subtree.py,sha256=T2gHV9lp_LBujwpFGcFVDFTArU-869dpbABhACye55w,1769 phyltr/commands/support.py,sha256=Fs6gM4RE75_Ypp-7huufg03pODagH5snCc4G847Yox4,2159 phyltr/commands/taxa.py,sha256=y9YR-BIctunqz1AG_rcBcxVieiVpHDv_NRpaTy7Qsmw,725 phyltr/commands/uniq.py,sha256=AJPzGQXjlUMQKxLxmOo3NUOqBRMSlDVqvXzD1prnu-w,2346 phyltr/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 phyltr/utils/cladeprob.py,sha256=fYLGJjn5TgEiMEZbhlKBcm9aisV_BHzHZsFCZ7kFnv8,3909 phyltr/utils/phyoptparse.py,sha256=kbsN_X8F4WWYLaziGnZJ6PjHeoX29uAPdL5d5nL4sk0,605 phyltr/utils/treestream_io.py,sha256=02X9bF8jp0liMVZIr85ARvVqK7cCeKWytsoo1-nim8A,217 phyltr-0.3.0.data/scripts/phyltr,sha256=Go-Z9St3l-fm21kybXHEzdrtEkX2UC4EuGhMZwwIwf0,3389 phyltr-0.3.0.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10 phyltr-0.3.0.dist-info/METADATA,sha256=Mwn7t3yBZpkYPeQG5wkwmp630-u9bdx_FHThr_k4EJY,466 phyltr-0.3.0.dist-info/RECORD,, phyltr-0.3.0.dist-info/WHEEL,sha256=eZuMUHtrZN3bwljZqH2VonANw_HIsKDj9jLQtlaMlbw,92 phyltr-0.3.0.dist-info/metadata.json,sha256=uMBkBTRF5I3dIqcfIhK0pBRuWToyugDaHbY2L0SHncU,682 phyltr-0.3.0.dist-info/top_level.txt,sha256=TDy2oB5ekEca6teZSJFW4TITbS3FLE2zbF4vpPbAbkg,36 PKC?Iphyltr/__init__.pyPKPJ9 0EE0phyltr/utils/cladeprob.pyPKI9phyltr/utils/treestream_io.pyPKC?I@]]phyltr/utils/phyoptparse.pyPKC?IVphyltr/utils/__init__.pyPKPJ(Jphyltr/commands/consensus.pyPKPJ,h$phyltr/commands/dedupe.pyPKI]5]j+phyltr/commands/height.pyPKC?IB* * #.phyltr/commands/uniq.pyPKi F?P/JJ7phyltr/commands/delete.pyPKIaoo<phyltr/commands/support.pyPKPJBbbDphyltr/commands/clades.pyPKIWuJJCKphyltr/commands/pretty.pyPKC?I b@@Qphyltr/commands/nexus.pyPKPJ`,:Xphyltr/commands/cat.pyPKPJx)ophyltr/commands/scale.pyPKPJ TVo sphyltr/commands/subtree.pyPK#_I3nn-zphyltr/commands/fastcat.pyPKPJnӖphyltr/commands/annotate.pyPKC?I6''phyltr/commands/stat.pyPKPJ'?phyltr/commands/taxa.pyPKC?IjIphyltr/commands/ages.pyPK>F$9phyltr/commands/com.pyPKPJ4Fo o Gphyltr/commands/plot.pyPKPJl TU U phyltr/commands/prune.pyPKC?IOq( vphyltr/commands/rogue.pyPKF|A,phyltr/commands/con.pyPKPJ~qBBphyltr/commands/collapse.pyPKPJD dphyltr/commands/rename.pyPKC?Ihyltr/commands/__init__.pyPK,PJtK= = 큔phyltr-0.3.0.data/scripts/phyltrPK,PJ^- &phyltr-0.3.0.dist-info/DESCRIPTION.rstPK,PJO$]phyltr-0.3.0.dist-info/metadata.jsonPK,PJ8$$$Iphyltr-0.3.0.dist-info/top_level.txtPK,PJ#M\\phyltr-0.3.0.dist-info/WHEELPK,PJ|Ephyltr-0.3.0.dist-info/METADATAPK,PJt> Tphyltr-0.3.0.dist-info/RECORDPK%%m j