我正在创建一个自定义的ggplot geom来代表Edward Tufte的第二个boxplot
最终的目标是能够将其用作轴来简洁地显示边际分布。 我的工作基于Jeffrey Arnold的ggthemes。
我得到了一个看起来正确的输出,但是在一般情况下使其工作导致了手头的问题。
下面是用于绘制中间线的代码(即替换框的行):
median.thickness <- 0.25
box.offset <- 0.01
boxdata <- data.frame(
x = data$x + box.offset,
xend = data$x + box.offset,
y = c(data$upper, data$lower),
yend = c(data$middle + median.thickness, data$middle - median.thickness),
alpha = NA,
common)
显然,值median.thickness
和box.offset
需要根据绘图的范围而有所不同,因此根据这些值计算它们是理想的。有没有办法在geom中实现这个目标?
答案 0 :(得分:0)
不可否认,不是你要求的,但这是一个如何用基本图形实现这一目标的例子。
tufte <- function(x, groups, data, offset=0.15, lwd=2,
xlab=NULL, ylab=NULL) {
if(is.null(xlab)) xlab <- deparse(substitute(groups))
if(is.null(ylab)) ylab <- deparse(substitute(x))
b <- boxplot(eval(substitute(x~groups)), data, plot=FALSE)
nm <- b$names
stats <- b$stats
plot.new()
plot.window(ylim=range(pretty(range(stats))), xlim=c(0.5, ncol(stats)+0.5))
mdn.span <- 0.15*min(stats[4, ] - stats[2, ])
invisible({
segments(rep(seq_len(ncol(stats)), each=2), c(stats[c(1, 4), ]),
y1=c(stats[c(2, 5), ]), lwd=lwd, lend=1)
segments(seq_len(ncol(stats)) + offest, c(stats[2, ]),
y1=c(stats[4, ]), lwd=lwd, lend=1)
})
segments(seq_len(ncol(stats)) + offset, stats[3, ] - mdn.span,
y1=stats[3, ] + mdn.span, col='white', lwd=3, lend=1)
axis(1, at=seq_len(ncol(stats)), labels=nm)
axis(2, las=1)
title(xlab=xlab, ylab=ylab)
box(lwd=2)
}
tufte(weight, feed, chickwts)
这里,x偏移被设置为一个常数,这对我来说是有意义的,因为有了更多的组,x轴的范围会更大,你会想要更小的偏移(我想?)。表示中位数的间隙的高度定义为IQR最小的组的四分位数范围的五分之一。但是,这意味着如果存在IQR非常小的组,则所有组的绘图都将受到影响。
答案 1 :(得分:0)
我想我已经找到了一个很好的解决方案。
boxdata <- data.frame(
x = data$x,
xend = data$x,
y = c(data$upper, data$lower),
yend = c(data$middle, data$middle),
alpha = NA,
common)
box_grob <- GeomSegment$draw(boxdata, ...)
offset <- 0.004
box_grob$x0 <- box_grob$x0 + unit(offset * common$size, "npc")
box_grob$x1 <- box_grob$x1 + unit(offset * common$size, "npc")
box_grob$y1 <- box_grob$y1 + unit(c(1.5 * offset, -1.5 * offset), "npc")
此代码生成与问题中公布的图相同的图,并根据线条粗细进行适当缩放。