1
votes

Recent changes to ggplot2 now require a group aesthetic for boxplot.

https://cran.r-project.org/web/packages/ggplot2/news/news.html

In some cases, ggplot2 now produces a warning or an error for code that previously produced plot output. In all these cases, the previous plot output was accidental, and the plotting code uses the ggplot2 API in a way that would lead to undefined behavior. Examples include a missing group aesthetic in geom_boxplot() (#3316), annotations across multiple facets (#3305), and not using aesthetic mappings when drawing ribbons with geom_ribbon() (#3318).

I have code to produce several boxplots, using stat_summary for custom stat control. I can't figure out how to make it work with these new changes to ggplot2. Help!

library(ggplot2)
library(dplyr)
library(cowplot)

varname <- 'medb0'
ylabel <- 'Medium b0\n'
ybreaks <- seq(0,1,0.2)
yref <- 0
ytrans <- "identity"
median_fill <- NA
median_colour <- NA
median_alpha <- 1
xlabels <- c('Wh', 'Wp', 'Po', 'Ot', 'Ta', 'Pu', 'Wt', 'Pi')
xint <- c(1.5,2.5,3.5,4.5,5.5,6.5,7.5)
barwidth <- 0.8
barfilter <- 1:8

custombox1 <- function(y) { # for error bar
  data.frame(ymin=quantile(y,0.025),
             lower=quantile(y,0.25),
             middle=quantile(y,0.5),
             upper=quantile(y,0.75),
             ymax=quantile(y,0.975),
             y=y,
             width=0.5)
}
custombox2 <- function(y) { # for box
  data.frame(ymin=quantile(y,0.025),
             lower=quantile(y,0.25),
             middle=quantile(y,0.5),
             upper=quantile(y,0.75),
             ymax=quantile(y,0.975),
             y=y,
             width=0.7)
}

# sampledata2 <- sampledata %>% 
#   select(setseqf, medb0) %>% 
#   sample_n(20)
# dput(sampledata2)

sampledata2 <- structure(list(setseqf = structure(c(2L, 6L, 1L, 4L, 1L, 8L, 
7L, 1L, 2L, 8L, 2L, 5L, 8L, 8L, 6L, 3L, 8L, 3L, 4L, 8L), .Label = c("1", 
"2", "3", "4", "5", "6", "7", "8"), class = "factor"), medb0 = c(0.0348358613288565, 
0.327077054358727, 0.250130244865912, 0.139639077532824, 0.29309407077181, 
0.252419925740145, 0.155195212332326, 0.333377585774501, 0.328818971135529, 
0.29628877007933, 0.369458460198307, 0.0761957556255915, 0.241107191479485, 
0.275889194987195, 0.17511839005858, 0.0313799783284502, 0.159873816423223, 
0.0250030271563139, 0.0489984043697202, 0.253889351601262)), row.names = c(NA, 
-20L), class = "data.frame")
# old code used to work
ggplot(data=sampledata2, mapping=aes_string(x='setseqf', y=varname)) +
  labs(title='', y=ylabel, x='') +
  theme_cowplot(font_size=10) +
  theme(axis.ticks.x=element_blank(), 
        plot.title=element_blank()) +
  panel_border(colour='black') +  
  geom_hline(yintercept=yref, linetype=2, colour='black') +
  geom_vline(xintercept=xint, colour='grey') +
  stat_summary(fun.data=custombox1, geom='errorbar') +
  stat_summary(fun.data=custombox2, geom='boxplot') + 
  scale_y_continuous(breaks=ybreaks, limits=c(min(ybreaks), max(ybreaks)), expand=c(0, 0), trans=ytrans) +
  scale_x_discrete(labels=xlabels) 
#> Error: Can't draw more than one boxplot per group. Did you forget aes(group = ...)?
# adding group works with stat_boxplot (but can't control stats)
ggplot(data=sampledata2, mapping=aes_string(x='setseqf', y=varname, group='setseqf')) +
  labs(title='', y=ylabel, x='') +
  theme_cowplot(font_size=10) +
  theme(axis.ticks.x=element_blank(), 
        plot.title=element_blank()) +
  panel_border(colour='black') +  
  geom_hline(yintercept=yref, linetype=2, colour='black') +
  geom_vline(xintercept=xint, colour='grey') +
  stat_boxplot(data=sampledata2, geom="errorbar", width=0.35) +
  geom_boxplot(outlier.size=0.5, notch=FALSE, outlier.shape=NA) +
  scale_y_continuous(breaks=ybreaks, limits=c(min(ybreaks), max(ybreaks)), expand=c(0, 0), trans=ytrans) +
  scale_x_discrete(labels=xlabels) 

# adding group does not work with stat_summary
ggplot(data=sampledata2, mapping=aes_string(x='setseqf', y=varname, group='setseqf')) +
  labs(title='', y=ylabel, x='') +
  theme_cowplot(font_size=10) +
  theme(axis.ticks.x=element_blank(), 
        plot.title=element_blank()) +
  panel_border(colour='black') +  
  geom_hline(yintercept=yref, linetype=2, colour='black') +
  geom_vline(xintercept=xint, colour='grey') +
  stat_summary(fun.data=custombox1, geom='errorbar') +
  stat_summary(fun.data=custombox2, geom='boxplot') + 
  scale_y_continuous(breaks=ybreaks, limits=c(min(ybreaks), max(ybreaks)), expand=c(0, 0), trans=ytrans) +
  scale_x_discrete(labels=xlabels) 
#> Error: Can't draw more than one boxplot per group. Did you forget aes(group = ...)?

Created on 2019-09-26 by the reprex package (v0.3.0)

1

1 Answers

1
votes

Thanks to Claus Wilke who solved this for me. The problem was my custombox stats functions had too many rows. I only needed the first row.

suppressMessages({
    library(ggplot2)
    library(dplyr)
    library(cowplot)
})

varname <- 'medb0'
ylabel <- 'Medium b0\n'
ybreaks <- seq(0,1,0.2)
yref <- 0
ytrans <- "identity"
median_fill <- NA
median_colour <- NA
median_alpha <- 1
xlabels <- c('Wh', 'Wp', 'Po', 'Ot', 'Ta', 'Pu', 'Wt', 'Pi')
xint <- c(1.5,2.5,3.5,4.5,5.5,6.5,7.5)
barwidth <- 0.8
barfilter <- 1:8

custombox1 <- function(y) { # for error bar
    data.frame(ymin=quantile(y,0.025),
               lower=quantile(y,0.25),
               middle=quantile(y,0.5),
               upper=quantile(y,0.75),
               ymax=quantile(y,0.975),
               y=y,
               width=0.5,
               row.names=NULL)[1,]
}
custombox2 <- function(y) { # for box
    data.frame(ymin=quantile(y,0.025),
               lower=quantile(y,0.25),
               middle=quantile(y,0.5),
               upper=quantile(y,0.75),
               ymax=quantile(y,0.975),
               y=y,
               width=0.7,
               row.names=NULL)[1,]
}

# sampledata2 <- sampledata %>%
#   select(setseqf, medb0) %>%
#   sample_n(20)
# dput(sampledata2)

sampledata2 <- structure(list(setseqf = structure(c(2L, 6L, 1L, 4L, 1L, 8L,
7L, 1L, 2L, 8L, 2L, 5L, 8L, 8L, 6L, 3L, 8L, 3L, 4L, 8L), .Label = c("1",
"2", "3", "4", "5", "6", "7", "8"), class = "factor"), medb0 = c(0.0348358613288565,
0.327077054358727, 0.250130244865912, 0.139639077532824, 0.29309407077181,
0.252419925740145, 0.155195212332326, 0.333377585774501, 0.328818971135529,
0.29628877007933, 0.369458460198307, 0.0761957556255915, 0.241107191479485,
0.275889194987195, 0.17511839005858, 0.0313799783284502, 0.159873816423223,
0.0250030271563139, 0.0489984043697202, 0.253889351601262)), row.names = c(NA,
-20L), class = "data.frame")

ggplot(data=sampledata2, mapping=aes_string(group='setseqf', x='setseqf', y=varname)) +
    labs(title='', y=ylabel, x='') +
    theme_cowplot(font_size=10) +
    theme(axis.ticks.x=element_blank(),
          plot.title=element_blank()) +
    panel_border(colour='black') +
    geom_hline(yintercept=yref, linetype=2, colour='black') +
    geom_vline(xintercept=xint, colour='grey') +
    stat_summary(fun.data=custombox1, geom='errorbar') +
    stat_summary(fun.data=custombox2, geom='boxplot') +
    scale_y_continuous(breaks=ybreaks, limits=c(min(ybreaks), max(ybreaks)), expand=c(0, 0), trans=ytrans) +
    scale_x_discrete(labels=xlabels)

Created on 2019-09-27 by the reprex package (v0.3.0)