def write(obj, handle, **kwargs): """Write a new Nexus file containing the given trees. Uses a simple Nexus template and the NewickIO writer to serialize just the trees and minimal supporting info needed for a valid Nexus file. """ trees = list(obj) writer = NewickIO.Writer(trees) nexus_trees = [ TREE_TEMPLATE % { 'index': idx + 1, 'tree': nwk } for idx, nwk in enumerate( writer.to_strings(plain=False, plain_newick=True, **kwargs)) ] tax_labels = [ str(x.name) for x in chain(*(t.get_terminals() for t in trees)) ] text = NEX_TEMPLATE % { 'count': len(tax_labels), 'labels': ' '.join(tax_labels), 'trees': '\n'.join(nexus_trees), } handle.write(text) return len(nexus_trees)
def nexus_text(obj, colour_branches, colours, **kwargs): """ Take tree-like object(s) and create nexus-format representation. Allows for colouring tip names. Modified from http://biopython.org/DIST/docs/api/Bio.Phylo.NexusIO-pysrc.html NB here we compensate for an apparent bug in the Biopython implementation, whereby an additional colon is wrongly added to confidence values in the output tree strings. """ try: trees = list(obj) # assume iterable except TypeError: trees = [obj] writer = NewickIO.Writer(trees) nexus_trees = [TREE_TEMPLATE % {'index': idx + 1, 'tree': nwk} for idx, nwk in enumerate( writer.to_strings(plain=False, plain_newick=True, **kwargs))] # if branches are being coloured, then taxon names already contain colouring annotation # otherwise we need to add this annotation here tax_labels = [ colour_taxon(str(x.name), colours) if not colour_branches else str(x.name) for x in chain(*(t.get_terminals() for t in trees))] text = NEX_TEMPLATE % { 'count': len(tax_labels), 'labels': ' '.join(tax_labels), # taxlabels all on one line 'trees': '\n'.join(nexus_trees), # trees on separate lines } return re.sub(r':([0-9]{1,3}\.[0-9]{1,3}):', r'\1:', text) # Corrects for biopython bug. eg ":50.00:" -> "50.00:"
def to_nexus(self, filename): """Writes the tree to the given file in nexus format. This method doesn't call Bio.Phylo.NexusIO as BayesTraitsV2 requires a different dialect of Nexus format. """ # Copy the tree before making any changes on it. tree = copy.deepcopy(self.tree) # BayesTraits requires the Nexus file to have a "Translate" block which # declares a number->taxon mapping so that numbers, not long taxa # names, are used in the tree descriptions. names_to_ints = dict((clade.name, i) for i, clade in enumerate( tree.get_terminals(), start=1)) # Assign numbers to terminal clades for node in tree.get_terminals(): node.name = str(names_to_ints[node.name]) # Drop names of the inner nodes for n in tree.get_nonterminals(): n.name = None # Tree to string writer = NewickIO.Writer([tree]) nexus_tree = NEX_TEMPLATE % { 'translate': ',\n'.join('%d %s' % (name, id) for id, name in names_to_ints.items()), 'tree': next(writer.to_strings(plain=False, plain_newick=True))} # Write string to file with open(filename, 'w') as handle: handle.write(nexus_tree)
def write_nexus_trees_to_bayestraits(nx, handle, **kwargs): """Modified from Bio.Phylo.NexusIO.write(): add a translate block converting leaf names to integers. """ trees = BioNexusTrees_to_BioPhylo(nx.trees) writer = NewickIO.Writer(trees) nexus_trees = [ TREE_TEMPLATE % {"index": idx + 1, "tree": nwk} for idx, nwk in enumerate( writer.to_strings(plain=False, plain_newick=True, **kwargs) ) ] translate = ["%d %s" % id_name for id_name in nx.translate.items()] # Unused in my output format (BayesTraits) + why aren't they unique? tax_labels = [taxon for nt in nx.trees for taxon in nt.get_taxa()] #tax_labels = [str(x.name) for x in chain(*(t.get_terminals() for t in trees))] text = NEX_TEMPLATE % { "count": len(tax_labels), "labels": " ".join(tax_labels), "trees": "\n".join(nexus_trees), "translate": ",\n ".join(translate) } handle.write(text) return len(nexus_trees)
import sys from Bio import Phylo from Bio.Phylo import NewickIO trees = list(Phylo.parse(sys.argv[1], "newick")) print("Removing trees that are not bifurcating.") for tree in trees: for nonterminal in tree.get_nonterminals(): nonterminal.comment = None nonterminal.branch_length = None writer = NewickIO.Writer([tree for tree in trees if tree.is_bifurcating()]) print() print("Saving trees as plain newick files (no branch lengths).") with open(sys.argv[2], "w") as handle: for newick_tree in writer.to_strings(plain=True): handle.write(newick_tree + "\n")