Jim Lemon píše v Pá 17. 01. 2014 v 13:21 +1100: > On 01/17/2014 10:59 AM, Marc Schwartz wrote: > > > > ... > > Arggh. > > > > No, this is my error for not actually looking at the plot and presuming > > that it would work. > > > > Turns out that it does work for a non-stacked barplot: > > > > barplot(VADeaths, angle = 1:20 * 10, density = 10, beside = TRUE) > > > > However, internally within barplot(), actually barplot.default(), the > > manner in which the matrix is passed to an internal function called > > xyrect() to draw the segments, is that entire columns are passed, rather > > than the individual segments (counts), when the bars are stacked. > > > > As a result, due to the vector based approach used, only the first 5 values > > of 'angle' are actually used, since there are 5 columns, rather than all > > 20. The same impact will be observed when using the default legend that is > > created. > > > > Thus, I don't believe that there will be an easy (non kludgy) way to do > > what you want, at least with the default barplot() function. > > > > You could fairly easily create/build your own function using ?rect, which > > is what barplot() uses to draw the segments. I am not sure if lattice based > > graphics can do this or perhaps using Hadley's ggplot based approach would > > offer a possibility. > > > > Apologies for the confusion. > > > > Regards, > > > > Marc > > > Hi Marc and Martin, > When I saw the original message I tried to look at the code for the > barplot function to see if I could call the rectFill function from > plotrix into it. Unfortunately barplot is one of those "internal" > functions that are not at all easy to hack and I have never gotten > around to adding stacked bars to the barp function. I thought that > rectFill would allow you to use more easily discriminated fills than > angles that only differed by 18 degrees. > > Jim
Hi, after Marc pointed me out where to look for, I hacked barplot.default a bit, so now it does what I want (I added "segmentwise" argument). Unfortunately, it works well with segmentwise = TRUE, but not with segmentwise = FALSE (default) With segmentwise = FALSE, density argument works only in 1/n-th of the segments, where n is the number of columns (it seems like it refuses to auto-multiplicate, but I do not know why). Any ideas? Martin Here is my hack of barplot: my.barplot<- function (height, width = 1, space = NULL, names.arg = NULL, legend.text = NULL, beside = FALSE, horiz = FALSE, density = NULL, angle = 45, col = NULL, border = par("fg"), main = NULL, sub = NULL, xlab = NULL, ylab = NULL, xlim = NULL, ylim = NULL, xpd = TRUE, log = "", axes = TRUE, axisnames = TRUE, cex.axis = par("cex.axis"), cex.names = par("cex.axis"), inside = TRUE, plot = TRUE, axis.lty = 0, offset = 0, add = FALSE, args.legend = NULL, segmentwise = FALSE, ...) { if (!missing(inside)) .NotYetUsed("inside", error = FALSE) if (is.null(space)) space <- if (is.matrix(height) && beside) c(0, 1) else 0.2 space <- space * mean(width) if (plot && axisnames && is.null(names.arg)) names.arg <- if (is.matrix(height)) colnames(height) else names(height) if (is.vector(height) || (is.array(height) && (length(dim(height)) == 1))) { height <- cbind(height) beside <- TRUE if (is.null(col)) col <- "grey" } else if (is.matrix(height)) { if (is.null(col)) col <- gray.colors(nrow(height)) } else stop("'height' must be a vector or a matrix") if (is.logical(legend.text)) legend.text <- if (legend.text && is.matrix(height)) rownames(height) stopifnot(is.character(log)) logx <- logy <- FALSE if (log != "") { logx <- length(grep("x", log)) > 0L logy <- length(grep("y", log)) > 0L } if ((logx || logy) && !is.null(density)) stop("Cannot use shading lines in bars when log scale is used") NR <- nrow(height) NC <- ncol(height) if (beside) { if (length(space) == 2) space <- rep.int(c(space[2L], rep.int(space[1L], NR - 1)), NC) width <- rep(width, length.out = NR) } else { width <- rep(width, length.out = NC) } offset <- rep(as.vector(offset), length.out = length(width)) delta <- width/2 w.r <- cumsum(space + width) w.m <- w.r - delta w.l <- w.m - delta log.dat <- (logx && horiz) || (logy && !horiz) if (log.dat) { if (min(height + offset, na.rm = TRUE) <= 0) stop("log scale error: at least one 'height + offset' value <= 0") if (logx && !is.null(xlim) && min(xlim) <= 0) stop("log scale error: 'xlim' <= 0") if (logy && !is.null(ylim) && min(ylim) <= 0) stop("log scale error: 'ylim' <= 0") rectbase <- if (logy && !horiz && !is.null(ylim)) ylim[1L] else if (logx && horiz && !is.null(xlim)) xlim[1L] else 0.9 * min(height, na.rm = TRUE) } else rectbase <- 0 if (!beside) height <- rbind(rectbase, apply(height, 2L, cumsum)) rAdj <- offset + (if (log.dat) 0.9 * height else -0.01 * height) delta <- width/2 w.r <- cumsum(space + width) w.m <- w.r - delta w.l <- w.m - delta if (horiz) { if (is.null(xlim)) xlim <- range(rAdj, height + offset, na.rm = TRUE) if (is.null(ylim)) ylim <- c(min(w.l), max(w.r)) } else { if (is.null(xlim)) xlim <- c(min(w.l), max(w.r)) if (is.null(ylim)) ylim <- range(rAdj, height + offset, na.rm = TRUE) } if (beside) w.m <- matrix(w.m, ncol = NC) if (plot) { dev.hold() opar <- if (horiz) par(xaxs = "i", xpd = xpd) else par(yaxs = "i", xpd = xpd) on.exit({ dev.flush() par(opar) }) if (!add) { plot.new() plot.window(xlim, ylim, log = log, ...) } xyrect <- function(x1, y1, x2, y2, horizontal = TRUE, ...) { if (horizontal) rect(x1, y1, x2, y2, ...) else rect(y1, x1, y2, x2, ...) } if(segmentwise){ arg.lengths <- c(length(angle), length(density), length(col), length(border)) angle <- rep(angle, max(arg.lengths)/arg.lengths[1]) density <- rep(density, max(arg.lengths)/arg.lengths[2]) col <- rep(col, max(arg.lengths)/arg.lengths[3]) border <- rep(border, max(arg.lengths)/arg.lengths[4]) } if (beside) xyrect(rectbase + offset, w.l, c(height) + offset, w.r, horizontal = horiz, angle = angle, density = density, col = col, border = border) else { for (i in 1L:NC) { xyrect(height[1L:NR, i] + offset[i], w.l[i], height[-1, i] + offset[i], w.r[i], horizontal = horiz, angle = angle[segmentwise * NR * (i-1)+(1L:NR)], density = density[segmentwise * NR * (i-1)+(1L:NR)], col = col[segmentwise * NR * (i-1)+(1L:NR)], border = border[segmentwise * NR * (i-1)+(1L:NR)]) } } if (axisnames && !is.null(names.arg)) { at.l <- if (length(names.arg) != length(w.m)) { if (length(names.arg) == NC) colMeans(w.m) else stop("incorrect number of names") } else w.m axis(if (horiz) 2 else 1, at = at.l, labels = names.arg, lty = axis.lty, cex.axis = cex.names, ...) } if (!is.null(legend.text)) { legend.col <- rep(col, length.out = length(legend.text)) if ((horiz & beside) || (!horiz & !beside)) { legend.text <- rev(legend.text) legend.col <- rev(legend.col) density <- rev(density) angle <- rev(angle) } xy <- par("usr") if (is.null(args.legend)) { legend(xy[2L] - xinch(0.1), xy[4L] - yinch(0.1), legend = legend.text, angle = angle, density = density, fill = legend.col, xjust = 1, yjust = 1) } else { args.legend1 <- list(x = xy[2L] - xinch(0.1), y = xy[4L] - yinch(0.1), legend = legend.text, angle = angle, density = density, fill = legend.col, xjust = 1, yjust = 1) args.legend1[names(args.legend)] <- args.legend do.call("legend", args.legend1) } } title(main = main, sub = sub, xlab = xlab, ylab = ylab, ...) if (axes) axis(if (horiz) 1 else 2, cex.axis = cex.axis, ...) invisible(w.m) } else w.m } ______________________________________________ R-help@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.