[Rd] extending boxplot with space() argument?
Ben Bolker
bolker at zoo.ufl.edu
Thu Sep 11 12:39:55 MEST 2003
A student asked me if it was possible to draw boxplots where the boxes
themselves were grouped: I was able to hack boxplot.formula() to do the
right thing, more or less, by incorporating an argument (space) and some
code from barplot.
with the extended boxplot.formula() below, the following commands "do the
right thing" (produce boxes grouped by levels of the second factor):
r = runif(480)
f1 = gl(4,120)
f2 = gl(10,4,480)
boxplot(r ~ f1*f2,space=c(0.5,2),col=2:5)
I think this *might* be generally useful: for example, the last example
in example(boxplot) sets up a grouped boxplot by hand, plotting one group
with an offset and then the other. This would be much easier with my
hack. (I know we're in feature-freeze for 1.8.0 right now ... my usual
good timing.)
The one thing that makes this hack difficult/ugly is that all the
spacing calculations (e.g. if one specifies varwidth=TRUE) are handled in
the bxp() function: the calling sequence is boxplot -> boxplot.formula ->
boxplot.default -> bxp , so I had to replicate some of the spacing
calculations within boxplot.formula, which is ugly and incomplete. Can
anyone suggest an elegant way to deal with this?
------
"boxplot.formula" <-
function (formula, data = NULL, width=1,
space = 0.5, xlim=NULL, ylim=NULL,
horizontal = FALSE, at = NULL, log="",
boxwex=0.8,
add=FALSE, ..., subset)
{
if (missing(formula) || (length(formula) != 3))
stop("formula missing or incorrect")
m <- match.call(expand.dots = FALSE)
if (is.matrix(eval(m$data, parent.frame())))
m$data <- as.data.frame(data)
m$... <- m$space <- m$xlim <- m$ylim <- m$add <- m$horizontal <-
m$at <- m$log <- m$boxwex <- NULL
m[[1]] <- as.name("model.frame")
mf <- eval(m, parent.frame())
response <- attr(attr(mf, "terms"), "response")
## spacing code adapted from barplot()
f <- mf[-response]
f <- lapply(f,as.factor) ## just in case
dims <- sapply(lapply(f,levels),length)
n <- prod(dims)
width <- if (!is.null(width)) {
if (any(is.na(width)) | any(width <= 0))
stop("invalid boxplot widths")
boxwex * width/max(width)
}
width <- rep(width, length=n)
delta <- width/2
if (is.null(at)) {
if (length(space) == 2) {
space <- rep(c(space[2], rep(space[1], dims[1] - 1)),
dims[2]) }
w.r <- cumsum(space + width)
w.m <- w.r - delta
at=w.m
}
## ugly: have to replicate spacing/plotting code from
## bxp() here (since boxplot doesn't take xlim as a parameter)
if (is.null(xlim)) xlim <- range(at)+c(-delta[1],delta[length(delta)])
if (is.null(ylim)) ylim <- range(mf[[response]])
if (!add) {
plot.new()
if (horizontal)
plot.window(ylim = xlim, xlim = ylim, log = log)
else plot.window(xlim = xlim, ylim = ylim, log = log)
}
b <- boxplot(split(mf[[response]], f),at=at,
horizontal=horizontal, boxwex=boxwex,
add=TRUE, ...)
invisible(b)
}
--
620B Bartram Hall bolker at zoo.ufl.edu
Zoology Department, University of Florida http://www.zoo.ufl.edu/bolker
Box 118525 (ph) 352-392-5697
Gainesville, FL 32611-8525 (fax) 352-392-3704
More information about the R-devel
mailing list