37

Following this question: How to add a number of observations per group and use group mean in ggplot2 boxplot?, I want to add number of observations per group in ggplot boxplot, too. But I have added a colour into aes mapping.

The existing answer shows how to adjust text position in y axis. How could I adjust the text position in the x axis?

This is a minimum example to reproduce my problem:

library(ggplot2)

give.n <- function(x){
  return(c(y = median(x)*1.05, label = length(x))) 
  # experiment with the multiplier to find the perfect position
}


p <- ggplot(mtcars, aes(factor(vs), mpg, colour = factor(am))) + 
    geom_boxplot() +
    stat_summary(fun.data = give.n, geom = "text", fun.y = median)
p

enter image description here

zx8754
  • 52,746
  • 12
  • 114
  • 209
Bangyou
  • 9,462
  • 16
  • 62
  • 94

2 Answers2

27

You can just use position:

p <- ggplot(mtcars, aes(factor(vs), mpg, colour = factor(am))) +  
     geom_boxplot() +
     stat_summary(fun.data = give.n, geom = "text", fun.y = median,
                  position = position_dodge(width = 0.75))
p

enter image description here

The width argument of position_dodge() controls the positioning on the horizontal axis. 0.75 is the sweet spot, see how it works for different numbers of groupings:

p2 <- ggplot(mtcars, aes(factor(vs), mpg, colour = factor(cyl))) + 
      geom_boxplot() +
      stat_summary(fun.data = give.n, geom = "text", fun.y = median, 
                   position = position_dodge(width = 0.75))
p2

enter image description here

Bangyou
  • 9,462
  • 16
  • 62
  • 94
alexwhan
  • 15,636
  • 5
  • 52
  • 66
3

Instead of stat_summary, you can use geom_text. Please refer to the following question: ggplot2 add text on top of boxplots.

This is an example of how you may do it with the number of observations:

# Create an aggregate of median & count
> cts <- merge(aggregate(mpg ~ cyl + am, mtcars, length), 
               aggregate(mpg ~ cyl + am, mtcars, median), 
               by=c("cyl", "am"))
# Rename the col names to fit with the original dataset..
> names(cts) <- c("cyl", "am", "count", "mpg")
# As alexwhan suggested, position_dodge helps with positioning
# along the x-axis..
> ggplot(mtcars, aes(factor(cyl), mpg, colour = factor(am))) + 
  geom_boxplot(position = position_dodge(width=1.0)) + 
  geom_text(data = cts, aes(label=count), 
            position=position_dodge(width=1.0))
Community
  • 1
  • 1
szabad
  • 380
  • 3
  • 10
  • `geom_text` does not seem to do counts by groups. Can you show the code how to do this with `geom_text`? – arun Aug 23 '16 at 18:59
  • `geom_text` is a text labeling function, it doesn't do any aggregations or summary statistics on the data. But you can create an aggregate of the dataset that calculates the count per group, and use that as an input to `geom_text`. I edited my answer to provide an example. – szabad Aug 24 '16 at 05:04