6

我需要在 R 中为我的箱线图使用黑白颜色。我想用线和点填充箱线图。例如:

在此处输入图像描述

我想ggplot2可以做到这一点,但我找不到任何方法来做到这一点。

预先感谢您的帮助!

4

2 回答 2

6

我认为这是一个很好的问题,并思考是否有可能在基础 R 中执行此操作并获得方格外观。所以我整理了一些依赖boxplot.statsand的代码polygon(可以绘制成角度的线)。这是解决方案,它实际上还没有为黄金时段做好准备,但它是一个可以修改以使其更通用的解决方案。

boxpattern <- 
function(y, xcenter, boxwidth, angle=NULL, angle.density=10, ...) {
    # draw an individual box
    bstats <- boxplot.stats(y)
    bxmin <- bstats$stats[1]
    bxq2 <- bstats$stats[2]
    bxmedian <- bstats$stats[3]
    bxq4 <- bstats$stats[4]
    bxmax <- bstats$stats[5]
    bleft <- xcenter-(boxwidth/2)
    bright <- xcenter+(boxwidth/2)
    # boxplot
    polygon(c(bleft,bright,bright,bleft,bleft),
        c(bxq2,bxq2,bxq4,bxq4,bxq2), angle=angle[1], density=angle.density)
    polygon(c(bleft,bright,bright,bleft,bleft),
        c(bxq2,bxq2,bxq4,bxq4,bxq2), angle=angle[2], density=angle.density)
    # lines
    segments(bleft,bxmedian,bright,bxmedian,lwd=3) # median
    segments(bleft,bxmin,bright,bxmin,lwd=1) # min
    segments(xcenter,bxmin,xcenter,bxq2,lwd=1)
    segments(bleft,bxmax,bright,bxmax,lwd=1) # max
    segments(xcenter,bxq4,xcenter,bxmax,lwd=1)
    # outliers
    if(length(bstats$out)>0){
        for(i in 1:length(bstats$out))
            points(xcenter,bstats$out[i])
    }
}

drawboxplots <- function(y, x, boxwidth=1, angle=NULL, ...){
    # figure out all the boxes and start the plot
    groups <- split(y,as.factor(x))
    len <- length(groups)
    bxylim <- c((min(y)-0.04*abs(min(y))),(max(y)+0.04*max(y)))
    xcenters <- seq(1,max(2,(len*(1.4))),length.out=len)
    if(is.null(angle)){
        angle <- seq(-90,75,length.out=len)
        angle <- lapply(angle,function(x) c(x,x))
    }
    else if(!length(angle)==len)
        stop("angle must be a vector or list of two-element vectors")
    else if(!is.list(angle))
        angle <- lapply(angle,function(x) c(x,x))
    # draw plot area
    plot(0, xlim=c(.97*(min(xcenters)-1), 1.04*(max(xcenters)+1)),
        ylim=bxylim, 
        xlab="", xaxt="n",
        ylab=names(y), 
        col="white", las=1)

    axis(1, at=xcenters, labels=names(groups))
    # draw boxplots
    plots <- mapply(boxpattern, y=groups, xcenter=xcenters,
        boxwidth=boxwidth, angle=angle, ...)
}

一些实例:

mydat <- data.frame(y=c(rnorm(200,1,4),rnorm(200,2,2)),
                    x=sort(rep(1:2,200)))
drawboxplots(mydat$y, mydat$x)

在此处输入图像描述

mydat <- data.frame(y=c(rnorm(200,1,4),rnorm(200,2,2),
                        rnorm(200,3,3),rnorm(400,-2,8)),
                    x=sort(rep(1:5,200)))
drawboxplots(mydat$y, mydat$x)

在此处输入图像描述

drawboxplots(mydat$y, mydat$x, boxwidth=.5, angle.density=30)

在此处输入图像描述

drawboxplots(mydat$y, mydat$x, # specify list of two-element angle parameters
             angle=list(c(0,0),c(90,90),c(45,45),c(45,-45),c(0,90)))

在此处输入图像描述

编辑:我想补充一点,也可以通过基本上绘制点图案来获得点作为填充,然后将它们覆盖为“甜甜圈”形多边形,如下所示:

x <- rep(1:10,10)
y <- sort(x)
plot(y~x, xlim=c(0,11), ylim=c(0,11), pch=20)
outerbox.x <- c(2.5,0.5,10.5,10.5,0.5,0.5,2.5,7.5,7.5,2.5)
outerbox.y <- c(2.5,0.5,0.5,10.5,10.5,0.5,2.5,2.5,7.5,7.5)
polygon(outerbox.x,outerbox.y, col="white", border="white") # donut
polygon(c(2.5,2.5,7.5,7.5,2.5),c(2.5,2.5,2.5,7.5,7.5)) # inner box

在此处输入图像描述

但是在单个绘图函数中将其与倾斜线混合会有点困难,并且通常更具挑战性,但它开始让你到达那里。

于 2013-07-02T15:54:27.803 回答
4

我认为很难做到这一点,ggplot2因为它不使用着色多边形(gris limitatipn)。但是您可以在基础图中使用阴影线特征,在某些绘图函数(ploygon、barplot、..)中通过密度角度参数进行参数化。

boxplot不使用此功能的问题。所以我破解了它,或者更确切地说,我破解bxp了 boxplot 内部使用的内容。hack 包括向 bxp 函数添加 2 个参数(角度和密度),并在xypolygon函数调用中在内部添加它们(这发生在 2 行中)。

my.bxp <- function (all.bxp.argument,angle,density, ...) {
    .....#### bxp code
    xypolygon(xx, yy, lty = boxlty[i], lwd = boxlwd[i], 
    border = boxcol[i],angle[i],density[i])  
    .......## bxp code after
    xypolygon(xx, yy, lty = "blank", col = boxfill[i],angle[i],density[i])      
    ......

}

这里举个例子。需要注意的是,确保图例与剧情一致完全是用户的责任。所以我添加了一些代码来重新排列图例和箱线图代码。

在此处输入图像描述

require(stats)
set.seed(753)
(bx.p <- boxplot(split(rt(100, 4), gl(5, 20))))
layout(matrix(c(1,2),nrow=1),
       width=c(4,1)) 
angles=c(60,30,40,50,60)
densities=c(50,30,40,50,30)
par(mar=c(5,4,4,0)) #Get rid of the margin on the right side
my.bxp(bx.p,angle=angles,density=densities)
par(mar=c(5,0,4,2)) #No margin on the left side
plot(c(0,1),type="n", axes=F, xlab="", ylab="")
legend("top", paste("region", 1:5),
       angle=angles,density=densities)
于 2013-07-02T11:20:06.113 回答