Reputation: 8890
I want to use tidy evaluation for ggplot's facet_grid
, but don't know how to allow for missing arguments?
ggplot2
3.0.0 introduced the function vars()
(see news), to use tidy
evaluation in for example facet_grid. But it is not clear to me how to handle missing/NULL arguments?
In the following code, how do I do so that no passing any argument to wrap_by
(i.e. using p + wrap_by()
) does not return an error?
library(ggplot2)
#> Registered S3 methods overwritten by 'ggplot2':
#> method from
#> [.quosures rlang
#> c.quosures rlang
#> print.quosures rlang
p <- ggplot(mtcars, aes(wt, disp)) + geom_point()
wrap_by <- function(...) {
facet_wrap(vars(...), labeller = label_both)
}
p + wrap_by() #ERROR!
#> Can't subset with `[` using an object of class NULL.
Use case: I want to have a function to define the facet variables, but want to make them optional.
fac_by <- function(var_fac1, var_fac2) {
facet_grid(rows=vars(!!enquo(var_fac1)),
cols=vars(!!enquo(var_fac2)))
}
p+ fac_by(vs, am)
p+ fac_by(var_fac1=vs) # won't work
The issue here is that ideally I would allow for either row, either col, both (ideally none also, though this does not seem possible with facet_grid(NULL, NULL)
)
Upvotes: 2
Views: 1133
Reputation: 47320
You can do :
fac_by <- function(var_fac1, var_fac2) {
# retrieve the arguments from the call
args_ <- rlang::call_args(match.call())
# rename them (use na.omit on top of it if you have more arguments)
names(args_) <- c(var_fac1 = "rows", var_fac2 = "cols")[names(args_)]
# apply vars on them
args_ <- purrr::map(args_, vars)
# build the call
call_ <- as.call(c(quote(facet_grid),args_))
eval(call_)
}
p+ fac_by(vs, am)
p+ fac_by(var_fac1=vs)
Using if
and missing
awould arguably be simpler though :
fac_by <- function(var_fac1, var_fac2) {
facet_grid(rows=if(missing(var_fac1)) NULL else enquos(var_fac1),
cols=if(missing(var_fac2)) NULL else enquos(var_fac2))
}
p+ fac_by(vs, am)
p+ fac_by(var_fac1=vs)
Note you can use enquos(var_fac1)
instead of vars(!!enquo(var_fac1)
Upvotes: 1
Reputation: 887223
Based on the updated code for facet_grid
an option would be to pass an expression
library(rlang)
library(ggplot2)
fac_by <- function(...) {
e1 <- enexprs(...)
do.call(facet_grid, e1)
}
p + fac_by(rows = vars(vs), cols = vars(am))
p + fac_by(rows = vars(vs))
p + fac_by(cols = vars(am))
Upvotes: 1