forked from llimllib/pymag-trees
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreingold_addmod.py
136 lines (114 loc) · 3.5 KB
/
reingold_addmod.py
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from gen import Tree, gentree
from operator import lt, gt
from sys import stdout, maxint
minint = -maxint - 1
class DrawTree:
def __init__(self, tree, depth=-1):
self.x = -1
self.y = depth
self.tree = tree
self.children = []
self.thread = None
self.mod = 0
def left(self):
return self.thread or len(self.children) and self.children[0]
def right(self):
return self.thread or len(self.children) and self.children[-1]
#traverse to the bottom of the tree, and place the leaves at an arbitrary
# x coordinate
#if the node is a parent, draw its subtrees, then shift the right one as close
# to the left as possible
#place the parent in the middle of the two trees.
def layout(tree):
dt = reingold_tilford(tree)
return addmods(dt)
def addmods(tree, mod=0):
tree.x += mod
for c in tree.children:
addmods(c, mod+tree.mod)
return tree
def reingold_tilford(tree, depth=0):
dt = DrawTree(tree, depth)
if len(tree) == 0:
dt.x = 0
return dt
if len(tree) == 1:
dt.children = [reingold_tilford(tree[0], depth+1)]
dt.x = dt.children[0].x
return dt
left = reingold_tilford(tree[0], depth+1)
right = reingold_tilford(tree[1], depth+1)
dt.children = [left, right]
dt.x = fix_subtrees(left, right)
return dt
#place the right subtree as close to the left subtree as possible
def fix_subtrees(left, right):
li, ri, diff, loffset, roffset, lo, ro \
= contour(left, right)
diff += 1
diff += (right.x + diff + left.x) % 2 #stick to the integers
right.mod = diff
right.x += diff
if right.children:
roffset += diff
#right was deeper than left
if ri and not li:
lo.thread = ri
lo.mod = roffset - loffset
#left was deeper than right
elif li and not ri:
ro.thread = li
ro.mod = loffset - roffset
return (left.x + right.x) / 2
def contour(left,
right,
max_offset=None,
loffset=0,
roffset=0,
left_outer=None,
right_outer=None):
if not max_offset \
or left.x + loffset - (right.x + roffset) > max_offset:
max_offset = left.x + loffset - (right.x + roffset)
if not left_outer:
left_outer = left
if not right_outer:
right_outer = right
lo = left_outer.left()
li = left.right()
ri = right.left()
ro = right_outer.right()
if li and ri:
loffset += left.mod
roffset += right.mod
return contour(li, ri, max_offset, loffset, roffset, lo, ro)
return li, ri, max_offset, loffset, roffset, left_outer, right_outer
#given an array of nodes, print them out reasonably on one line
def printrow(level):
x = dict((t.x, t.tree) for t in level)
for i in range(max(x.keys())+1):
try: stdout.write(str(x[i])[:4])
except: stdout.write(" ")
def p(tree):
level = [tree]
while 1:
newlevel = []
printrow(level)
for t in level:
newlevel.extend(t.children[:2])
print
if not newlevel: break
level = newlevel
if __name__ == "__main__":
def mirror(t):
if len(t.children) > 1:
t.children = (t.children[1], t.children[0])
for c in t.children:
mirror(c)
return t
from demo_trees import trees
layout(mirror(trees[10]))
#root = gentree("/Users/llimllib/Movies")
#root.children.reverse()
#drawtree = reingold_tilford(root)
#p(drawtree)