File: text_tree.py

package info (click to toggle)
python-cogent 1.9-14
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 19,752 kB
  • sloc: python: 137,485; makefile: 149; sh: 64
file content (114 lines) | stat: -rw-r--r-- 3,460 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/python
# file text_tree.py
"""Simple base text representation of phylo tree."""

__author__ = "Micah Hamady"
__copyright__ = "Copyright 2007-2016, The Cogent Project"
__credits__ = ["Micah Hamady"]
__license__ = "GPL"
__version__ = "1.9"
__maintainer__ = "Micah Hamady"
__email__ = "hamady@colorado.edu"
__status__ = "Prototype"

class TextNode(object):
    """ Helper to display text phyolo tree """
    def __init__(self, branch_length, name):
        """Set up defaults"""
        self.BranchLength = 0.0
        if branch_length:
            self.BranchLength = branch_length

        self.Name = name
        self.Printed = False
        self.NumChildren = 0
        self.NumChildrenPrinted = 0
        self.LastChild = None

    def display(self, max_dist, scale):
        """Display current node - should refactor this"""
        delimiter = "-"
        pdelimiter = "+"

        if self.Printed:
            delimiter = " "
            pdelimiter = "|"

        # compute number of children last child has
        last_ct = 0
        if self.LastChild:
            last_ct = self.LastChild.NumChildren

        # update values
        self.Printed = True
        self.NumChildrenPrinted += 1
        print_ct = self.NumChildren - last_ct

        if self.NumChildrenPrinted == (print_ct + 1): # or \
            delimiter = " "
            pdelimiter = "+"
        elif self.NumChildrenPrinted > (print_ct + 1):
            pdelimiter = " "
            delimiter = " "
        if (self.NumChildren == self.NumChildrenPrinted and self.NumChildren == print_ct): 
            delimiter = " "
            pdelimiter = "+"
 
        # check if leaf
        dout = ""
        if self.Name:
            dout = "@@%s" % self.Name 
            pdelimiter = ">"
            delimiter = "-"

        return (int(self.BranchLength) - 1) * delimiter + pdelimiter + dout

def process_nodes(all_nodes, cur_nodes, cur_node, parent):
    """ Recursively process nodes """
    # make current node
    pn = TextNode(cur_node.Length, cur_node.Name)

    # set current node as last child of parent (last one wins)
    if parent:
        parent.LastChild = pn

    # handle terminal node
    if not cur_node.Children:
        all_nodes.append(cur_nodes + [pn])

    # internal node
    else:
        cur_nodes.append(pn)
        pn.NumChildren = 0 
        for child in cur_node.Children:
            if child.Children:
                pn.NumChildren +=  len(child.tips())
            else:
                pn.NumChildren += 1 
        for child in cur_node.Children: 
            process_nodes(all_nodes, cur_nodes, child, pn)
        cur_nodes.pop()

def generate_nodes(tree, max_dist, scale):
    """Iterate over list of TextNodes to display """ 
    all_nodes = []
    cur_nodes = []
    
    # generate list of lists of TextNodes
    process_nodes(all_nodes, cur_nodes, tree, None)

    # process each list of TextNodes
    for node_list in all_nodes:

        # generate text string and node key 
        ticks, node_key =  ''.join([x.display(max_dist, scale) for x in node_list]).split("@@")
        
        # compute distances
        dist = sum([x.BranchLength for x in node_list])
        #scaled_dist = sum([x.ScaledBranchLength for x in node_list])
        scaled_dist = sum([x.BranchLength for x in node_list])
        branch_len = node_list[-1].BranchLength

        # yield each node 
        yield ticks, node_key, dist, scaled_dist, branch_len