可用于R中Tufte boxplots的功能?
我有一些数据,我已经分成足够的分组,标准箱图显得非常拥挤。 Tufte有他自己的盒子,其中你基本放弃了全部或部分盒子,如下所示:
一些示例数据:
cw <- transform(ChickWeight,
Time = cut(ChickWeight$Time,4)
)
cw$Chick <- as.factor( sample(LETTERS[seq(3)], nrow(cw), replace=TRUE) )
levels(cw$Diet) <- c("Low Fat","Hi Fat","Low Prot.","Hi Prot.")
我想为每个饮食*时间*小鸡分组提供一个箱子重量。
几年前,我遇到了这个问题,并且使用网格图形拼凑了一个解决方案,我将稍后发布。 但是在解决这个新的(类似的)问题时,我想知道是否有一种库存的方式来完成它们,而不是修复我一起出现的问题。
顺便说一句,这些似乎是Tufte创作中不太受人喜爱的,但我真的很喜欢它们,因为它们在大量的群体中密集展示分布模式,如果它们有一个好的功能,我会更多地使用它们。 ggplot2或格子。
你显然只想要一个垂直版本,所以我使用了panel.bwplot代码,除去了所有非基本要素(如框和帽),并在参数中设置了horizontal = FALSE,并创建了一个panel.tuftebxp函数。 同时将点的cex设置为默认值的一半。 还有相当多的选项可以根据你的口味进行调整。 “时间”的“数字”因素名称看起来马虎,但我认为“概念验证”很清晰,您可以清理对您来说重要的事情:
panel.tuftebxp <-
function (x, y, box.ratio = 1, box.width = box.ratio/(1 + box.ratio), horizontal=FALSE,
pch = box.dot$pch, col = box.dot$col,
alpha = box.dot$alpha, cex = box.dot$cex, font = box.dot$font,
fontfamily = box.dot$fontfamily, fontface = box.dot$fontface,
fill = box.rectangle$fill, varwidth = FALSE, notch = FALSE,
notch.frac = 0.5, ..., levels.fos = if (horizontal) sort(unique(y)) else sort(unique(x)),
stats = boxplot.stats, coef = 1.5, do.out = TRUE, identifier = "bwplot")
{
if (all(is.na(x) | is.na(y)))
return()
x <- as.numeric(x)
y <- as.numeric(y)
box.dot <- trellis.par.get("box.dot")
box.rectangle <- trellis.par.get("box.rectangle")
box.umbrella <- trellis.par.get("box.umbrella")
plot.symbol <- trellis.par.get("plot.symbol")
fontsize.points <- trellis.par.get("fontsize")$points
cur.limits <- current.panel.limits()
xscale <- cur.limits$xlim
yscale <- cur.limits$ylim
if (!notch)
notch.frac <- 0
#removed horizontal code
blist <- tapply(y, factor(x, levels = levels.fos), stats,
coef = coef, do.out = do.out)
blist.stats <- t(sapply(blist, "[[", "stats"))
blist.out <- lapply(blist, "[[", "out")
blist.height <- box.width
if (varwidth) {
maxn <- max(table(x))
blist.n <- sapply(blist, "[[", "n")
blist.height <- sqrt(blist.n/maxn) * blist.height
}
blist.conf <- if (notch)
sapply(blist, "[[", "conf")
else t(blist.stats[, c(2, 4), drop = FALSE])
ybnd <- cbind(blist.stats[, 3], blist.conf[2, ], blist.stats[,
4], blist.stats[, 4], blist.conf[2, ], blist.stats[,
3], blist.conf[1, ], blist.stats[, 2], blist.stats[,
2], blist.conf[1, ], blist.stats[, 3])
xleft <- levels.fos - blist.height/2
xright <- levels.fos + blist.height/2
xbnd <- cbind(xleft + notch.frac * blist.height/2, xleft,
xleft, xright, xright, xright - notch.frac * blist.height/2,
xright, xright, xleft, xleft, xleft + notch.frac *
blist.height/2)
xs <- cbind(xbnd, NA_real_)
ys <- cbind(ybnd, NA_real_)
panel.segments(rep(levels.fos, 2), c(blist.stats[, 2],
blist.stats[, 4]), rep(levels.fos, 2), c(blist.stats[,
1], blist.stats[, 5]), col = box.umbrella$col, alpha = box.umbrella$alpha,
lwd = box.umbrella$lwd, lty = box.umbrella$lty, identifier = paste(identifier,
"whisker", sep = "."))
if (all(pch == "|")) {
mult <- if (notch)
1 - notch.frac
else 1
panel.segments(levels.fos - mult * blist.height/2,
blist.stats[, 3], levels.fos + mult * blist.height/2,
blist.stats[, 3], lwd = box.rectangle$lwd, lty = box.rectangle$lty,
col = box.rectangle$col, alpha = alpha, identifier = paste(identifier,
"dot", sep = "."))
}
else {
panel.points(x = levels.fos, y = blist.stats[, 3],
pch = pch, col = col, alpha = alpha, cex = cex,
identifier = paste(identifier,
"dot", sep = "."))
}
panel.points(x = rep(levels.fos, sapply(blist.out, length)),
y = unlist(blist.out), pch = plot.symbol$pch, col = plot.symbol$col,
alpha = plot.symbol$alpha, cex = plot.symbol$cex*0.5,
identifier = paste(identifier, "outlier", sep = "."))
}
bwplot(weight ~ Diet + Time + Chick, data=cw, panel=
function(x,y, ...) panel.tuftebxp(x=x,y=y,...))
这是一个不使用任何软件包的解决方案,只是操纵boxplot pars
图形参数。 我的建议最接近@DWin,但是摆脱了颜色和坐标轴,只用了几行代码。 通过@ GSK3和@Ramnath两项建议都非常好,而且比我的更先进,但如果我可以提出意见 - 它们不能解决蒂夫特的主要理念。 如果我们摆脱灰色背景,白色“监狱酒吧”和不必要的颜色,上述所有解决方案都将获得清晰,简单和正确的数据墨水平衡。
积分应该发给PerformanceAnalytics
创作者,他们包含可爱的chart.Boxplot
包装由Tufte工作启发。 我简单地提取了一些功能元素,以使它更简单。 只需在@ gsk3上面添加'cw'样本数据即可。
attach(cw)
par(mfrow=c(1,3))
boxplot(weight~Time, horizontal = F, main = "", xlab="Time", ylab="Weight",
pars = list(boxcol = "white", medlty = "blank", medpch=16, medcex = 1.3,
whisklty = c(1, 1), staplelty = "blank", outcex = 0.5), axes = FALSE)
axis(1,at=1:4,label=c(1:4))
axis(2)
boxplot(weight~Chick, horizontal = F, main = "", xlab = "Chick",
ylab = "", pars = list(boxcol = "white", medlty = "blank", medpch=16,
medcex = 1.3, whisklty = c(1, 1), staplelty = "blank", outcex = 0.5),
axes = FALSE)
axis(1,at=1:3,label=c("A","B","C"))
boxplot(weight~Diet, horizontal = F, main = "", xlab = "Diet", ylab = "",
pars = list(boxcol = "white", medlty = "blank", medpch=16, medcex = 1.3,
whisklty = c(1, 1), staplelty = "blank", outcex = 0.5), axes = FALSE)
axis(1,at=1:4,label=c("LoFat","HiFat","LoProt","HiProt"))
这是习惯性的ggplot
解决方案(或者更确切地说是一种高雅的黑客)
require(ggplot2)
# melt the data frame
cw2 = melt(cw, id = 'weight')
# create a data frame with boxplot stats
cw3 = ddply(cw2, .(value, variable), function(df) boxplot.stats(df$weight)$stats)
# generate the plot
ggplot(cw2, aes(value, weight)) +
geom_boxplot(fill = 'gray90', colour = 'gray90', alpha = 0) +
geom_segment(data = cw3, aes(xend = value, y = V1, yend = V2)) +
geom_segment(data = cw3, aes(xend = value, y = V4, yend = V5)) +
geom_point(data = cw3, aes(y = V3), size = 3) +
facet_wrap(~ variable, scales = 'free_x', nrow = 1)
链接地址: http://www.djcxy.com/p/24921.html