Skip to content

Allow expressions in facet specs even when some variables are not available on some layers #3757

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

yutannihilation
Copy link
Member

@yutannihilation yutannihilation commented Jan 22, 2020

(Cherry-picked version of #3735 for v3.3.0-rc branch)


Fix #2963

Background

Not all variables in a facet spec are available on all the layers. A solution suggested on r-lib/rlang#888 (comment) is:

bind the same symbols inside each panel, and when the symbols are undefined use an active binding to throw a typed error? And then you'd only catch these particular errors in the tryCatch()

Main change

This PR injects such an active bindings on the column names of all the plot data so that we can let eval_facet() fail gracefully.

eval_facet() evaluates facet specs in these two steps:

  1. When the spec is a symbol (the most common case), check if the layer data contains the same name of column. If it does, subset the column and return it. If it doesn't, return NULL. In this case, no error happens even if the symbol is not available on all the layers.
  2. When the spec is a expression, evaluate it. In this case, an error is raised on the layer where the symbol is not available.

This PR changes only step 2, so I expect this doesn't affect most of the existing code. Note that, while step 2 can also handle symbols, we still need step 1 to issue a friendly error ("At least one layer must contain all faceting variables") when no layer contain the variable.

devtools::load_all("~/repo/ggplot2/")
#> Loading ggplot2

# works fine with expressions
ggplot(mtcars, aes(mpg, cyl)) +
  geom_point() +
  geom_vline(xintercept = 20) +
  facet_wrap(vars(2 * am))

# works fine with external variables
two <- 2
ggplot(mtcars, aes(mpg, cyl)) +
  geom_point() +
  geom_vline(xintercept = 20) +
  facet_wrap(vars(two * am))

# raises an error when the expression refers to some non-existent variable
ggplot(mtcars, aes(mpg, cyl)) +
  geom_point() +
  geom_vline(xintercept = 20) +
  facet_wrap(vars(no_such_variable * am))
#> Error in eval_tidy(facet, mask): object 'no_such_variable' not found

# special case: raises a friendlier error when the expression is a symbol
ggplot(mtcars, aes(mpg, cyl)) +
  geom_point() +
  geom_vline(xintercept = 20) +
  facet_wrap(vars(no_such_variable))
#> Error: At least one layer must contain all faceting variables: `no_such_variable`.
#> * Plot is missing `no_such_variable`
#> * Layer 1 is missing `no_such_variable`
#> * Layer 2 is missing `no_such_variable`

# a data pronoun can be handled
ggplot(mtcars, aes(mpg, cyl)) +
  geom_point() +
  geom_vline(xintercept = 20) +
  facet_wrap(vars(.data$am))

Created on 2020-01-23 by the reprex package (v0.3.0)

Minor change

  • This PR removes env argument of eval_facet(). This is not necessary, but done in order to avoid confusion. I believe all facet specs are converted to quosures and bare expressions are not allowed, which means env is always ignored on eval_tidy().

@yutannihilation
Copy link
Member Author

May I merge this? I'll keep this open for a day or so in case we need further discussion. Feel free to merge if you need to run revdepchecks early.

@yutannihilation yutannihilation added this to the ggplot2 3.3.0 milestone Jan 23, 2020
@thomasp85
Copy link
Member

You can merge at your leisure - we won't run revdeps before after the conf anyway

@yutannihilation
Copy link
Member Author

Sure.

@yutannihilation yutannihilation merged commit 5e6b1e5 into tidyverse:v3.3.0-rc Jan 25, 2020
@yutannihilation yutannihilation deleted the fix/issue-2963-tolerant-facet-rc branch January 25, 2020 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants