Недавно пытаясь исправить проблему с передачей аргументов из функции на основе dplyr
в функцию ggplot
, я с удивлением обнаружил, что существует совершенно новое программирование с dplyr
виньетка и соответствующая версия для ggplot2
в пакетах . Я надеялся убить двух зайцев одним выстрелом: изучить новые заклинания tidyeval и избавиться от своей проблемы.
Мне нужна была функция для создания пользовательских графиков, которые иногда могут быть вызваны другой функцией, которая выполняет некоторые предварительные операции. -обработка предоставленных данных; но это было не так:
library(ggplot2)
library(dplyr)
my_plot <- function(df, x_var, colour_var = "cyl") {
char_col <- df %>%
pull(colour_var) %>%
is.character()
if(!char_col ) cat(colour_var, "is not character.")
ggplot(df) +
geom_point(aes(x = !! ensym(x_var), y = hp, colour = !!ensym(colour_var))) +
labs(title = paste("Passed in x variable:", x_var))
}
process_n_plot <- function(x_var, val, colour_var) {
cat("You are filtering variable", x_var, "\n")
mtcars %>%
filter(!!ensym(x_var) > val) %>%
my_plot(x_var = x_var, colour_var = colour_var)
}
process_n_plot("disp", 200, "cyl")
#> You are filtering variable "disp"
#> cyl is not character.
my_plot(mtcars, "disp", "cyl")
#> cyl is not character.
I realise I could have just used aes_string
... But I was actually operating in ggraph
and forgot 'cause I'd never used aes_string
there. Also, having strings as arguments was me assuming it would the most straightforward way, but still preferred to call the functions with unquoted variable names.
So, things worked when calling my_plot
directly; and almost worked when called "indirectly". The vignettes didn't quite cover these use cases, so I had to test.
However, replacing !!ensym(x_var)
with {{x_var}}
above does not work; neither does the naïve approach below with bare variable names. {{}}
as per the vignettes seems to combine the steps of enquo(s)
and !!(!)
but that poses a problem when trying to use something like as_label
/as_string
, which want you to enquo
but not !!
.
library(ggplot2)
library(dplyr)
library(rlang)
my_plot <- function(df, x_var, colour_var = "cyl") {
discrete_col <- df %>%
pull(colour_var) %>%
is.character()
if(!discrete_col) cat(colour_var, "is not character.")
ggplot(df) +
geom_point(aes(x = {{ x_var }}, y = hp, colour = {{ colour_var }})) +
labs(title = paste("Passed in x variable:", as_label({{ x_var }})))
}
process_n_plot <- function(x_var, val, colour_var) {
cat("You are filtering variable", as_label( {{ x_var }} ), "\n")
mtcars %>%
filter({{ x_var }} > val) %>%
my_plot(x_var = x_var, colour_var = colour_var)
}
process_n_plot(disp, 200, cyl)
#> Error in is_quosure(quo): object 'disp' not found
my_plot(mtcars, disp, cyl)
#> Error: object 'cyl' not found
Обратите внимание, что удаление labs
делает my_plot
работает нормально, как и ожидалось из виньетки.