R ggplot2 facet_grid с vars(): как обработать отсутствующий аргумент?

Я хочу использовать аккуратное вычисление для facet_grid ggplot, но не знаю, как разрешить отсутствующие аргументы?

ggplot2 3.0.0 представила функцию vars() (см. новости ), чтобы использовать аккуратное вычисление, например, в facet_grid. Но мне непонятно, как обрабатывать отсутствующие/NULL аргументы?

В следующем коде, как мне сделать так, чтобы передача любого аргумента в wrap_by (т. е. использование p + wrap_by()) не возвращала ошибку?

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.

Вариант использования: я хочу иметь функцию для определения переменных фасета, но хочу сделать их необязательными.

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

Проблема здесь в том, что в идеале я бы разрешил либо строку, либо столбец, либо оба (в идеале также ни одного, хотя это не представляется возможным с facet_grid(NULL, NULL))


person Matifou    schedule 25.05.2019    source источник
comment
Спасибо за отзыв, обновил, надеюсь теперь стало понятнее?   -  person Matifou    schedule 26.05.2019
comment
Это принципиально другое? Я надеялся, что vars() можно использовать с отсутствующими, будь то 3... или аргумент. Но ведь если выбирать, то нужны довольно конкретные аргументы. Спасибо за вашу помощь и извините, что это не так ясно!   -  person Matifou    schedule 26.05.2019


Ответы (2)


Ты можешь сделать :

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)

Однако использование if и missing, возможно, было бы проще:

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)

Обратите внимание, что вы можете использовать enquos(var_fac1) вместо vars(!!enquo(var_fac1)

person Moody_Mudskipper    schedule 05.06.2019

На основе обновленного кода для facet_grid можно было бы передать выражение

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))

введите здесь описание изображения

person akrun    schedule 25.05.2019
comment
Благодарность! Идеальным решением было бы избежать if(), так как я использую его на самом деле с facet_grid, со строками и столбцами, поэтому код быстро станет громоздким (проверьте 4 разных случая?)? - person Matifou; 26.05.2019
comment
@Matifou Можете ли вы уточнить свой комментарий? Если вы не хотите передавать отсутствующие аргументы, вы должны проверить это. Если некоторые функции (я не могу придумать ни одного rn, но) обрабатывают это, это потому, что функция по умолчанию имеет этот оператор if. Покажите нам этот пример из 4 разных случаев, и мы сможем помочь. - person M--; 26.05.2019