tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.39k stars 2k forks source link

scale_y_discrete() fails without data to plot #5945

Open twest820 opened 2 weeks ago

twest820 commented 2 weeks ago

Hitting some instances where geom_col() + scale_y_discrete() errors out instead of producing an empty plot when given no data.

I've encountered two different failure modes with ggplot 3.5.1 in R 4.4. repexes below simplified from actual use.

theme_set(theme_bw()) # probably doesn't matter, but just in case

ggplot() + 
  geom_col(aes(x = meanX, y = level, fill = level), tibble(x = 1, level = factor(1)) %>% filter(x < 1) %>% group_by(level, x) %>% summarize(meanX = mean(x), .groups = "drop")) +
  labs(x = NULL, y = NULL, fill = NULL, title = "title") +
  scale_y_discrete()
Error in ans[ypos] <- rep(yes, length.out = len)[ypos] : 
  replacement has length zero
In addition: Warning message:
In rep(yes, length.out = len) : 'x' is NULL so the result will be NULL
ggplot() + 
  geom_col(aes(x = meanX, y = level, fill = level), tibble(x = 1, level = factor(1)) %>% filter(x < 1) %>% group_by(level, x) %>% summarize(meanX = mean(x), .groups = "drop")) +
  labs(x = NULL, y = NULL, fill = NULL, title = "title") +
  scale_y_discrete(labels = NULL, limits = rev, drop = FALSE)
Error in `mapped_discrete()`:
! Can't convert `x` <list> to <double>.
Run `rlang::last_trace()` to see where the error occurred.
Warning messages:
1: In structure(in_domain, pos = match(in_domain, breaks)) :
  Calling 'structure(NULL, *)' is deprecated, as NULL cannot have attributes.
  Consider 'structure(list(), *)' instead.
2: In structure(in_domain, pos = match(in_domain, breaks)) :
  Calling 'structure(NULL, *)' is deprecated, as NULL cannot have attributes.
  Consider 'structure(list(), *)' instead.

Workaround's to check for empty tibbles and skip + scale_y_discrete() when they occur. Easy enough but it seems atypical for ggplot that callers need to check for and handle the no data case. Also seems curious explicitly specifying a default scale_y_discrete() fails but leaving it implicit succeeds.

teunbrand commented 2 weeks ago

Thanks for the report! The first example does not throw an error in the current development version, so I don't think it needs a fix at the moment. I agree with you that the second example should simply return an empty plot.