2013-07-02 11 views
5

Potrzebuję użyć koloru czarnego i białego dla moich działek w R. Chciałbym kolorować wypełnienie boxplot liniami i kropkami. Dla przykładu:Colorfill boxplot w R-cran z liniami, kropkami lub podobnym

enter image description here

Wyobrażam ggplot2 mógł to zrobić, ale nie mogę znaleźć jakiś sposób, aby to zrobić.

Z góry dziękujemy za pomoc!

+0

Pojawiło się trochę googlowania [ta dyskusja z r-help] (http://r.789695.n4.nabble.com/How-to-fill-bar-plot-with-textile-rather-than-color- td847003.html), co sprawia, że ​​brzmi to dość trudne. – Thomas

Odpowiedz

4

Myślę, że trudno to zrobić z ggplot2, ponieważ nie należy używać cieniowania wielokąta (gris limitatipn). Ale można użyć funkcji cieniowania na wykresie bazowym, z parametrem gęstości i kąt argumenty w niektórych funkcjach wykresu (ploygon, barplot, ..).

Problem polegający na tym, że boxplot nie używa tej funkcji. Więc włamuję się do niego, a raczej włamuję się do wewnętrznego użytku przez boxplot. Hack polega na dodaniu 2 argumentów (kąt i gęstość) do funkcji bxp i dodanie ich wewnętrznie w wywołaniu funkcji xypolygon (występuje to w 2 wierszach).

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])  
    ...... 

} 

Oto przykład. Należy zauważyć, że to całkowicie w gestii użytkownika jest zapewnienie, że legenda odpowiada działce. Dodałem więc trochę kodu, aby zmienić legendę i kod boxplota.

enter image description here

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) 
+0

Awesome! Działa świetnie! Dziękuję Ci bardzo! – user2427949

4

Myślałem, że to wielkie pytanie i rozważała, czy to możliwe, aby zrobić to w podstawy R i uzyskanie klatkową wygląd. Tak więc skompilowałem kod, który bazuje na boxplot.stats i polygon (który może narysować pochylone linie). Oto rozwiązanie, które nie jest jeszcze gotowe na pierwszy dzień, ale jest rozwiązaniem, które można zmodyfikować, aby było bardziej ogólne.

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, ...) 
} 

Przykłady w akcji

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

enter image description here

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) 

enter image description here

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

enter image description here

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))) 

enter image description here

EDIT: Chciałem dodać, że można również uzyskać kropki jako wypełnienia przez zasadzie rysując wzór kropek, a następnie pokrycie im „pączek” wielokąt w kształcie litery, tak jak poniżej:

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 

enter image description here

Ale mieszanie że z ukośnymi liniami w jednej funkcji kreślenia będzie to trochę trudne, i to na ogół nieco bardziej challeng ale zacznie cię tam sprowadzać.

Powiązane problemy