This is an automated email from the git hooks/post-receive script. bob.dybian-guest pushed a commit to branch master in repository beeswarm.
commit 991436cea2cd2921ded8fcc2bad7d11bd7e9e3df Author: Dylan Aïssi <[email protected]> Date: Wed Jul 16 20:04:23 2014 +0200 Imported Upstream version 0.1.6 --- DESCRIPTION | 13 ++ MD5 | 11 ++ NAMESPACE | 8 ++ NEWS | 54 ++++++++ R/beeswarm.R | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ R/bxplot.R | 63 +++++++++ R/zzz.R | 1 + data/breast.RData | Bin 0 -> 6219 bytes man/beeswarm.Rd | 147 +++++++++++++++++++++ man/breast.Rd | 38 ++++++ man/bxplot.Rd | 73 +++++++++++ man/swarmx.Rd | 45 +++++++ 12 files changed, 831 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..fc14c55 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,13 @@ +Package: beeswarm +Version: 0.1.6 +Date: 2013-09-18 +Title: The bee swarm plot, an alternative to stripchart +Author: Aron Eklund +Maintainer: Aron Eklund <[email protected]> +Description: The bee swarm plot is a one-dimensional scatter plot like "stripchart", but with closely-packed, non-overlapping points. +License: Artistic-2.0 +URL: http://www.cbs.dtu.dk/~eklund/beeswarm/ +Packaged: 2013-09-20 13:50:51 UTC; aron +NeedsCompilation: no +Repository: CRAN +Date/Publication: 2013-09-20 16:39:35 diff --git a/MD5 b/MD5 new file mode 100644 index 0000000..ea0851d --- /dev/null +++ b/MD5 @@ -0,0 +1,11 @@ +4cef87738c855a220bd7e59bf77c8bf9 *DESCRIPTION +b641ad00a22a083cca208de1fb31b268 *NAMESPACE +6b1b075c2e8e5abbef4133bfc7938cb7 *NEWS +01e6fa4e1ec5d55b5c588df9a711a829 *R/beeswarm.R +643471dc2a194e0696ced4f40cd29f35 *R/bxplot.R +16cc12d2742742718c88949f18d5ac5d *R/zzz.R +bcf102fab14afb8d779c8c4148685174 *data/breast.RData +d6942ba25f56ac90174b92d2751056a6 *man/beeswarm.Rd +1ee38a2972fa0874a81c807e36dd22a6 *man/breast.Rd +d7097bb52220995656e837936b892d12 *man/bxplot.Rd +7fc0307d8fc01021340dd59121c0acf3 *man/swarmx.Rd diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..71c1a65 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,8 @@ + +export(beeswarm, bxplot, swarmx, swarmy) + +S3method(beeswarm, default) +S3method(beeswarm, formula) +S3method(bxplot, default) +S3method(bxplot, formula) + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..7369939 --- /dev/null +++ b/NEWS @@ -0,0 +1,54 @@ +beeswarm NEWS + +Changes in version 0.1.6 (2013-09-18) + +- The argument "labels" now gets recycled. +- "labels = NULL" is now the same as missing "labels"; i.e. labels are inferred from data. +- There is now a "width" argument to control the size of corrals, if corrals are used. + + +Changes in version 0.1.5 (2012-05-07) + +- Minor adjustments. + + +Changes in version 0.1.4 (2012-05-03) + +- Minor adjustments. + + +Changes in version 0.1.3 (2012-03-22) + +- New function "bxplot" as a minimal version of "boxplot", intended mainly as a way to add quantile lines to a beeswarm plot. +- "beeswarm" has a new argument "corral" to control the spread of swarms into adjacent groups. + + +Changes in version 0.1.2 (2012-03-14) + +- Documentation fixes +- Added a NAMESPACE file +- The formula interface now splits as expected for formulas such as: x ~ y * z + + +Changes in version 0.1.1 (2011-08-04) + +- Documentation fixes. +- Adjusted "beeswarm.default" to work when x is a simple numeric vector. +- Removed "beeswarm.numeric" . + + +Changes in version 0.1.0 (2011-08-03) + +- In "beeswarm", defaults for "col", "pch" are now taken from "par", and "bg" defaults to NA, and "pwbg" defaults to NULL. +- Renamed "smile" method; now it is called "swarm" +- Changed default method to "swarm" +- Removed function "smile" +- New functions "swarmx" and "swarmy" for easily adding swarm-ed points to a plot. +- Fixed bug affecting swarming when par('cex') was not 1. +- Fixed bug reversing xlim and ylim on horizontal plots. +- Fixed bug causing an error if xlim or ylim were set to NULL +- Defaults for xlim and ylim are now NULL instead of missing +- New argument 'dlim' +- Log scales are now supported. + + diff --git a/R/beeswarm.R b/R/beeswarm.R new file mode 100644 index 0000000..f6b2d47 --- /dev/null +++ b/R/beeswarm.R @@ -0,0 +1,378 @@ +# beeswarm.R +# +# Aron Charles Eklund +# +# A part of the "beeswarm" R package +# + + +beeswarm <- function (x, ...) + UseMethod("beeswarm") + + +## here x should be a list or data.frame or numeric +beeswarm.default <- function(x, + method = c("swarm", "center", "hex", "square"), + vertical = TRUE, horizontal = !vertical, + cex = 1, spacing = 1, breaks = NULL, + labels, at = NULL, + corral = c("none", "gutter", "wrap", "random", "omit"), + corralWidth, + pch = par("pch"), col = par("col"), bg = NA, + pwpch = NULL, pwcol = NULL, pwbg = NULL, + do.plot = TRUE, add = FALSE, log = FALSE, + xlim = NULL, ylim = NULL, dlim = NULL, glim = NULL, + xlab = NULL, ylab = NULL, dlab = "", glab = "", + ...) { + + method = match.arg(method) + corral = match.arg(corral) + if(length(cex) > 1) { + stop('the parameter "cex" must have length 1') + } + if(is.numeric(x)) { + x <- list(x) + } + + n.groups <- length(x) + + #### Resolve group labels + if(missing(labels) || is.null(labels)) { + if(is.null(names(x))) { + if(n.groups == 1) { + labels <- NA + } else { + labels <- 1:n.groups + } + } else { + labels <- names(x) + } + } else { + labels <- rep(labels, length.out = n.groups) + } + + if (is.null(at)) + at <- 1:n.groups + else if (length(at) != n.groups) + stop(gettextf("'at' must have length equal to %d, the number of groups", + n.groups), domain = NA) + + if (is.null(dlab)) + dlab <- deparse(substitute(x)) + + ## this function returns a "group" vector, to complement "unlist" + unlistGroup <- function(x, nms = names(x)) rep(nms, sapply(x, length)) + + x.val <- unlist(x) + x.gp <- unlistGroup(x, nms = labels) + if((range(x.val, finite = TRUE)[1] <= 0) && log) + warning('values <= 0 omitted from logarithmic plot') + + n.obs <- length(x.val) + n.obs.per.group <- sapply(x, length) + + #### Resolve xlim, ylim, dlim, xlab, ylab + if(is.null(dlim)) { + if(log) { + dlim <- 10 ^ (extendrange(log10(x.val[x.val > 0]))) + } else { + dlim <- extendrange(x.val, f = 0.01) + } + } + if(is.null(glim)) { + glim <- c(min(at) - 0.5, max(at) + 0.5) + } + if(horizontal) { + if(is.null(ylim)) + ylim <- glim + if(is.null(xlim)) { + xlim <- dlim + } else { + dlim <- xlim + } + if (is.null(xlab)) + xlab <- dlab + if (is.null(ylab)) + ylab <- glab + } else { ## vertical + if(is.null(xlim)) + xlim <- glim + if(is.null(ylim)) { + ylim <- dlim + } else { + dlim <- ylim + } + if (is.null(ylab)) + ylab <- dlab + if (is.null(xlab)) + xlab <- glab + } + + #### Resolve plotting characters and colors + if(is.null(pwpch)) { + pch.out <- unlistGroup(x, nms = rep(pch, length.out = n.groups)) + } else { + if(is.list(pwpch)) { + names(pwpch) <- names(x) + stopifnot(all(sapply(pwpch, length) == n.obs.per.group)) + pch.out <- unlist(pwpch) + } else { + pch.out <- pwpch + } + } + stopifnot(length(pch.out) == n.obs) + + if(is.null(pwcol)) { + col.out <- unlistGroup(x, nms = rep(col, length.out = n.groups)) + } else { + if(is.list(pwcol)) { + names(pwcol) <- names(x) + stopifnot(all(sapply(pwcol, length) == n.obs.per.group)) + col.out <- unlist(pwcol) + } else { + col.out <- pwcol + } + } + stopifnot(length(col.out) == n.obs) + + if(is.null(pwbg)) { + bg.out <- unlistGroup(x, nms = rep(bg, length.out = n.groups)) + } else { + if(is.list(pwbg)) { + names(pwbg) <- names(x) + stopifnot(all(sapply(pwbg, length) == n.obs.per.group)) + bg.out <- unlist(pwbg) + } else { + bg.out <- pwbg + } + } + stopifnot(length(bg.out) == n.obs) + + #### Set up the plot + if(do.plot & !add) { + plot(xlim, ylim, + type = 'n', axes = FALSE, + log = ifelse(log, ifelse(horizontal, 'x', 'y'), ''), + xlab = xlab, ylab = ylab, ...) + } + + #### Calculate the size of a plotting character along group- or data-axis + sizeMultiplier <- par('cex') * cex * spacing + if(horizontal) { + size.g <- yinch(0.08, warn.log = FALSE) * sizeMultiplier + size.d <- xinch(0.08, warn.log = FALSE) * sizeMultiplier + } else { # vertical + size.g <- xinch(0.08, warn.log = FALSE) * sizeMultiplier + size.d <- yinch(0.08, warn.log = FALSE) * sizeMultiplier + } + +## Calculate point positions g.pos, d.pos + if(method == 'swarm') { + if(horizontal) { + g.offset <- lapply(x, function(a) swarmy(x = a, y = rep(0, length(a)), cex = sizeMultiplier)$y) + } else { + g.offset <- lapply(x, function(a) swarmx(x = rep(0, length(a)), y = a, cex = sizeMultiplier)$x) + } + d.pos <- x + } else { + if(method == 'hex') size.d <- size.d * sqrt(3) / 2 + + if(log) { + if(is.null(breaks)) + breaks <- 10 ^ seq(log10(dlim[1]), log10(dlim[2]) + size.d, by = size.d) + if(length(breaks) == 1 && is.na(breaks[1])) { + d.index <- x + d.pos <- x + } else { + mids <- 10 ^ ((log10(head(breaks, -1)) + log10(tail(breaks, -1))) / 2) + d.index <- lapply(x, cut, breaks = breaks, labels = FALSE) + d.pos <- lapply(d.index, function(a) mids[a]) + } + } else { + if(is.null(breaks)) + breaks <- seq(dlim[1], dlim[2] + size.d, by = size.d) + if(length(breaks) == 1 && is.na(breaks[1])) { + d.index <- x + d.pos <- x + } else { + mids <- (head(breaks, -1) + tail(breaks, -1)) / 2 + d.index <- lapply(x, cut, breaks = breaks, labels = FALSE) + d.pos <- lapply(d.index, function(a) mids[a]) + } + } + + x.index <- lapply(d.index, function(v) { + if(length(na.omit(v)) == 0) return(v) + v.s <- lapply(split(v, v), seq_along) + if(method == 'center') + v.s <- lapply(v.s, function(a) a - mean(a)) + else if(method == 'square') + v.s <- lapply(v.s, function(a) a - floor(mean(a))) + else if(method == 'hex') { + odd.row <- (as.numeric(names(v.s)) %% 2) == 1 + v.s[odd.row] <- lapply(v.s[odd.row], function(a) a - floor(mean(a)) - 0.25) + v.s[!odd.row] <- lapply(v.s[!odd.row], function(a) a - ceiling(mean(a)) + 0.25) + } + unsplit(v.s, v) + }) + + g.offset <- lapply(1:n.groups, function(i) x.index[[i]] * size.g) + } + + ## now check for runaway points (if "corral" has been set) + if(corral != 'none') { + if(missing(corralWidth)) { + if(n.groups > 1) { + corralWidth <- min(at[-1] - at[-n.groups]) - (2 * size.g) + } else { + corralWidth <- 2 * (min(diff(c(par('usr')[1], at, par('usr')[2]))) - size.g) + } + } else { + stopifnot(length(corralWidth) == 1) + stopifnot(corralWidth > 0) + } + halfCorralWidth <- corralWidth / 2 + if(corral == 'gutter') { + g.offset <- lapply(g.offset, function(zz) pmin(halfCorralWidth, pmax(-halfCorralWidth, zz))) + } + if(corral == 'wrap') { + g.offset <- lapply(g.offset, function(zz) ((zz + halfCorralWidth) %% (halfCorralWidth * 2)) - halfCorralWidth) + } + if(corral == 'random') { + g.offset <- lapply(g.offset, function(zz) ifelse(zz > halfCorralWidth | zz < -halfCorralWidth, runif(length(zz), -halfCorralWidth, halfCorralWidth), zz)) + } + if(corral == 'omit') { + g.offset <- lapply(g.offset, function(zz) ifelse(zz > halfCorralWidth, NA, ifelse(zz < -halfCorralWidth, NA, zz))) + } + } + + g.pos <- lapply(1:n.groups, function(i) at[i] + g.offset[[i]]) + + out <- data.frame(x = unlist(g.pos), y = unlist(d.pos), + pch = pch.out, col = col.out, bg = bg.out, + x.orig = x.gp, y.orig = x.val, + stringsAsFactors = FALSE) + + if(do.plot) { + if(horizontal) { + points(out$y, out$x, pch = out$pch, col = out$col, bg = out$bg, cex = cex) + if(!add) { + axis(1, ...) + axis(2, at = at, labels = labels, tick = FALSE, ...) + box(...) + } + } else { + points(out$x, out$y, pch = out$pch, col = out$col, bg = out$bg, cex = cex) + if(!add) { + axis(2, ...) + axis(1, at = at, labels = labels, tick = FALSE, ...) + box(...) + } + } + } + invisible(out) +} + + +beeswarm.formula <- function (formula, data = NULL, subset, na.action = NULL, + pwpch = NULL, pwcol = NULL, pwbg = NULL, dlab, glab, ...) +{ + 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$... <- NULL + m$dlab <- NULL + m$glab <- NULL + m$na.action <- na.action + require(stats, quietly = TRUE) + m[[1]] <- as.name("model.frame") + mf <- eval(m, parent.frame()) + response <- attr(attr(mf, "terms"), "response") + if (missing(dlab)) + dlab <- names(mf)[response] + if (missing(glab)) + glab <- as.character(formula)[3] + f <- mf[-response] + f <- f[names(f) %in% attr(attr(mf, "terms"), "term.labels")] + if(!is.null(mf$'(pwpch)')) pwpch <- split(mf$'(pwpch)', f) + if(!is.null(mf$'(pwcol)')) pwcol <- split(mf$'(pwcol)', f) + if(!is.null(mf$'(pwbg)')) pwbg <- split(mf$'(pwbg)',f) + beeswarm(split(mf[[response]], f), + pwpch = pwpch, pwcol = pwcol, pwbg = pwbg, + dlab = dlab, glab = glab, ...) +} + + +## hidden function +.calculateSwarm <- function(x, dsize, gsize) { + if(length(x) == 0) return(numeric(0)) + out <- data.frame(x = x / dsize, y = 0, i = seq(along = x)) + out <- out[order(out$x), ] + if(nrow(out) > 1) { + for (i in 2:nrow(out)) { + xi <- out$x[i] + yi <- out$y[i] + pre <- out[1:(i - 1), ] # previous points + wh <- xi - pre$x < 1 # which ones are potentially overlapping + wh[is.na(wh)] <- FALSE # missing values are not potentially overlapping + if(any(wh)) { + pre <- pre[wh, ] + pre <- pre[order(abs(pre$y)), ] + poty.off <- sqrt(1 - ((xi - pre$x) ^ 2)) # potential y offset + poty <- c(0, pre$y + poty.off, pre$y - poty.off) # potential y values + poty.bad <- sapply(poty, function(y) { # check for overlaps + any(((xi - pre$x) ^ 2 + (y - pre$y) ^ 2) < 0.999) + }) + poty[poty.bad] <- Inf + out$y[i] <- poty[which.min(abs(poty))] + } else { + out$y[i] <- 0 + } + } + } + out <- out[order(out$i), ] + out[is.na(out$x), 'y'] <- NA # missing x values should have missing y values + out$y * gsize +} + + +# jitter points horizontally +swarmx <- function(x, y, + xsize = xinch(0.08, warn.log = FALSE), + ysize = yinch(0.08, warn.log = FALSE), + log = NULL, cex = par("cex")) { + if(is.null(log)) + log <- paste(ifelse(par('xlog'), 'x', ''), ifelse(par('ylog'), 'y', ''), sep = '') + xlog <- 'x' %in% strsplit(log, NULL)[[1L]] + ylog <- 'y' %in% strsplit(log, NULL)[[1L]] + xy <- xy.coords(x = x, y = y, recycle = TRUE, log = log) + stopifnot((length(unique(xy$x)) <= 1)) + if(xlog) xy$x <- log10(xy$x) + if(ylog) xy$y <- log10(xy$y) + x.new <- xy$x + .calculateSwarm(xy$y, dsize = ysize * cex, gsize = xsize * cex) + out <- data.frame(x = x.new, y = y) + if(xlog) out$x <- 10 ^ out$x + out +} + +# jitter points vertically +swarmy <- function(x, y, + xsize = xinch(0.08, warn.log = FALSE), + ysize = yinch(0.08, warn.log = FALSE), + log = NULL, cex = par("cex")) { + if(is.null(log)) + log <- paste(ifelse(par('xlog'), 'x', ''), ifelse(par('ylog'), 'y', ''), sep = '') + xlog <- 'x' %in% strsplit(log, NULL)[[1L]] + ylog <- 'y' %in% strsplit(log, NULL)[[1L]] + xy <- xy.coords(x = x, y = y, recycle = TRUE, log = log) + stopifnot((length(unique(xy$y)) <= 1)) + if(xlog) xy$x <- log10(xy$x) + if(ylog) xy$y <- log10(xy$y) + y.new <- xy$y + .calculateSwarm(xy$x, dsize = xsize * cex, gsize = ysize * cex) + out <- data.frame(x = x, y = y.new) + if(ylog) out$y <- 10 ^ out$y + out +} + diff --git a/R/bxplot.R b/R/bxplot.R new file mode 100644 index 0000000..2e9c453 --- /dev/null +++ b/R/bxplot.R @@ -0,0 +1,63 @@ +# bxplot.R +# +# Aron Charles Eklund +## +# A part of the "beeswarm" R package +# + + + +bxplot <- function (x, ...) + UseMethod("bxplot") + +bxplot.default <- function(x, probs = c(0.25, 0.5, 0.75), + vertical = TRUE, horizontal = !vertical, add = FALSE, + col = par("col"), lty = par("lty"), lwd = NULL, + at = NULL, width = 0.75, ...) { + if(is.numeric(x)) { + x <- list(x) + } + n <- length(x) + n.probs <- length(probs) + if(is.null(lwd)) { + lwd <- rep(par('lwd'), length.out = n.probs) + if(0.5 %in% probs) lwd[probs == 0.5] <- par('lwd') * 3 + } + y <- lapply(x, quantile, probs = probs, na.rm = TRUE) + if(is.null(at)) at <- 1:n + if(!add) { + boxplot(x, horizontal = horizontal, at = at, + pars = list(whisklty = 0, staplelty = 0, outpch = NA, + boxlty = 0, medlty = 0), ...) + } + hw <- width / 2 # half-width + if(horizontal) { + for (i in 1:n) { + segments(y0 = at[i] - hw, y1 = at[i] + hw, x0 = y[[i]], + col = col, lwd = lwd, lty = lty) + } + } else { + for (i in 1:n) { + segments(x0 = at[i] - hw, x1 = at[i] + hw, y0 = y[[i]], + col = col, lwd = lwd, lty = lty) + } + } +} + +bxplot.formula <- function (formula, data = NULL, ..., subset, na.action = NULL) +{ + if (missing(formula) || (length(formula) != 3L)) + 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$... <- NULL + m$na.action <- na.action + require(stats, quietly = TRUE) + m[[1L]] <- as.name("model.frame") + mf <- eval(m, parent.frame()) + response <- attr(attr(mf, "terms"), "response") + bxplot(split(mf[[response]], mf[-response]), ...) +} + + diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..80d4f39 --- /dev/null +++ b/R/zzz.R @@ -0,0 +1 @@ +.noGenerics <- TRUE diff --git a/data/breast.RData b/data/breast.RData new file mode 100644 index 0000000..5fcfa68 Binary files /dev/null and b/data/breast.RData differ diff --git a/man/beeswarm.Rd b/man/beeswarm.Rd new file mode 100644 index 0000000..31047f7 --- /dev/null +++ b/man/beeswarm.Rd @@ -0,0 +1,147 @@ +\name{beeswarm} + +\alias{beeswarm} +\alias{beeswarm.default} +\alias{beeswarm.formula} + +\title{Bee swarm plot} +\description{ +Create a bee swarm plot. A bee swarm plot is a one-dimensional scatter plot similar to \code{\link{stripchart}}, but with various methods to separate coincident points such that each point is visible. Also, \code{beeswarm} introduces additional features unavailable in \code{stripchart}, such as the ability to control the color and plotting character of each point. +} + +\usage{ +beeswarm(x, \dots) + +\method{beeswarm}{formula}(formula, data = NULL, subset, na.action = NULL, + pwpch = NULL, pwcol = NULL, pwbg = NULL, dlab, glab, \dots) + +\method{beeswarm}{default}(x, + method = c("swarm", "center", "hex", "square"), + vertical = TRUE, horizontal = !vertical, + cex = 1, spacing = 1, breaks = NULL, + labels, at = NULL, + corral = c("none", "gutter", "wrap", "random", "omit"), + corralWidth, + pch = par("pch"), col = par("col"), bg = NA, + pwpch = NULL, pwcol = NULL, pwbg = NULL, + do.plot = TRUE, add = FALSE, log = FALSE, + xlim = NULL, ylim = NULL, dlim = NULL, glim = NULL, + xlab = NULL, ylab = NULL, dlab = "", glab = "", + \dots) +} + +\arguments{ + \item{formula}{A formula, such as \code{y ~ grp}, where \code{y} is a + numeric vector of data values to be split into groups according to + the grouping variable \code{grp} (usually a factor).} + \item{data}{A data.frame (or list) from which the variables in + \code{formula} should be taken.} + \item{subset}{An optional vector specifying a subset of observations + to be used.} + \item{na.action}{A function which indicates what should happen + when the data contain \code{NA}s. The default is to quietly ignore missing + values in either the response or the group.} + \item{x}{ A numeric vector, or a data frame or list of numeric vectors, each of which is plotted as an individual swarm.} + \item{method}{ Method for arranging points (see Details). } + \item{vertical, horizontal}{ Orientation of the plot. \code{horizontal} takes precedence if both are specified. } + \item{cex}{ Size of points relative to the default given by \code{par("cex")}. Unlike other plotting functions, this must be a single value.} + \item{spacing}{ Relative spacing between points.} + \item{breaks}{ Breakpoints (optional). If \code{NULL}, breakpoints are chosen automatically. If \code{NA}, bins are not used (similar to \code{stripchart} with \code{method = "stack"}).} + \item{labels}{ Labels for each group. Recycled if necessary. By default, these are inferred from the data. } + \item{at}{ Numeric vector giving the locations where the swarms should be drawn; defaults to \code{1:n} where \var{n} is the number of groups. } + \item{corral}{ Method to adjust points that would be placed outside their own group region (see Details). } + \item{corralWidth}{ Width of the "corral" in user coordinates. If missing, a sensible value will be chosen. } + \item{pch, col, bg}{ Plotting characters and colors, specified by group. Recycled if necessary. (see Details). } + \item{pwpch, pwcol, pwbg}{ \dQuote{Point-wise} plotting characters and colors, specified for each data point (see Details). } + \item{do.plot}{ Draw a plot? } + \item{add}{ Add to an existing plot? } + \item{log}{ Use a logarithmic scale on the data axis? } + \item{xlim, ylim}{ Limits of the plot. } + \item{dlim, glim}{ An alternative way to specify limits (see Details). } + \item{xlab, ylab}{ Axis labels. } + \item{dlab, glab}{ An alternative way to specify axis labels (see Details). } + \item{\dots}{ Further arguments passed to \code{\link{plot}}. } +} + +\details{ +Several methods for placing the points are available; each method uses a different algorithm to avoid overlapping points. + +The default method, \code{swarm}, places points in increasing order. If a point would overlap an existing point, it is shifted sideways (along the group axis) by a minimal amount sufficient to avoid overlap. \code{breaks} is ignored. + +The other three methods first discretize the values along the data axis, in order to create more efficient packing: \code{square} places the points on a square grid, whereas \code{hex} uses a hexagonal grid. \code{center} uses a square grid to produce a symmetric swarm. By default, the number of breakpoints for discretization is determined by a combination of the available plotting area and the plotting character size. The discretization of the data can be explicitly controlled using \ [...] + +In contrast to most other plotting functions, changing the size of the graphics device will often change the position of the points. + +The plotting characters and colors can be controlled in two ways. First, the arguments \code{pch}, \code{col} and \code{bg} can specify plotting characters and colors in the same way as \code{\link{stripchart}} and \code{\link{boxplot}}: in short, the arguments apply to each group as a whole (and are recycled if necessary). + +Alternatively, the \dQuote{point-wise} characteristics of each individual data point can be controlled using \code{pwpch}, \code{pwcol}, and \code{pwbg}, which override \code{pch}, \code{col} and \code{bg} if these are also specified. These arguments can be specified as a list or vector. If supplied using the formula method, the arguments can be specified as part of the formula interface; i.e. they are affected by \code{data} and \code{subset}. + + The \code{dlab} and \code{glab} labels may be used instead of \code{xlab} + and \code{ylab} if those are not specified. \code{dlab} applies to the + continuous data axis (the Y axis unless \code{horizontal} is \code{TRUE}); + \code{glab} to the group axis. Likewise, \code{dlim} and \code{glim} can be used to specify limits of the axes instead of \code{xlim} or \code{ylim}. + +This function is intended to be mostly compatible with calls to \code{\link{stripchart}} or \code{\link{boxplot}}. Thus, code that works with these functions should work with \code{beeswarm} with minimal modification. + +By default, swarms from different groups are not prevented from overlapping. Thus, large data sets, or data sets with uneven distributions, may produce somewhat unpleasing beeswarms. If this is a problem, consider reducing \code{cex}. Another approach is to control runaway points (those that would be plotted outside a region allotted to each group) with the \code{corral} argument: The default, \code{"none"}, does not control runaway points. \code{"gutter"} collects runaway points along t [...] +} + +\value{ A data frame with plotting information, invisibly. } + +\seealso{ \code{\link{stripchart}}, \code{\link{boxplot}} } + +\examples{ + ## One of the examples from 'stripchart' + beeswarm(decrease ~ treatment, + data = OrchardSprays, log = TRUE, + pch = 16, col = rainbow(8)) + + ## One of the examples from 'boxplot', with a beeswarm overlay + boxplot(len ~ dose, data = ToothGrowth, + main = "Guinea Pigs' Tooth Growth", + xlab = "Vitamin C dose mg", + ylab = "Tooth length") + beeswarm(len ~ dose, data = ToothGrowth, col = 2, add = TRUE) + + ## Compare the 4 methods + op <- par(mfrow = c(2,2)) + for (m in c("swarm", "center", "hex", "square")) { + beeswarm(len ~ dose, data = ToothGrowth, method = m, main = m) + } + par(op) + + ## Demonstrate the use of 'pwcol' + data(breast) + beeswarm(time_survival ~ ER, data = breast, + pch = 16, pwcol = 1 + as.numeric(event_survival), + xlab = "", ylab = "Follow-up time (months)", + labels = c("ER neg", "ER pos")) + legend("topright", legend = c("Yes", "No"), + title = "Censored", pch = 16, col = 1:2) + + ## The list interface + distributions <- list(runif = runif(100, min = -3, max = 3), + rnorm = rnorm(100), + rlnorm = rlnorm(100, sdlog = 0.5)) + beeswarm(distributions, col = 2:4) + + ## Demonstrate 'pwcol' with the list interface + myCol <- lapply(distributions, function(x) cut(x, breaks = quantile(x), labels = FALSE)) + beeswarm(distributions, pch = 16, pwcol = myCol) + legend("bottomright", legend = 1:4, pch = 16, col = 1:4, title = "Quartile") + + ## Demonstrate the 'corral' methods + par(mfrow = c(2,3)) + beeswarm(distributions, col = 2:4, + main = 'corral = "none" (default)') + beeswarm(distributions, col = 2:4, corral = "gutter", + main = 'corral = "gutter"') + beeswarm(distributions, col = 2:4, corral = "wrap", + main = 'corral = "wrap"') + beeswarm(distributions, col = 2:4, corral = "random", + main = 'corral = "random"') + beeswarm(distributions, col = 2:4, corral = "omit", + main = 'corral = "omit"') +} + +\keyword{ hplot } diff --git a/man/breast.Rd b/man/breast.Rd new file mode 100644 index 0000000..104ced5 --- /dev/null +++ b/man/breast.Rd @@ -0,0 +1,38 @@ +\name{breast} +\alias{breast} +\docType{data} +\title{ +Lymph-node-negative primary breast tumors +} +\description{ +Tumor molecular measurements and outcome from breast cancer patients. +} +\usage{data(breast)} +\format{ + A data frame with 286 observations on the following 5 variables. + \describe{ + \item{\code{ER}}{Estrogen receptor status (factor with levels \code{neg}, \code{pos})} + \item{\code{ESR1}}{Expression of the ESR1 gene (numeric)} + \item{\code{ERBB2}}{Expression of the ERBB2 gene (numeric)} + \item{\code{time_survival}}{Time in months (numeric)} + \item{\code{event_survival}}{Coded event: 0 = censored, 1 = metastasis (numeric)} + } +} +\details{ +ER, ESR1, and ERBB2 were measured on a tumor specimen taken at surgery (time = 0). + +ESR1 and ERBB2 expression values were determined by microarray probe sets 205225_at and 216836_s_at using RMA-normalized data. +} +\source{ +Wang Y, Klijn JG, Zhang Y, Sieuwerts AM, Look MP, Yang F, Talantov D, Timmermans M, Meijer-van Gelder ME, Yu J, Jatkoe T, Berns EM, Atkins D, Foekens JA. +Gene-expression profiles to predict distant metastasis of lymph-node-negative primary breast cancer. +Lancet. 2005 Feb 19-25;365(9460):671-9. +} +\examples{ + data(breast) + + with(breast, + plot(ESR1, ERBB2, col = as.numeric(ER)) + ) +} +\keyword{datasets} diff --git a/man/bxplot.Rd b/man/bxplot.Rd new file mode 100644 index 0000000..5546de1 --- /dev/null +++ b/man/bxplot.Rd @@ -0,0 +1,73 @@ +\name{bxplot} + +\alias{bxplot} +\alias{bxplot.default} +\alias{bxplot.formula} + +\title{Plot quantile lines} + +\description{ +Plot lines indicating the specified quantiles for each group. This function is intended as a simplified interpretation of \code{\link{boxplot}}, + which can be combined with a \code{\link{beeswarm}} (or \code{\link{stripchart}}) plot. +} + +\usage{ +bxplot(x, \dots) + +\method{bxplot}{formula}(formula, data = NULL, \dots, subset, na.action = NULL) + +\method{bxplot}{default}(x, probs = c(0.25, 0.5, 0.75), + vertical = TRUE, horizontal = !vertical, add = FALSE, + col = par("col"), lty = par("lty"), lwd = NULL, + at = NULL, width = 0.75, \dots) +} + +\arguments{ + \item{formula}{A formula, such as \code{y ~ grp}, where \code{y} is a + numeric vector of data values to be split into groups according to + the grouping variable \code{grp} (usually a factor).} + \item{data}{A data.frame (or list) from which the variables in + \code{formula} should be taken.} + \item{subset}{An optional vector specifying a subset of observations + to be used.} + \item{na.action}{A function which indicates what should happen + when the data contain \code{NA}s. The default is to quietly ignore missing + values in either the response or the group.} + \item{x}{A numeric vector, or a data frame or list of numeric vectors, each of which is considered as a group.} + \item{probs}{A numeric vector of probabilities with values in [0,1]} + \item{vertical, horizontal}{ Orientation of the plot. \code{horizontal} takes precedence if both are specified. } + \item{add}{Add to an existing plot?} + \item{col, lty}{Color and line type for each probability.} + \item{lwd}{Line width for each probability (see below).} + \item{at}{Numeric vector giving the locations where the swarms should be drawn; defaults to \code{1:n} where \var{n} is the number of groups.} + \item{width}{Width of the lines.} + \item{\dots}{Further arguments passed to \code{\link{boxplot}}.} +} +\details{ +This function is intended as a minimalistic interpration of \code{\link{boxplot}}; however, the quantiles plotted by \code{bxplot} are not necessarily the same as the hinges plotted by a \code{boxplot}. + +Notice that specifying a vector of graphical parameters such as \code{lwd} or \code{col} will refer to each of \code{probs}, \emph{not} to each group in the data (as one might expect by analogy with \code{boxplot}). + +If \code{lwd} is \code{NULL}, and if the \code{probs} includes 0.5, \code{lwd} will be set to 3 times \code{par("lwd")} for probs=0.5, and \code{par("lwd")} for the others. (Thus something resembling the median line and hinges of a boxplot is produced by default.) +} + +\value{ None.} + +\examples{ + ## bxplot on bottom + beeswarm(len ~ dose, data = ToothGrowth) + bxplot(len ~ dose, data = ToothGrowth, add = TRUE) + + ## bxplot on top + bxplot(decrease ~ treatment, data = OrchardSprays, probs = 0.5, col = 2) + beeswarm(decrease ~ treatment, data = OrchardSprays, add = TRUE) + + ## Show deciles + data(breast) + bxplot(time_survival ~ event_survival, data = breast, + probs = seq(0, 1, by = 0.1), col = rainbow(10)) + beeswarm(time_survival ~ event_survival, data = breast, + pch = 21, bg = "gray75", add = TRUE) +} + +\keyword{ hplot } diff --git a/man/swarmx.Rd b/man/swarmx.Rd new file mode 100644 index 0000000..f4c5aa4 --- /dev/null +++ b/man/swarmx.Rd @@ -0,0 +1,45 @@ +\name{swarmx} +\alias{swarmx} +\alias{swarmy} +\title{ Adjust 1-d data to separate coincident points } +\description{Take a series of points lying in a horizontal or vertical line, and jitter them in the other dimension such that no points are overlapping. } +\usage{ +swarmx(x, y, + xsize = xinch(0.08, warn.log = FALSE), + ysize = yinch(0.08, warn.log = FALSE), + log = NULL, cex = par("cex")) +swarmy(x, y, + xsize = xinch(0.08, warn.log = FALSE), + ysize = yinch(0.08, warn.log = FALSE), + log = NULL, cex = par("cex")) +} +\arguments{ + \item{x, y}{ Coordinate vectors in any format supported by \code{\link{xy.coords}}. } + \item{xsize, ysize}{ Width and height of the plotting character in user coordinates. } + \item{log}{ Character string indicating which axes are logarithmic, as in \code{\link{plot.default}}, or \code{NULL} to figure it out automatically.} + \item{cex}{ Relative plotting character size.} +} +\details{ +For \code{swarmx}, the input coordinates must lie in a vertical line. For \code{swarmy}, the input coordinates must lie in a horizontal line. + +\code{swarmx} adjusts coordinates to the left or right; \code{swarmy} adjusts coordinates up or down. + +Usually it makes sense to call this function after a plotting device has already been set up (e.g. when adding points to an existing plot), so that the default values for \code{xsize}, \code{ysize}, and \code{log} will be appropriate. +} +\value{ A data frame with columns \code{x} and \code{y} with the new coordinates. } +\seealso{ \code{\link{beeswarm}}, \code{\link{jitter}} } +\examples{ + +## Plot points in one dimension +index <- rep(0, 100) +values <- rnorm(100) +plot(index, values, xlim = c(-0.5, 2.5)) +points(swarmx(index + 1, values), col = 2) +points(swarmx(index + 2, values, cex = 1.5), col = 3, cex = 1.5) + +## Try the horizontal direction, with a log scale +plot(values, index, log = "x", ylim = c(-1, 2)) +points(swarmy(values, index + 1), col = 2) + +} +\keyword{ dplot } -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/beeswarm.git _______________________________________________ debian-med-commit mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit
