def __init__(self, newickstr, periods=None, root_age=None): """ newickstr: newick tree with branch lengths periods: list of durations ordered from present to past root_age: age of root node for branch length scaling """ self.root = newick.parse(newickstr) phylo.polarize(self.root) self.periods = periods # initialize nodes (label interiors, etc) # and collect leaves and postorder sequence self.postorder_nodes = [] self.leaves = [] for i, node in enumerate(self.root.descendants(phylo.POSTORDER)): node.tree = self node.number = i node.segments = [] if (not node.istip) and (not node.label): node.label = str(node.number) node.age = None if node.istip: #node.age = 0.0 self.leaves.append(node) self.postorder_nodes.append(node) self.root_age = root_age if root_age: self.calibrate(root_age) self.label2node = dict([(n.label, n) for n in self.postorder_nodes ]) self.assign_node_ages() ## for node in self.postorder_nodes: ## if node.parent and (node.parent.age is None): ## node.parent.age = node.age + node.length # initialize branch segments for node in self.postorder_nodes: if node.parent: periods = self.periods anc = node.parent.age des = node.age assert anc > des, "%s = %g, %s = %g\n%s" \ % (node.parent.label, anc, node.label, des, self.root.render_ascii(scaled=1, minwidth=80)) t = des for i, p in enumerate(periods): s = sum(periods[:i+1]) if t < s: duration = min((s - t, anc - t)) if duration > 0: seg = BranchSegment(duration, i) node.segments.append(seg) t += p if t > anc: break
def tree2ascii(tree, unitlen=3, minwidth=None, maxwidth=None, scaled=False, show_internal_labels=True, data=None): phylo.polarize(tree) depth_length_preorder_traversal(tree) leaves = tree.leaves() nleaves = len(leaves) node2label = dict([(n, n.label) for n in tree.descendants()]) if data: for k, v in node2label.items(): if v in data: if k.istip: node2label[k] = "[%s] %s" % (data[v], v) else: node2label[k] = "%s [%s]" % (data[v], v) maxdepth = max([lf.depth for lf in leaves]) max_labelwidth = max([len(node2label[lf]) for lf in leaves]) + 1 root_offset = 0 if tree.label and show_internal_labels: root_offset = len(node2label[tree]) width = maxdepth * unitlen + max_labelwidth + 2 + root_offset # print width height = 2 * nleaves - 1 if minwidth and (width < minwidth): unitlen = (minwidth - max_labelwidth - 2 - root_offset) / maxdepth width = maxdepth * unitlen + max_labelwidth + 2 + root_offset buf = AsciiBuffer(width, height) for i, lf in enumerate(leaves): lf.c = width - max_labelwidth - 2 lf.r = i * 2 for node in tree.descendants(phylo.POSTORDER): if not node.istip: children = node.children() rmin = children[0].r rmax = children[-1].r node.r = int(rmin + (rmax - rmin) / 2.0) node.c = min([ch.c for ch in children]) - unitlen if not scaled: for i in range(maxdepth): smooth_cpos(tree) else: maxlen = max([lf.length_to_root for lf in leaves]) scalef = (leaves[0].c + 1 - root_offset) / maxlen scale_cpos(tree, scalef, root_offset) for node in tree.descendants(phylo.POSTORDER): if node.parent: for r in range(min([node.r, node.parent.r]), max([node.r, node.parent.r])): buf.putstr(r, node.parent.c, ":") sym = getattr(node, "hchar", "-") vbar = sym * (node.c - node.parent.c) buf.putstr(node.r, node.parent.c, vbar) if node.istip: buf.putstr(node.r, node.c + 1, " " + node2label[node]) else: if node.label and show_internal_labels: label = node2label[node] buf.putstr(node.r, node.c - len(label), label) buf.putstr(node.r, node.c, "+") return str(buf)