tags:

views:

287

answers:

2

I am trying to find a suitable display to illustrate various properties within and across school classes. For each class there is only 15-30 data points (pupils).

Right now i am leaning towards a whisker-less boxplot, showing only 1.,2. and 3. quartile + datapoints more then e.g. 1 population SD +/- the sample median.

This I can do.

However - I need to show this graph to some teachers, in order to gauge what they like most. I'd like to compare my graph with a normal boxplot. But the normal boxplot looks the same if there is only one outlier, or e.g. 5 outliers at the same value. In this case this would be a deal-breaker.

e.g.

test <-structure(list(value = c(3, 5, 3, 3, 6, 4, 5, 4, 6, 4, 6, 4, 
4, 6, 5, 3, 3, 4, 4, 4, 3, 4, 4, 4, 3, 4, 5, 6, 6, 4, 3, 5, 4, 
6, 5, 6, 4, 5, 5, 3, 4, 4, 6, 4, 4, 5, 5, 3, 4, 5, 8, 8, 8, 8, 
9, 6, 6, 7, 6, 9), places = structure(c(1L, 2L, 1L, 1L, 1L, 2L, 
1L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 1L, 
2L, 1L, 1L, 1L, 1L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 
2L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 2L, 2L, 1L, 
1L, 2L, 2L, 1L, 2L, 1L), .Label = c("a", "b"), class = "factor")), .Names = c("value", 
"places"), row.names = c(NA, -60L), class = "data.frame")

ggplot(test, aes(x=places,y=value))+geom_boxplot()

Here there are two outliers at ("a",9) - but only one "dot" shown.

So my question: How to jitter the outliers. And - what kind of display would you suggest for this kind of data?

+1  A: 

Does this get you what you are looking for? The limit to where the jitter begins is not automatic, but it is a start.

g = ggplot(test, aes(x = places,y = value))

g + geom_boxplot(outlier.colour = rgb(0,0,0,0)) + geom_point(data = test[test$value > 8,], position = position_jitter(width = .4))
Greg
Thank you greg. But I think your solution will result in one data point to many. the two actual points + the boxplot dot for the outlier. If I could tell ggplot not to draw the outlier, this would be a solution (combined with stat_boxplot and some magic I guess), but geom_boxplot(outlier.color=NULL) does not work.
Andreas
With the outlier.colour argument that I added above, I think it will work.
Greg
Offcause - four zeros makes a lot of difference in stead of just three. With position_jitter(w = .1,h=0)) - it kinds of look okay - but it's obvious that ggplot still leaves room for the outlier dot. It's not beautifull - but I sure works :-)
Andreas
I have accepted Koshke's answer. But thank you still.
Andreas
+2  A: 

you can redifine the funcition

GeomBoxplot$draw<-function (., data, ..., outlier.colour = "black", outlier.shape = 16, 
    outlier.size = 2, outlier.jitter=0) 
{
    defaults <- with(data, data.frame(x = x, xmin = xmin, xmax = xmax, 
        colour = colour, size = size, linetype = 1, group = 1, 
        alpha = 1, fill = alpha(fill, alpha), stringsAsFactors = FALSE))
    defaults2 <- defaults[c(1, 1), ]
        if (!is.null(data$outliers) && length(data$outliers[[1]] >= 
        1)) {
            pp<-position_jitter(width=outlier.jitter,height=0)
            p<-pp$adjust(data.frame(x=data$x[rep(1, length(data$outliers[[1]]))], y=data$outliers[[1]]),.scale)
        outliers_grob <- GeomPoint$draw(data.frame(x=p$x, y = p$y, colour = I(outlier.colour), 
            shape = outlier.shape, alpha = 1, size = outlier.size, 
            fill = NA), ...)
    }
    else {
        outliers_grob <- NULL
    }
    with(data, ggname(.$my_name(), grobTree(outliers_grob, GeomPath$draw(data.frame(y = c(upper, 
        ymax), defaults2), ...), GeomPath$draw(data.frame(y = c(lower, 
        ymin), defaults2), ...), GeomRect$draw(data.frame(ymax = upper, 
        ymin = lower, defaults), ...), GeomRect$draw(data.frame(ymax = middle, 
        ymin = middle, defaults), ...))))
}

ggplot(test, aes(x=places,y=value))+geom_boxplot(outlier.jitter=0.05)

This is ad-hoc solution. Of course, in the sense of OOP, you should create a sub-class of GeomBoxplot and override the function. This is easy because ggplot2 is nice.

=== added for example of sub-class definition ===

GeomBoxplotJitterOutlier <- proto(GeomBoxplot, {
   draw <- function (., data, ..., outlier.colour = "black", outlier.shape = 16, 
    outlier.size = 2, outlier.jitter=0) {
# copy the body of function 'draw' above and paste here.
}

  objname <- "boxplot_jitter_outlier"
  desc <- "Box and whiskers plot with jittered outlier"
  guide_geom <- function(.) "boxplot_jitter_outlier"

})
geom_boxplot_jitter_outlier <- GeomBoxplotJitterOutlier$build_accessor()

then you can do with your sub-class:

ggplot(test, aes(x=places,y=value))+geom_boxplot_jitter_outlier(outlier.jitter=0.05)
kohske
This looks nice! - thank you. how would I go about creating a sub-class? I can't find ref to this in hadleys book - and I am not apt in OOP :-)
Andreas
I put an example above.
kohske