-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathplotrecipe.jl
89 lines (80 loc) · 3.14 KB
/
plotrecipe.jl
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
function _treeplot(tree::Tree)
nodequeue = findroots(tree)
treesize = leafcount.(Ref(tree), nodequeue)
distances = distance.(Ref(tree), nodequeue)
countpct = treesize / sum(treesize)
left_pos = cumsum(countpct) .- (0.5 * countpct)
queueposition = 1
while(queueposition <= length(nodequeue))
@debug "Processing Node $(nodequeue[queueposition])"
children = childnodes(tree, nodequeue[queueposition])
@debug "Children Nodes = $children"
if length(children) > 0
append!(nodequeue, children)
# find the proportion of all leaf nodes contained the subtrees
subtreesize = max.(leafcount.(Ref(tree), children), 1)
@debug "Number of leaves per child = $subtreesize"
append!(countpct, subtreesize / sum(treesize))
@debug "Proportion of total leaves per child = $(round.(subtreesize / sum(treesize), digits=3))"
# calculate the positions
# 1a - find parent node postion
# 1b - find left-most leaf position of subtree
subtree_left = left_pos[queueposition] - 0.5 * countpct[queueposition]
@debug "Position of parent node = $(round(left_pos[queueposition], digits=3))"
@debug "Leftmost descendant leaf node position = $(round(subtree_left, digits=3))"
# 2a - find indices of children
c_ind = (length(countpct) - length(children) + 1):length(countpct)
@debug "Indices of children = $c_ind"
# 2b - find position relative to left of subtree
# 2c - use a cumulative sum based on leaf node count %
# 2d - adjust these cumulative-sum-based positions down to their midpoints
append!(left_pos, subtree_left .+ cumsum(countpct[c_ind]) .- 0.5 * countpct[c_ind])
@debug "Position of children = $(round.(left_pos[c_ind], digits=3))"
end
queueposition += 1
@debug "Increment queue position to $queueposition"
end
# distance from root + tree.height as node height/distance
heights = distance.(Ref(tree), nodequeue) .+ tree.height
if any(heights .== Inf)
error("Inf heights are not supported in plotting")
end
tree_x = Vector{Float64}[]
tree_y = Vector{Float64}[]
leaf_indices = Int64[]
node_ids = Int64[]
for i in eachindex(nodequeue)
if !isroot(tree, nodequeue[i])
pn_index = findfirst(parentnode(tree, nodequeue[i]) .== nodequeue)
push!(tree_x, heights[[i; pn_index; pn_index]])
push!(tree_y, left_pos[[i; i; pn_index]])
if isleaf(tree, nodequeue[i])
push!(leaf_indices, length(tree_y))
end
push!(node_ids, nodequeue[i])
end
end
return tree_x, tree_y, leaf_indices, node_ids
end
@recipe function plot(tree::Tree; plot_leaves = true, hover_ids = false)
tree_x, tree_y, leaf_indices, node_ids = _treeplot(tree)
yaxis := false
grid := :x
legend := false
@series begin
seriestype := :path
linecolor --> :black
tree_x, tree_y
end
if plot_leaves
@series begin
seriestype := :scatter
marker --> :diamond
markersize --> min(3, 100 * length(leaf_indices)^-1)
if hover_ids
hover := ["Node $x" for x in node_ids[leaf_indices]]
end
getindex.(tree_x[leaf_indices], 1), getindex.(tree_y[leaf_indices], 1)
end
end
end