Skip to content

Commit 9f93143

Browse files
author
Xing Han Lu
committed
Modify Phylogeny Tree Construction
For Phylogeny demo
1 parent 48d91d5 commit 9f93143

File tree

1 file changed

+91
-19
lines changed

1 file changed

+91
-19
lines changed

demos/usage-phylogeny.py

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,115 @@
1111
exit(1)
1212

1313

14-
def generate_elements(tree):
15-
elements = []
16-
17-
def _add_to_elements(clade, clade_id):
14+
def generate_elements(tree, xlen=30, ylen=30, grabbable=False):
15+
def get_col_positions(tree, column_width=80):
16+
taxa = tree.get_terminals()
17+
18+
# Some constants for the drawing calculations
19+
max_label_width = max(len(str(taxon)) for taxon in taxa)
20+
drawing_width = column_width - max_label_width - 1
21+
22+
"""Create a mapping of each clade to its column position."""
23+
depths = tree.depths()
24+
# If there are no branch lengths, assume unit branch lengths
25+
if not max(depths.values()):
26+
depths = tree.depths(unit_branch_lengths=True)
27+
# Potential drawing overflow due to rounding -- 1 char per tree layer
28+
fudge_margin = int(math.ceil(math.log(len(taxa), 2)))
29+
cols_per_branch_unit = ((drawing_width - fudge_margin) /
30+
float(max(depths.values())))
31+
return dict((clade, int(blen * cols_per_branch_unit + 1.0))
32+
for clade, blen in depths.items())
33+
34+
def get_row_positions(tree):
35+
taxa = tree.get_terminals()
36+
positions = dict((taxon, 2 * idx) for idx, taxon in enumerate(taxa))
37+
38+
def calc_row(clade):
39+
for subclade in clade:
40+
if subclade not in positions:
41+
calc_row(subclade)
42+
positions[clade] = ((positions[clade.clades[0]] +
43+
positions[clade.clades[-1]]) // 2)
44+
45+
calc_row(tree.root)
46+
return positions
47+
48+
def add_to_elements(clade, clade_id):
1849
children = clade.clades
1950

20-
cy_source = {"data": {"id": clade_id}, 'classes': 'nonterminal'}
21-
elements.append(cy_source)
51+
pos_x = col_positions[clade] * xlen
52+
pos_y = row_positions[clade] * ylen
53+
54+
cy_source = {
55+
"data": {"id": clade_id},
56+
'position': {'x': pos_x, 'y': pos_y},
57+
'classes': 'nonterminal',
58+
'grabbable': grabbable
59+
}
60+
nodes.append(cy_source)
2261

2362
if clade.is_terminal():
2463
cy_source['data']['name'] = clade.name
2564
cy_source['classes'] = 'terminal'
2665

27-
for n, child in enumerate(children, 1):
28-
child_id = len(elements) + n
29-
30-
cy_edge = {'data': {
31-
'source': clade_id,
32-
'target': child_id,
33-
'length': clade.branch_length
34-
}}
66+
for n, child in enumerate(children):
67+
# The "support" node is on the same column as the parent clade,
68+
# and on the same row as the child clade. It is used to create the
69+
# 90 degree angle between the parent and the children.
70+
# Edge config: parent -> support -> child
71+
72+
support_id = clade_id + 's' + str(n)
73+
child_id = clade_id + 'c' + str(n)
74+
pos_y_child = row_positions[child] * ylen
75+
76+
cy_support_node = {
77+
'data': {'id': support_id},
78+
'position': {'x': pos_x, 'y': pos_y_child},
79+
'grabbable': grabbable,
80+
'classes': 'support'
81+
}
82+
83+
cy_support_edge = {
84+
'data': {
85+
'source': clade_id,
86+
'target': support_id,
87+
'sourceCladeId': clade_id
88+
},
89+
}
90+
91+
cy_edge = {
92+
'data': {
93+
'source': support_id,
94+
'target': child_id,
95+
'length': clade.branch_length,
96+
'sourceCladeId': clade_id
97+
},
98+
}
3599

36100
if clade.confidence and clade.confidence.value:
37101
cy_source['data']['confidence'] = clade.confidence.value
38102

39-
elements.extend([cy_edge])
103+
nodes.append(cy_support_node)
104+
edges.extend([cy_support_edge, cy_edge])
105+
106+
add_to_elements(child, child_id)
107+
108+
col_positions = get_col_positions(tree)
109+
row_positions = get_row_positions(tree)
40110

41-
_add_to_elements(child, child_id)
111+
nodes = []
112+
edges = []
42113

43-
_add_to_elements(tree.clade, 0)
114+
add_to_elements(tree.clade, 'r')
44115

45-
return elements
116+
return nodes, edges
46117

47118

48119
# Define elements, stylesheet and layout
49120
tree = Phylo.read('data/apaf.xml', 'phyloxml')
50-
elements = generate_elements(tree)
121+
nodes, edges = generate_elements(tree)
122+
elements = nodes + edges
51123

52124
layout = {
53125
'name': 'breadthfirst',

0 commit comments

Comments
 (0)