1
2
3
4
5
6
7
8 """I/O function wrappers for the Newick file format.
9
10 See: U{ http://evolution.genetics.washington.edu/phylip/newick_doc.html }
11 """
12 __docformat__ = "epytext en"
13
14 from cStringIO import StringIO
15
16 from Bio.Phylo import Newick
17
18
19 NODECOMMENT_START = '[&'
20 NODECOMMENT_END = ']'
24 """Exception raised when Newick object construction cannot continue."""
25 pass
26
27
28
29
30
31 -def parse(handle):
32 """Iterate over the trees in a Newick file handle.
33
34 @return: a generator of Bio.Phylo.Newick.Tree objects.
35 """
36 return Parser(handle).parse()
37
38 -def write(trees, handle, plain=False, **kwargs):
39 """Write a trees in Newick format to the given file handle.
40
41 @return: number of trees written.
42 """
43 return Writer(trees).write(handle, plain=plain, **kwargs)
44
45
46
47
48
49 -class Parser(object):
50 """Parse a Newick tree given a file handle.
51
52 Based on the parser in Bio.Nexus.Trees.
53 """
54
57
58 @classmethod
62
63 - def parse(self, values_are_support=False, rooted=False):
64 """Parse the text stream this object was initialized with."""
65 self.values_are_support = values_are_support
66 self.rooted = rooted
67 buf = ''
68 for line in self.handle:
69 buf += line.rstrip()
70 if buf.endswith(';'):
71 yield self._parse_tree(buf)
72 buf = ''
73 if buf:
74
75 yield self._parse_tree(buf)
76
81
111
152
153
154
155
156
157 -class Writer(object):
158 """Based on the writer in Bio.Nexus.Trees (str, to_string)."""
159
162
163 - def write(self, handle, **kwargs):
164 """Write this instance's trees to a file handle."""
165 count = 0
166 for treestr in self.to_strings(**kwargs):
167 handle.write(treestr + '\n')
168 count += 1
169 return count
170
171 - def to_strings(self, support_as_branchlengths=False,
172 branchlengths_only=False, plain=False,
173 plain_newick=True, ladderize=None,
174 max_support=1.0):
175 """Return an iterable of PAUP-compatible tree lines."""
176
177 if support_as_branchlengths or branchlengths_only:
178 plain = False
179 make_info_string = self._info_factory(plain, support_as_branchlengths,
180 branchlengths_only, max_support)
181 def newickize(clade):
182 """Convert a node tree to a Newick tree string, recursively."""
183 if clade.is_terminal():
184 return ((clade.name or '')
185 + make_info_string(clade, terminal=True))
186 else:
187 subtrees = (newickize(sub) for sub in clade)
188 return '(%s)%s' % (','.join(subtrees),
189 make_info_string(clade))
190
191
192 for tree in self.trees:
193 if ladderize in ('left', 'LEFT', 'right', 'RIGHT'):
194
195 tree.ladderize(reverse=(ladderize in ('right', 'RIGHT')))
196 rawtree = newickize(tree.root) + ';'
197 if plain_newick:
198 yield rawtree
199 continue
200
201 treeline = ['tree', (tree.name or 'a_tree'), '=']
202 if tree.weight != 1:
203 treeline.append('[&W%s]' % round(float(tree.weight), 3))
204 if tree.rooted:
205 treeline.append('[&R]')
206 treeline.append(rawtree)
207 yield ' '.join(treeline)
208
209 - def _info_factory(self, plain, support_as_branchlengths,
210 branchlengths_only, max_support):
211 """Return a function that creates a nicely formatted node tag."""
212 if plain:
213
214 def make_info_string(clade, terminal=False):
215 return ''
216
217 elif support_as_branchlengths:
218
219 def make_info_string(clade, terminal=False):
220 if terminal:
221
222 return ':%1.2f' % max_support
223 else:
224 return ':%1.2f' % (clade.confidence)
225
226 elif branchlengths_only:
227
228 def make_info_string(clade, terminal=False):
229 return ':%1.5f' % (clade.branch_length)
230
231 else:
232
233 def make_info_string(clade, terminal=False):
234 if terminal:
235 return ':%1.5f' % (clade.branch_length or 1.0)
236 else:
237 if (clade.branch_length is not None and
238 hasattr(clade, 'confidence') and
239 clade.confidence is not None):
240
241 return '%1.2f:%1.5f' % (clade.confidence,
242 clade.branch_length)
243 elif clade.branch_length is not None:
244
245 return '0.00000:%1.5f' % clade.branch_length
246 elif (hasattr(clade, 'confidence') and
247 clade.confidence is not None):
248
249 return '%1.2f:0.00000' % clade.confidence
250 else:
251 return '0.00:0.00000'
252
253 return make_info_string
254