17

I am trying to match boxplot's outliers color to the fill color which is set by aesthetic (scale_colour_discrete).

Here is an example.

m <- ggplot(movies, aes(y = votes, x = factor(round(rating)),
    fill=factor(Animation)))
m + geom_boxplot() + scale_y_log10()

This generates plot below. How do I change those black dots to be reddish/greenish colors used in the body? outlier.colour option of the boxplot seems to pick one colour across, and not as aesthetic, if I understand correctly. I dont mind using colour aesthetics if that helps.

Original Version


Edit:

Adapted this solution (Changing whisker definition in geom_boxplot). The horizontal dodging is reset by stats_summary and I couldn't figure out how to get it back. I'd ptobably drop outliers and stretch whiskers as needed since I know how now.

# define the summary function
f <- function(x) {
  r <- quantile(x, probs = c(0.05, 0.25, 0.5, 0.75, 0.95))
  names(r) <- c("ymin", "lower", "middle", "upper", "ymax")
  r
}
# define outlier function, beyound 5 and 95% percentiles
o <- function(x) {
  subset(x, x < quantile(x,probs=c(0.05))[1] | quantile(x,probs=c(0.95))[1] < x)
}

m <- ggplot(movies, aes(y = votes, x = factor(round(rating)),
    colour=factor(Animation)))
m <- m + stat_summary(fun.data=f, geom='boxplot')
m <- m + stat_summary(fun.y=o, geom='point', aes(colour=factor(Animation)))
m + scale_y_log10()

Failed attempt

Community
  • 1
  • 1
yosukesabai
  • 6,184
  • 4
  • 30
  • 42
  • 1
    This is impossible with the current release but will be possible in the next version. – kohske Dec 14 '11 at 12:51
  • @kohske, maybe you could still make an answer out of your comment. If yosukesabai accepts this answer it is clear to the SO community that this question is solved. (and it get's you some rep :)). – Paul Hiemstra Dec 14 '11 at 13:11
  • Actually I found kohske's answer ["Changing whisker definition in geom_boxplot"](http://stackoverflow.com/questions/4765482/changing-whisker-definition-in-geom-boxplot) , which may be adapted to solve my problem. Hope it won't be too nasty... – yosukesabai Dec 14 '11 at 18:11
  • @kohske, could you elaborate on what would be fixed in new version and time frame for this? I just with position='dodge' works across different geometry provided x scale is discrete. Is this what is in progress? – yosukesabai Dec 15 '11 at 16:21
  • @yosukesabai -- Nice question and solution. Would you be willing to cut out your edit, and put it into an answer to your own question? You can then accept it, and users can easily see that the question has a good answer. Thanks! – Josh O'Brien Dec 15 '11 at 19:33
  • 1
    @JoshO'Brien, i dont think my "solution" is acceptable... When I figure out how to dodge those two dataset apart, I will do what you said. Thanks for comment tho. – yosukesabai Dec 15 '11 at 22:08
  • @yosukesabai: `o <- function(x) {subset(x, x < quantile(x)[2] -1.5*IQR(x) | quantile(x)[4] +1.5*IQR(x) < x)}` and `m + geom_boxplot() + scale_y_log10() + stat_summary(fun.y = o, geom="point", aes(colour=factor(Animation)))` gets you a little further – Henry Dec 20 '11 at 01:29

4 Answers4

11

As @koshke said, having the outliers colored like the lines of the box (not the fill color) is now easily possible by setting outlier.colour = NULL:

m <- ggplot(movies, aes(y = votes, x = factor(round(rating)),
    colour = factor(Animation)))
m + geom_boxplot(outlier.colour = NULL) + scale_y_log10()

boxplot with coloured outliers

  • outlier.colour must be written with "ou"
  • outlier.colour must be outside aes ()

I'm posting this as a late answer because I find myself looking this up again and again, and I also posted it for the related question Coloring boxplot outlier points in ggplot2?.

Community
  • 1
  • 1
cbeleites unhappy with SX
  • 13,717
  • 5
  • 45
  • 57
  • i tried to check your answer works before i accept your answer, but somehow my R installation got screwed. i trust you and just made it accepted answer! – yosukesabai Apr 27 '13 at 03:34
  • @yosukesabai: there's no haste to accept late answers for old questions. Hope you got your installation working again. – cbeleites unhappy with SX Apr 27 '13 at 08:52
  • Note that this doesn't match the fill color, as the title of the OP would suggest, but it does match the outline/line color - which was what I needed. +1 – RyanStochastic Jan 07 '14 at 23:30
  • @RyanStochastic: you're right - I just copied from the other post. However, setting the fill color is straightforward. – cbeleites unhappy with SX Jan 08 '14 at 11:50
  • 11
    It seems that this solution doesn't work anymore for ggplot2 1.0.0 and R 3.1.1. Any ideas how to get matching outlier colours for the new version? – Jon Snow Sep 15 '14 at 15:20
  • it seems that in ggplot2 2.2.1, you only need to specify `aes(..., color = some_factor_level)` to get this effect, do not need `outlier.colour = NULL` – user5359531 Jan 29 '19 at 18:51
5

I found a solution to the fact that setting geom_boxplot(outlier.colour = NULL) doesn't work anymore in newest versions of R (@jonsnow speaks about version 1.0.0 of ggplot2).

In order to replicate the behaviour that @cbeleites propsed you simply need to use the following code:

update_geom_defaults("point", list(colour = NULL))
m <- ggplot(movies, aes(y = votes, x = factor(round(rating)),
            colour = factor(Animation)))
m + geom_boxplot() + scale_y_log10()

as expected this produces plot with points that match the line color.

Of course one should remember to restore the default if he needs to draw multiple plots:

update_geom_defaults("point", list(colour = "black"))

The solution was found by reading the ggplot2 changelog on github:

The outliers of geom_boxplot() use the default colour, size and shape from geom_point(). Changing the defaults of geom_point() with update_geom_defaults() will apply the same changes to the outliers of geom_boxplot(). Changing the defaults for the outliers was previously not possible. (@ThierryO, #757)

Posted here as well: Coloring boxplot outlier points in ggplot2?

Community
  • 1
  • 1
tarch
  • 381
  • 3
  • 3
4

I found a way to do this, editing raw grid object.

library(ggplot2)

match.ol.col <- function(plt,aes.cp='fill') {
  # matches outliers' color to either fill or colour aesthetics
  #   plt: ggplot layer object having boxplot
  #   aes.cp: aetsthetic from which copy color.  must be either 'fill' or 'col'
  # returns grid objects, so print it wigh grid.draw(), not print()
  if (aes.cp %in% c('color', 'colour')) aes.cp <- 'col'
  grob <- ggplotGrob(plt)
  bps <- getGrob(grob, 'boxplots', grep=T)
  for (bp in bps$children) {
    p <- getGrob(bp, 'point', grep=T)
    if (is.null(p)) next
    r <- getGrob(bp, 'rect', grep=T)
    grob <- geditGrob(grob, p$name, gp=gpar(col=r$gp[[aes.cp]]))
  }
  return(grob)
}


m <- ggplot(movies, aes(y = votes, x = factor(round(rating)),
    colour=factor(Animation)))
p <- m + geom_boxplot() + scale_y_log10()

grob <- match.ol.col(p, aes.cp='colour')
grid.draw(grob)

results:

demobox.png

yosukesabai
  • 6,184
  • 4
  • 30
  • 42
1

I had a very similar issue. I wanted to match style with a previous plot, so wanted black borders with coloured fill, and matching outliers.

My solution was to over-print , once with colour= and the default solid circle point, and once with fill= and an open circle point-shape

p <- ggplot(mtcars, aes(factor(cyl), mpg))
p + geom_boxplot(aes(colour=factor(cyl))) + 
    geom_boxplot(aes(fill=factor(cyl)), outlier.shape=21)

boxplot with coloured fill, and black borders and median line

JocelynSP
  • 11
  • 2
  • you can also do `outlier.colour = NA` in the second `geom_boxplot` call. – bmayer Jan 25 '17 at 20:31
  • 1
    With `ggplot2` 2.2.1, I found that overprinting was not necessary. `p + geom_boxplot(aes(fill=factor(cyl)), outlier.shape=21)` was sufficient to get a fill color in the outlier dots that matched the box fill. – Michael S Taylor Nov 01 '17 at 18:16