nsgrantham / ggbraid

Braided ribbons in ggplot2
https://nsgrantham.github.io/ggbraid/
Other
78 stars 1 forks source link

Using `after_stat()` fails with `Aesthetics can not vary with a ribbon` #1

Closed eliocamp closed 2 years ago

eliocamp commented 2 years ago

Reprex:

set.seed(42)
data <- data.frame(x = 1:10, 
                   y = rnorm(10) + 1:10/10)

library(ggplot2)
library(ggbraid)

ggplot(data, aes(x, y)) +
  geom_line() +
  geom_braid(aes(ymin = y, ymax = predict(lm(y ~ x)), 
                 fill = predict(lm(y ~ x)) < y))
#> `geom_braid()` using method = 'line'

 ggplot(data, aes(x, y)) +
  geom_line() +
  geom_braid(aes(ymin = y, ymax = predict(lm(y ~ x)), 
                 fill = after_stat(ymin < ymax)))
#> `geom_braid()` using method = 'line'
#> Error in `f()`:
#> ! Aesthetics can not vary with a ribbon

I think the issue is that StatBraid returns the unchanged data if there is no fill or colour column so it doesn't add the intersection points.

Created on 2022-03-23 by the reprex package (v2.0.1)

nsgrantham commented 2 years ago

Yes, your hunch is correct — stat_braid() does not see a fill or color column and since method = 'line', it exits early and passes the data unchanged to geom_ribbon(). I need to add something in stat_braid() so that it is aware of aesthetics for which the user has used after_stat(). I'll take a look at how other stats have approached this.

However, even if this were addressed, it's not possible for after_stat(ymin < ymax) to work as intended. I go into some detail about how stat_braid() works in the Average Daily Temperatures article (https://nsgrantham.github.io/ggbraid/articles/temps.html). The important part is that an intersection requires two rows with the same x, ymin, and ymax but different fill, where one has fill = TRUE and another has fill = FALSE. So if we use after_stat(ymin < ymax) then that undoes the "braiding."

This could be a common source of confusion (it confused me and I wrote the package!) so I may add this to a Frequently Asked Questions page of the documentation or write an article that goes into detail about what is and is not supported by ggbraid.

For now, I'm going to keep the issue open while I investigate other uses of after_stat() which are not currently supported but should be.

Thanks for beta testing!

eliocamp commented 2 years ago

Perhaps the braiding needs to happen at the geom level instead of at the stat level?

nsgrantham commented 2 years ago

Yes, that's possible.

Another option is to create a new column in data that the user can use in after_stat(). Something like the following:

ggplot(data, aes(x, y)) +
  geom_line() +
  geom_braid(aes(ymin = y, ymax = predict(lm(y ~ x)), fill = after_stat(max_over_min)))
nsgrantham commented 2 years ago

This is now possible with fill = after_stat(braid). Please install the latest version of ggbraid (0.2.0) and give it a try when you have a chance. Closing the issue now, but feel free to reopen if something's off. Thanks again for the early feedback!