Problems with stat_summary by group

Viewed 7051

My ultimate aim here is to have stat_summary add summary lines to a plot, using existing group memberships. I'm having trouble getting the lines to plot, and while I understand the problem, I can't figure out how to avoid causing it.

An example:

library(ggplot2)
df <- data.frame(low=c(20,24,18,16), 
                 mid=c(60,61,48,45), 
                 high=c(80,75,81,83), 
                 category=factor(seq(1:4)), 
                 membership=factor(c(1,1,2,2)))

p <- ggplot(df, aes(x=category, y=mid)) +
  geom_linerange(aes(ymin=low, ymax=high)) +
  geom_point(shape=95, size=8)
p

This produces a plot of each of the four categories: enter image description here

First step is to use stat_summary to add a line showing the means of ymin, y and ymax, like so:

p + 
  stat_summary(data=df, aes(x="Aggregate", ymin=mean(low), y=mean(mid), ymax=mean(high)), 
               fun.data="mean", geom="linerange", inherit.aes=F) +
  stat_summary(data=df, aes(x="Aggregate", y=mid), fun.y="mean", geom="point", 
               size=8, shape=95)

enter image description here

But when I try to use the memberships in df to produce means within groups, I run into problems with linerange (though point plots fine).

p + 
  stat_summary(data=df, aes(x="Aggregates", ymin=low, y=mid, ymax=high, group=membership), 
               fun.ymin="mean", fun.y="mean", fun.ymax="mean", geom="linerange", 
               inherit.aes=F, position_dodge(0.5))
  stat_summary(data=df, aes(x="Aggregates", y=mid, group=membership), 
               fun.y="mean", geom="point", size=8, shape=95, position_dodge(0.5))

enter image description here

I know from ggplot_build(p) that ymin=y=ymax, which is why nothing is showing on the plot. However, if I use fun.data rather than fun.ymin/fun.ymax I get errors about not having required ymin and ymax aesthetics.

$data[[3]]
      x group ymin    y ymax 
1 5.125     2 46.5 46.5 46.5 
2 4.875     1 60.5 60.5 60.5 

Any help would be appreciated!

1 Answers

You may find it easier to calculate the by-group means before passing the data frame to ggplot() for plotting. One possible approach below:

library(dplyr)

df %>%
  rbind(df %>%
          mutate(category = "Aggregate") %>%
          group_by(category, membership) %>%
          summarise_all(mean) %>% # calculate mean for low / mid / high by group
          ungroup() %>%
          select(colnames(df))) %>% #reorder columns to match the original df
  ggplot(aes(x = category, y = mid, ymin = low, ymax = high,
             colour = membership)) +
  geom_linerange(position = position_dodge(width = 0.5)) +
  geom_point(shape = 95, size = 8,
             position = position_dodge(width = 0.5))

(I added color = membership to make the groups more visually distinct.)

plot

Related