Nothing
# palette.R: functions for handling "box.palette" and related arguments.
# Predefined palettes. The Color Brewer palettes were used as a
# starting point for these palettes, with manual interpolation to bring
# the number of colors per palette to nine.
# The darkest color in each palette is still fairly light
# so black text on it can be easily read.
Grays <- gray(seq(1, .6, length.out=9))
Greys <- Grays # british spelling
Greens <- c("#F7FCF5", "#EEF8EA", "#E5F5E0", "#D6EFD0", "#C7E9C0", "#B4E1AD", "#A1D99B", "#8ACE88", "#74C476")
Blues <- c("#F7FBFF", "#EAF3FB", "#DEEBF7", "#D2E3F3", "#C6DBEF", "#B2D2E8", "#9ECAE1", "#84BCDB", "#6BAED6")
Browns <- hsv(h=0.06, s=seq(from=0, to=.6, length.out=9), v=seq(from=1, to=.85, length.out=9))
Oranges <- c("#FFF5EB", "#FEEDDC", "#FEE6CE", "#FDDBB8", "#FDD0A2", "#FDBF86", "#FDAE6B", "#FD9D53", "#FD8D3C")
Reds <- c("#FFF5F0", "#FEEAE1", "#FEE0D2", "#FDCDB9", "#FCBBA1", "#FCA689", "#FC9272", "#FB7E5E", "#FB6A4A")
Purples <- c("#FFFBFF", "#FFF4FF", "#FFEDFF", "#FFE3FF", "#FFDAFF", "#FFCBFF", "#FFBDFF", "#FFABFF", "#FF9AFF")
Gy <- Grays # alternate names for the above palettes
Gn <- Greens
Bu <- Blues
Bn <- Browns
Or <- Oranges
Rd <- Reds
Pu <- Purples
RdYlGn <- lighten(rainbow(100, end=.36), .2) # three color palettes
GnYlRd <- rev(RdYlGn)
# got by library(viridis); viridis(16) and dropping the seven darkest colors
BlGnYl <- c("#23888E", "#1F988B", "#22A884", "#35B779", "#54C568", "#7AD151", "#A5DB36", "#D2E21B", "#FDE725")
YlGnBl <- rev(BlGnYl)
# two-color diverging palettes
ICOL <- seq(from=3, to=length(Blues), by=1) # start at 3 to avoid near-whites
RICOL <- rev(ICOL)
GyGy <- c(Gy[RICOL], Gy[ICOL])
GyGn <- c(Gy[RICOL], Gn[ICOL])
GyBu <- c(Gy[RICOL], Bu[ICOL])
GyBn <- c(Gy[RICOL], Bn[ICOL])
GyOr <- c(Gy[RICOL], Or[ICOL])
GyRd <- c(Gy[RICOL], Rd[ICOL])
GyPu <- c(Gy[RICOL], Pu[ICOL])
BuGy <- c(Bu[RICOL], Gy[ICOL])
BuGn <- c(Bu[RICOL], Gn[ICOL])
BuBu <- c(Bu[RICOL], Bu[ICOL])
BuBn <- c(Bu[RICOL], Bn[ICOL])
BuOr <- c(Bu[RICOL], Or[ICOL])
BuRd <- c(Bu[RICOL], Rd[ICOL])
BuPu <- c(Bu[RICOL], Pu[ICOL])
BnGy <- c(Bn[RICOL], Gy[ICOL])
BnGn <- c(Bn[RICOL], Gn[ICOL])
BnBu <- c(Bn[RICOL], Bu[ICOL])
BnBn <- c(Bn[RICOL], Bn[ICOL])
BnOr <- c(Bn[RICOL], Or[ICOL])
BnRd <- c(Bn[RICOL], Rd[ICOL])
BnPu <- c(Bn[RICOL], Pu[ICOL])
GnGy <- c(Gn[RICOL], Gy[ICOL])
GnGn <- c(Gn[RICOL], Gn[ICOL])
GnBu <- c(Gn[RICOL], Bu[ICOL])
GnBn <- c(Gn[RICOL], Bn[ICOL])
GnOr <- c(Gn[RICOL], Or[ICOL])
GnRd <- c(Gn[RICOL], Rd[ICOL])
GnPu <- c(Gn[RICOL], Pu[ICOL])
OrGy <- c(Or[RICOL], Gy[ICOL])
OrGn <- c(Or[RICOL], Gn[ICOL])
OrBu <- c(Or[RICOL], Bu[ICOL])
OrBn <- c(Or[RICOL], Bn[ICOL])
OrOr <- c(Or[RICOL], Or[ICOL])
OrRd <- c(Or[RICOL], Rd[ICOL])
OrPu <- c(Or[RICOL], Pu[ICOL])
PuGy <- c(Pu[RICOL], Gy[ICOL])
PuGn <- c(Pu[RICOL], Gn[ICOL])
PuBu <- c(Pu[RICOL], Bu[ICOL])
PuBn <- c(Pu[RICOL], Bn[ICOL])
PuOr <- c(Pu[RICOL], Or[ICOL])
PuRd <- c(Pu[RICOL], Rd[ICOL])
PuPu <- c(Pu[RICOL], Pu[ICOL])
RdGy <- c(Rd[RICOL], Gy[ICOL])
RdGn <- c(Rd[RICOL], Gn[ICOL])
RdBu <- c(Rd[RICOL], Bu[ICOL])
RdBn <- c(Rd[RICOL], Bn[ICOL])
RdOr <- c(Rd[RICOL], Or[ICOL])
RdRd <- c(Rd[RICOL], Rd[ICOL])
RdPu <- c(Rd[RICOL], Pu[ICOL])
remove(ICOL)
remove(RICOL)
predefined.palette.names <- c("AUTO",
"Grays", "Greys", "Greens", "Blues", "Browns", "Oranges", "Reds", "Purples",
"Gy", "Gn", "Bu", "Bn", "Or", "Rd", "Pu",
"RdYlGn", "GnYlRd", "BlGnYl","YlGnBl",
"GyGy", "GyGn", "GyBu", "GyBn", "GyOr", "GyRd", "GyPu",
"GnGy", "GnGn", "GnBu", "GnBn", "GnOr", "GnRd", "GnPu",
"BuGy", "BuGn", "BuBu", "BuBn", "BuOr", "BuRd", "BuPu",
"BnGy", "BnGn", "BnBu", "BnBn", "BnOr", "BnRd", "BnPu",
"OrGy", "OrGn", "OrBu", "OrBn", "OrOr", "OrRd", "OrPu",
"PuGy", "PuGn", "PuBu", "PuBn", "PuOr", "PuRd", "PuPu",
"RdGy", "RdGn", "RdBu", "RdBn", "RdOr", "RdRd", "RdPu")
predefined.palettes.msg <- paste0(
"Try something like box.palette=\"blue\" or box.palette=\"Blues\".\n",
"The predefined palettes are (with an optional \"-\" prefix):\n",
" Grays Greys Greens Blues Browns Oranges Reds Purples\n",
" Gy Gn Bu Bn Or Rd Pu (alternative names for the above palettes)\n",
" BuGn BuBn GnRd etc. (two-color diverging palettes: any combination of two palettes)\n",
" RdYlGn GnYlRd BlGnYl YlGnBl (three color palettes)\n")
is.predefined.palette <- function(pal)
{
is.character(pal) &&
length(pal) == 1 &&
nzchar(pal) &&
(grepl("[A-Z]", substr(pal, 1, 1), ignore.case=FALSE) || # upper case first letter
substr(pal, 1, 1) == "-") # or first letter is "-"
}
# This can deal with the following examples:
# pal = "auto" (becomes default.pal)
# pal = "Reds" (becomes the vector of colors defined by Reds)
# pal = c("tan1", "tan2", "tan3") (no change)
# pal = c("-Reds", "Blues")
# pal = c("tan3", "tan2", "tan1", "Blues")
# pal = c("auto", "-Reds")
expand.palette <- function(pal, default.pal)
{
argname <- deparse(substitute(pal))
original.pal <- pal
pal <- NULL
for(i in seq_along(original.pal)) {
pal_i <- original.pal[i]
if(is.auto(pal_i)) # need upper case first letter for is.predefined.palette
pal_i <- if(substr(pal_i, 1, 1) == "-") "-AUTO" else "AUTO"
if(is.predefined.palette(pal_i)) {
# pal_i is a predefined palette, does it begin with "-"?
rev <- FALSE
if(substr(pal_i, 1, 1) == "-") {
rev <- TRUE
pal_i = substring(pal_i, 2) # discard "-"
}
pal_i <- match.choices(pal_i, predefined.palette.names,
argname="box.palette",
errmsg=predefined.palettes.msg)
if(is.auto(pal_i))
pal_i <- default.pal
pal_i <- getFromNamespace(pal_i, "rpart.plot")
if(rev)
pal_i <- rev(pal_i)
}
pal <- c(pal, pal_i)
}
# check that all elements of pal are in fact colors
if(length(pal) == 0)
stop0(argname, ": palette length is zero")
for(i in seq_along(pal)) {
pal_i <- pal[i]
if(is.null(pal_i))
stop0(argname,
": NULL is neither a color nor a palette.\n",
predefined.palettes.msg)
try <- try(col2rgb(pal_i), silent=TRUE)
if(is.try.err(try))
stop0(argname, ": ",
if(is.character(pal_i[1])) quotify(pal_i)
else pal_i,
" is neither a color nor a palette.\n",
predefined.palettes.msg)
}
pal
}
# TRUE if pal is a two-color diverging palette like GnBu.
#
# Not completely reliable, but works for the predefined
# palettes (except for BnOr and BnRd)
#
# Assume diverging if both the following are true:
# 1. the hues in the first half are quite different from the second half
# 2. the first and last hue in the first half are similar
# where "first half" means the colors in the first half of the pal vector.
is.diverging <- function(pal, trace)
{
if(length(pal) == 1)
return(FALSE)
if(length(pal) == 2) # two color palettes are always considered as diverging
return(TRUE)
hue <- rgb2hsv(col2rgb(pal))[1,] # extract hue
n2 <- floor(length(hue) / 2)
mean1 <- mean(hue[1:n2])
mean2 <- mean(hue[(n2+1):length(hue)])
# max(sd) below is necessary for grays where sd(hue)==0
crit1 <- abs(mean1 - mean2) / max(.02, sd(hue))
crit2 <- abs(hue[1] - hue[n2])
if(trace >= 3)
printf("is.diverging: mean1 %g mean2 %g sd(hue) %g crit1 %g (%s) crit2 %g (%s)\n",
mean1, mean2, sd(hue),
crit1, if(crit1 > 1.5) "diverging" else "not diverging",
crit2, if(crit2 < .1) "diverging" else "not diverging")
crit1 > 1.5 && crit2 < .1
}
# Return an index vector with elements with values in the range 1 to nquantiles.
# Each element indicates the quantile of the corresponding element in fitted.
# The returned index vector is intended to be used as in index into a color palette.
quantile_index <- function(fitted, pal.halflen, trace)
{
# length(fitted)==0 if called from get.col.from.diverging.palette
# and no fitted > pal.thresh
if(length(fitted) == 0 || pal.halflen == 1)
return(1)
fitted.nona <- fitted
if(anyNA(fitted)) {
trace1(trace, "fitted[%d] is NA\n", which(is.na(fitted))[1])
fitted.nona[is.na(fitted)] <- min(fitted, na.rm=TRUE)
}
q <- quantile(fitted.nona, # e.g. pal.halflen=2 means q=c(0, .5, 1)
probs=seq(0, 1, length.out=pal.halflen+1), na.rm=TRUE)
q <- q[2:length(q)] # e.g. pal.halflen=2 means q is now c(.5, 1)
quantile_index <- rep(NA, times=length(fitted.nona))
# TODO could be vectorized?
for(ifitted in 1:length(fitted.nona))
for(iq in 1:length(q)) {
if(fitted.nona[ifitted] <= q[iq]) {
quantile_index[ifitted] <- iq
break
}
}
quantile_index[is.na(fitted)] <- NA
quantile_index
}
# Returns box colors (like palette[quantile_index]) but values in fitted
# below pal.thresh take colors in the first half of palette; values above
# pal.thresh take colors in the second half of palette.
# For example, with palette=BuGn, fitted values below pal.thresh=.5
# will be blue and values above .5 will be green.
get.col.from.diverging.palette <- function(fitted, pal, trace, box.palette, pal.thresh)
{
if(anyNA(fitted)) # TODO fix this
stop0("Diverging palettes like box.palette=\"",
if(box.palette == "auto" || box.palette == "-auto") "BuGn"
else box.palette,
"\" cannot be used for this model\n",
" because there are NAs in the fitted values.\n",
" Try something like box.palette=\"Blues\"")
index1 <- quantile_index(fitted[fitted <= pal.thresh], length(pal)/2, trace)
index2 <- quantile_index(fitted[fitted > pal.thresh], length(pal)/2, trace)
index <- rep(NA, times=length(fitted))
index[fitted <= pal.thresh] <- index1
index[fitted > pal.thresh] <- index2 + length(pal) / 2
index[is.na(fitted)] <- NA
pal[index]
}
print_palette <- function(pal)
{
if(length(pal) > 20)
printf(" %d colors from %s to %s\n",
length(pal), describe.col(pal[1]), describe.col(pal[length(pal)]))
else for(i in 1:length(pal))
printf(" %s\n", describe.col(pal[i]))
}
handle.anova.palette <- function(obj, box.palette, trace,
fitted, pal.thresh,
default.pal="Blues")
{
original.pal <- box.palette
pal <- expand.palette(box.palette, default.pal)
if(trace >= 2)
printf("handle.anova.palette\n")
diverging <- is.diverging(pal, trace)
if(trace >= 1)
printf("box.palette %s(%s): %s to %s\n",
if(is.predefined.palette(original.pal))
sprint("\"%s\" ", original.pal)
else
"",
if(diverging)
sprint("diverging pal.thresh %g", pal.thresh)
else
"not diverging",
describe.col(pal[1], show.hex=FALSE),
describe.col(pal[length(pal)], show.hex=FALSE))
if(trace >= 3) {
printf("expanded box.palette:\n")
print_palette(pal)
}
list(box.col=if(diverging)
get.col.from.diverging.palette(fitted,
pal, trace, box.palette, pal.thresh)
else
pal[quantile_index(fitted, length(pal), trace)],
box.palette=pal)
}
# multiclass response, or two class response with box.palette=list
handle.multiclass.palette <- function(obj, box.palette, trace, class.stats)
{
must.reverse <- FALSE
used.classes <- unique(sort(class.stats$fitted, na.last=TRUE))
if(is.auto(box.palette)) {
must.reverse <- substr(box.palette[1], 1, 1) == "-"
# palette chosen below so if factor is ordered colors make sense
box.palette <-
switch(min(length(used.classes), 6),
list(Greens), # comat with anova model # 1
list(Blues, Greens), # compat with binary model (BuGn) # 2
list(Reds, Grays, Greens), # 3
list(Reds, Oranges, Grays, Greens), # 4
list(Reds, Oranges, Grays, Blues, Greens), # 5
list(Reds, Oranges, Purples, Grays, Blues, Greens)) # 6 or more
if(trace >= 1)
printf("multiclass auto box.palette: %s\n",
switch(min(length(used.classes), 6),
"list(Greens)", # 1
"list(Blues, Greens)", # 2
"list(Reds, Grays, Greens)", # 3
"list(Reds, Oranges, Grays, Greens)", # 4
"list(Reds, Oranges, Grays, Blues, Greens)", # 5
"list(Reds, Oranges, Purples, Grays, Blues, Greens)")) # 6 or more
}
if(length(box.palette) == 1) { # allow the user to specify a single color or palette
# how many uppercase letters in box.palette? e.g. Blues is 1, GnBu is 2
nuppercase <- length(gregexpr("[A-Z]", box.palette)[[1]])
if(nuppercase <= 1) # single color?
box.palette <- as.list(repl(box.palette, length(used.classes)))
else { # multiple colors: divide up the colors among the used.classes
cols <- expand.palette(box.palette, "Undefined")
if(length(cols) < length(used.classes))
cols <- repl(cols, length(used.classes))
nper <- length(cols) / length(used.classes)
box.palette <- list()
for(i in 0:(length(used.classes)-1))
box.palette[[i+1]] <- cols[floor(i*nper+1):floor(i*nper+nper)]
}
}
if(!is.list(box.palette))
stop0(
"The rpart model has a multiclass response (not a continuous or binary response).\n",
"Therefore box.palette must be \"auto\",\n",
" or a list of colors or palettes,\n",
" or a single color or palette.\n",
"e.g. box.palette=list(\"pink\", \"lightblue\", \"lightgray\")\n",
"e.g. box.palette=list(\"Reds\", \"Oranges\", \"Grays\", \"Blues\", \"Greens\")")
for(i in 1:length(box.palette))
box.palette[[i]] <- expand.palette(box.palette[[i]], "Undefined")
if(trace >= 3) {
printf("multiclass box.palette:\n")
for(i in 1:length(box.palette)) {
printf("box.palette[[%d]]:\n", i)
print_palette(box.palette[[i]])
}
}
warning.issued <- FALSE
if(class.stats$nlev > length(box.palette)) {
if(length(used.classes) > length(box.palette)) {
if(trace >= 0) {
warning.issued <- TRUE
warning0(
"All boxes will be white (the box.palette argument will be ignored) because\n",
"the number of classes in the response ", class.stats$nlev,
" is greater than length(box.palette) ",
length(box.palette), ".\n",
"To silence this warning use box.palette=0 or trace=-1.")
}
return(list(box.col=get.bg()))
} else {
if(trace >= 0) {
NULL
# warning.issued <- TRUE
# warning0(
# "The box colors are not exactly those specified in box.palette.\n",
# "The box palettes have been reassigned because the number ",
# class.stats$nlev, "\n",
# "of response classes is greater than length(box.palette) ",
# length(box.palette), ".\n",
# "(However only 4 classes are predicted by the model, therefore there are enough\n",
# "palettes in box.palette for a unique color per class after reassigning the palettes.)\n",
# "To silence this warning use box.palette=0 or trace=-1.")
}
}
}
box.palette <- box.palette[1:min(length(box.palette), length(used.classes))]
if(must.reverse)
box.palette <- rev(box.palette)
if(trace >= 2 || warning.issued) {
# show how colors are assigned to predicted classes
ylevel <- attr(obj, "ylevels")
ylevel <- if(is.null(ylevel)) as.character(ylevel) else ylevel
max <- max(nchar(paste(ylevel[used.classes])))
# sformat will be something like "box.col %-7.7s: %s\n"
if(warning.issued)
printf("\n")
sformat <- sprint("%sbox.col %%-%d.%ds: %%s\n",
if(warning.issued) " " else "", max, max)
for(i in 1:length(used.classes))
printf(sformat, paste(ylevel[used.classes[i]]),
describe.col(box.palette[[i]][length(box.palette[[i]])]))
}
match <- match(class.stats$fitted, used.classes)
box.col <- repl(NA, length(class.stats$fitted))
first.time <- TRUE
max.prob.for.class <- apply(class.stats$prob.per.lev, 2, max)
for(i in 1:length(box.col)) { # paranoia
ilist <- match[i]
if(ilist > length(box.palette)) {
box.col[i] <- "white" # more used classes than elements in box.palette
if(first.time && trace >= 0)
warning0(
"Internal error: some boxes are colored white\n",
"because there are more than ", length(box.palette),
" predicted classes ",
"but length(box.palette) is ", length(box.palette), "\n",
"To silence this warning use box.palette=0 or trace=-1")
first.time <- FALSE
} else {
pal <- box.palette[[ilist]]
highest.prob <- class.stats$prob.per.lev[i,class.stats$fitted[i]] /
max.prob.for.class[class.stats$fitted[i]]
# highest prob is a fraction from 0 to 1
# convert to an index from 1 to length(pal)
box.col[i] <- pal[1 + highest.prob * (length(pal)-1)]
}
}
list(box.col=box.col, box.palette=box.palette)
}
# Possibly add a legend (only for multi-class-response models)
possible.palette.legend <- function(ret, class.stats, box.col, box.palette,
legend.x, legend.y, legend.cex, tweak, trace)
{
if(!is.specified(box.palette[1]) || all(box.palette == get.bg()))
return()
if(!is.null(legend.x[1]) && is.na(legend.x[1]))
return()
if(!is.null(legend.y[1]) && is.na(legend.y[1]))
return()
obj <- ret$obj
if(obj$method != "class")
return()
if(class.stats$nlev <= 2)
return()
# get here if multi-level-response model with a list box.palette
# same as code in handle.multiclass.palette
used.classes <- 1:class.stats$nlev
if(class.stats$nlev > length(box.palette))
used.classes <- unique(sort(class.stats$fitted, na.last=TRUE))
nlegend <- length(class.stats$ylevels)
# box.palette is a list of vecs, we select one color from each vector
legend.col <- select.legend.col(box.palette)
if(is.na(legend.col[1]))
return() # all legend colors the same, no legend
# set legend to names of all classes (if class never predicted then append "unused")
# also set col to appropriate class colors (if class unpredicted then bg color)
col <- character(length=nlegend)
legend <- character(length=nlegend)
iclass <- 1
for(i in 1:nlegend) {
if(i %in% used.classes) {
legend[i] <- attr(obj, "ylevels")[i]
col[i] <- legend.col[iclass]
iclass <- iclass + 1
} else {
legend[i] <- paste0(attr(obj, "ylevels")[i], " (unused)")
col[i] <- get.bg()
}
}
x <- legend.x
if(is.null(x)) { # auto horizontal position?
x <- if(ret$x[1] > .5) ret$xlim[1] # left side
else ret$xlim[2] - .2 * (ret$xlim[2] - ret$xlim[1]) # right side
# May 2018: removed this because it's probably best to always display
# the legend even if there is some overwriting
#
# # check that there is space for the legend
# xedge <-
# if(!is.na(ret$boxes$x1[1]) # top node box exists? (depends on prp's type arg)
# ret$boxes$x1[1] # top node left edge
# else # else use top branch position
# ret$branch.x[1,1]
# if(1.4 * max(strwidth(legend)) > xedge) # not enough horizontal space?
# return()
}
y <- legend.y
if(is.null(y)) # auto vertical position? estimate from height of legend
y <- ret$y[1] + min(5, 1 + length(legend)) * strheight("X")
# legend.skip.unpredicted <- TRUE
# if(legend.skip.unpredicted) {
# legend <- legend[used.classes]
# col <- col[used.classes]
# }
if(trace >= 1)
printf("legend.x %g legend.y %g\n", x, y)
legend(x=x, y=y, legend=legend,
col=0, xpd=NA, bty="n", cex=tweak * legend.cex * min(1.1 * ret$cex, 1),
border=0, fill=col)
}
select.legend.col <- function(box.palette)
{
select.col <- function(cols)
{
hsv <- rgb2hsv(col2rgb(cols))
# sort first on the lowest value (lowest brightness), then on most saturated
order <- order(hsv["v",], 1 - hsv["s",])
cols[order[1]]
}
#--- select.legend.col starts here ---
legend.col <- sapply(box.palette, select.col)
# check if all legend colors are the same (e.g. box.color="Blues")
if(all(legend.col == legend.col[1]))
legend.col <- NA # all legend colors the same, no legend
legend.col
}
get.palette.fitted <- function(default.fitted, node.labs, pal.node.fun, trace)
{
fitted <- default.fitted
if(pal.node.fun) {
# extract first number in each label, if possible
# two regexs separated by | below, first handles numbers with digits before
# the point (if any), second handle numbers without digits before the point
regex <- "-?[0-9]+\\.?[0-9]*e?-?[0-9]*|-?\\.[0-9]+e?-?[0-9]*"
m <- regexpr(regex, node.labs)
labs <- regmatches(node.labs, m)
labs[m == -1] <- NA # m==-1 for entries in node.labs which don't match regex
# convert warning to errors (because silent=TRUE doesn't work for warnings)
old.warn <- getOption("warn")
on.exit(options(warn=old.warn))
options(warn=2)
fitted <- try(as.numeric(labs), silent=TRUE)
options(warn=old.warn)
if(trace >= 2)
cat("as.numeric(node.labs):", fitted, "\n")
if(is.try.err(fitted) || anyNA(fitted)) {
cat("\nnode labs generated by node.fun:\n")
print(node.labs)
cat("\n")
stop0("Cannot convert node labs to numeric\n",
"To silence this error, change node.fun or use pal.node.fun=FALSE")
}
}
fitted
}
# like median but if median is largest or smallest value in x then adjust it
# (so e.g. for diverging palettes we use at least one divergent color)
smart.median <- function(x)
{
median <- median(x, na.rm=TRUE)
sort <- sort_unique(x)
len <- length(sort)
if(len >= 2) {
if(median == sort[1])
median <- (sort[1] + sort[2]) / 2
else if(median == sort[len])
median <- (sort[len] + sort[len-1]) / 2
}
median
}
# invoked if box.palette is specified (including when box.palette="auto")
handle.box.palette <- function(obj, box.palette, trace, class.stats, node.labs,
pal.thresh, # if not specified then auto
node.fun.name, pal.node.fun)
{
get.pal.thresh <- function(default.pal.thresh)
{
check.numeric.scalar(pal.thresh, na.ok=TRUE, null.ok=TRUE)
if(is.null(pal.thresh) || is.na(pal.thresh))
default.pal.thresh
else
pal.thresh
}
#--- handle.box.palette starts here ---
# return list(box.col, box.palette) where box.palette is the expanded box.palette
# if statements below matches code in internal.node.labs() in node.labs.R
pal.node.fun <-
pal.node.fun && !identical(node.fun.name, "NULL")
if(obj$method %in% c("poisson", "exp")) {
fitted <- get.palette.fitted(obj$frame$yval2[,1], # rate
node.labs, pal.node.fun, trace)
handle.anova.palette(obj, box.palette, trace, fitted,
get.pal.thresh(smart.median(fitted)))
} else if(obj$method == "mrt") {
fitted <- get.palette.fitted(apply(obj$frame$yval2, 1, which.max),
node.labs, pal.node.fun, trace)
handle.anova.palette(obj, box.palette, trace, fitted,
get.pal.thresh(smart.median(fitted)))
} else if(obj$method == "anova" || is_numeric_response(obj)) {
fitted <- get.palette.fitted(obj$frame$yval,
node.labs, pal.node.fun, trace)
handle.anova.palette(obj, box.palette, trace, fitted,
get.pal.thresh(smart.median(fitted)))
} else if(obj$method == "class" || is.class.response(obj)) {
if(class.stats$nlev != 2 || is.list(box.palette)) {
if(trace >= 2)
printf("handle.box.palette for class response invokes handle.multiclass.palette\n")
# multiclass response, or two class response with box.palette=list
# (here we ignore pal.thresh and pal.node.fun)
handle.multiclass.palette(obj, box.palette, trace, class.stats)
} else {
# binomial model (two class response)
# (note that we use BuGn although rattle::fancyRpartPlot uses GnBu
# because we want to be compatible with 2-used-class multiclass model,
# see handle.multiclass.palette)
fitted <- get.palette.fitted(class.stats$fitted,
node.labs, pal.node.fun, trace)
pal.thresh <-
get.pal.thresh(
if(pal.node.fun) smart.median(fitted) else .5)
if(trace >= 2)
printf("handle.box.palette for class response invokes ")
handle.anova.palette(obj, box.palette, trace,
fitted=get.palette.fitted(class.stats$prob.per.lev[,2],
node.labs, pal.node.fun, trace),
pal.thresh, default.pal="BuGn")
}
} else # unrecognized response, can probably never get here
list(box.col=get.bg(), box.palette=get.bg())
}
# handle the box.col and box.palette arguments possibly specified by the user
handle.box.palette.args <- function(obj, trace, box.col, box.palette,
pal.thresh, # if not specified then auto
pal.node.fun,
node.fun.name, class.stats, node.labs)
{
retval <- list(box.col=box.col, box.palette=box.palette)
bg <- get.bg() # never returns NA or 0
# ignore box.palette if box.col is specified
if(is.specified(box.col) || !is.specified(box.palette))
retval$box.palette <- bg
else # convert box.palette to box.col and expand box.palette
retval <- handle.box.palette(obj, box.palette, trace, class.stats, node.labs,
pal.thresh, node.fun.name, pal.node.fun)
# convert zeroes in box.col to bg, but retain NAs
is.na.box.col <- is.na(box.col)
retval$box.col <- set.zero.to.bg(retval$box.col, bg)
retval$box.col[is.na.box.col] <- NA
retval # return list(box.col, box.palette)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.