## Compute the x-y coordinates for a tree
rpartco <- function(tree, parms)
{
if (missing(parms)) {
pn <- paste0("device", dev.cur())
if (!exists(pn, envir = rpart_env, inherits = FALSE))
stop("no information available on parameters from previous call to plot()")
parms <- get(pn, envir = rpart_env, inherits = FALSE)
}
frame <- tree$frame
node <- as.numeric(row.names(frame))
depth <- tree.depth(node)
is.leaf <- (frame$var == "<leaf>")
if (length(parms)) {
uniform <- parms$uniform
nspace <- parms$nspace
minbranch <- parms$minbranch
} else {
uniform <- FALSE
nspace <- -1
minbranch <- 0.3
}
if (uniform)
y <- (1 + max(depth) - depth) / max(depth, 4L)
else { # make y- (parent y) = change in deviance
y <- dev <- frame$dev
temp <- split(seq(node), depth) #d epth 0 nodes, then 1, then ...
parent <- match(node %/% 2L, node)
sibling <- match(ifelse(node %% 2L, node - 1L, node + 1L), node)
## assign the depths
for (i in temp[-1L]) {
temp2 <- dev[parent[i]] - (dev[i] + dev[sibling[i]])
y[i] <- y[parent[i]] - temp2
}
##
## For some problems, classification & loss matrices in particular
## the gain from a split may be 0. This is ugly on the plot.
## Hence the "fudge" factor of 0.3 * the average step
##
fudge <- minbranch * diff(range(y)) / max(depth)
for (i in temp[-1L]) {
temp2 <- dev[parent[i]] - (dev[i] + dev[sibling[i]])
haskids <- !(is.leaf[i] & is.leaf[sibling[i]])
y[i] <- y[parent[i]] - ifelse(temp2 <= fudge & haskids, fudge, temp2)
}
y <- y / (max(y))
}
# Now compute the x coordinates, by spacing out the leaves and then
# filling in
x <- double(length(node)) # allocate, then fill it in below
x[is.leaf] <- seq(sum(is.leaf)) # leaves at 1, 2, 3, ....
left.child <- match(node * 2L, node)
right.child <- match(node * 2L + 1L, node)
## temp is a list of non-is.leaf, by depth
temp <- split(seq(node)[!is.leaf], depth[!is.leaf])
for (i in rev(temp))
x[i] <- 0.5 * (x[left.child[i]] + x[right.child[i]])
if (nspace < 0) return(list(x = x, y = y))
##
## Now we get fancy, and try to do overlapping
##
## The basic algorithm is, at each node:
## 1: get the left & right edges, by depth, for the left and
## right sons, of the x-coordinate spacing.
## 2: find the minimal free spacing. If this is >0, slide the
## right hand son over to the left
## 3: report the left & right extents of the new tree up to the
## parent
## A way to visualize steps 1 and 2 is to imagine, for a given node,
## that the left son, with all its descendants, is drawn on a
## slab of wood. The left & right edges, per level, give the
## width of this board. (The board is not a rectangle, it has
## 'stair step' edges). Do the same for the right son. Now
## insert some spacers, one per level, and slide right hand
## board over until they touch. Glue the boards and spacer
## together at that point.
##
## If a node has children, its 'space' is considered to extend left
## and right by the amount "nspace", which accounts for space
## used by the arcs from this node to its children. For
## horseshoe connections nspace usually is 1.
##
compress <- function(x, me, depth)
{
lson <- me + 1L
if (is.leaf[lson]) left <- list(left = x[lson], right = x[lson],
depth = depth + 1L, sons = lson)
else {
left <- compress(x, me + 1L, depth + 1L)
x <- left$x
}
rson <- me + 1L + length(left$sons) #index of right son
if (is.leaf[rson]) right <- list(left = x[rson], right = x[rson],
depth = depth + 1L, sons = rson)
else {
right <- compress(x, rson, depth + 1L)
x <- right$x
}
maxd <- max(left$depth, right$depth) - depth
mind <- min(left$depth, right$depth) - depth
## Find the smallest distance between the two subtrees
## But only over depths that they have in common
## 1 is a minimum distance allowed
slide <- min(right$left[1L:mind] - left$right[1L:mind]) - 1L
if (slide > 0) { # slide the right hand node to the left
x[right$sons] <- x[right$sons] - slide
x[me] <- (x[right$sons[1L]] + x[left$sons[1L]])/2
}
else slide <- 0
## report back
if (left$depth > right$depth) {
templ <- left$left
tempr <- left$right
tempr[1L:mind] <- pmax(tempr[1L:mind], right$right - slide)
} else {
templ <- right$left - slide
tempr <- right$right - slide
templ[1L:mind] <- pmin(templ[1L:mind], left$left)
}
list(x = x,
left = c(x[me] - nspace * (x[me] - x[lson]), templ),
right = c(x[me] - nspace * (x[me] - x[rson]), tempr),
depth = maxd + depth, sons = c(me, left$sons, right$sons))
}
x <- compress(x, 1L, 1L)$x
list(x = x, y = y)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.