1
2
3
4
5
6 """I/O function wrappers for Bio.Nexus trees."""
7 __docformat__ = "epytext en"
8
9 from itertools import chain
10
11 from Bio.Nexus import Nexus
12 from Bio.Phylo import Newick, NewickIO
13
14
15
16 NEX_TEMPLATE = """\
17 #NEXUS
18 Begin Taxa;
19 Dimensions NTax=%(count)d;
20 TaxLabels %(labels)s;
21 End;
22 Begin Trees;
23 %(trees)s
24 End;
25 """
26
27
28 TREE_TEMPLATE = "Tree tree%(index)d=[&U]%(tree)s;"
29
30
32 """Parse the trees in a Nexus file.
33
34 Uses the old Nexus.Trees parser to extract the trees, converts them back to
35 plain Newick trees, and feeds those strings through the new Newick parser.
36 This way we don't have to modify the Nexus module yet. When we're satisfied
37 with Bio.Phylo, we can change Nexus to use the new NewickIO parser directly.
38 """
39 nex = Nexus.Nexus(handle)
40
41
42
43 def node2clade(nxtree, node):
44 subclades = [node2clade(nxtree, nxtree.node(n)) for n in node.succ]
45 return Newick.Clade(
46 branch_length=node.data.branchlength,
47 name=node.data.taxon,
48 clades=subclades,
49 confidence=node.data.support,
50 comment=node.data.comment)
51
52 for nxtree in nex.trees:
53 newroot = node2clade(nxtree, nxtree.node(nxtree.root))
54 yield Newick.Tree(root=newroot, rooted=nxtree.rooted, name=nxtree.name,
55 weight=nxtree.weight)
56
57 -def write(obj, handle, **kwargs):
58 """Write a new Nexus file containing the given trees.
59
60 Uses a simple Nexus template and the NewickIO writer to serialize just the
61 trees and minimal supporting info needed for a valid Nexus file.
62 """
63 trees = list(obj)
64 writer = NewickIO.Writer(trees)
65 nexus_trees = [TREE_TEMPLATE % {'index': idx+1, 'tree': nwk}
66 for idx, nwk in enumerate(
67 writer.to_strings(plain=False, plain_newick=True,
68 **kwargs))]
69 tax_labels = map(str, chain(*(t.get_terminals() for t in trees)))
70 text = NEX_TEMPLATE % {
71 'count': len(tax_labels),
72 'labels': ' '.join(tax_labels),
73 'trees': '\n'.join(nexus_trees),
74 }
75 handle.write(text)
76 return len(nexus_trees)
77