Reputation: 4879
I am trying to use rlang
to write custom functions. Although I can do this when functions involve data
argument, I have trouble how to use quasiquotations properly when the functions require vectors and I need to use the $
operator.
Here is a toy example-
library(tidyverse)
# proper implementation
tryfn <- function(data, x, y) {
# creating a dataframe
data <-
dplyr::select(
.data = data,
!!rlang::enquo(x),
!!rlang::enquo(y)
) %>% # dropping unused levels
dplyr::mutate(.data = .,
!!rlang::enquo(x) := droplevels(as.factor(!!rlang::enquo(x))))
# checking if data is getting imported properly
print(data)
# figuring out number of levels in the grouping factor
return(length(levels(data$`!!rlang::enquo(x)`))[[1]])
}
# using the function
tryfn(ggplot2::msleep, vore, brainwt)
#> # A tibble: 83 x 2
#> vore brainwt
#> <fct> <dbl>
#> 1 carni NA
#> 2 omni 0.0155
#> 3 herbi NA
#> 4 omni 0.00029
#> 5 herbi 0.423
#> 6 herbi NA
#> 7 carni NA
#> 8 <NA> NA
#> 9 carni 0.07
#> 10 herbi 0.0982
#> # ... with 73 more rows
#> Warning: Unknown or uninitialised column: '!!rlang::enquo(x)'.
#> [1] 0
As can be seen here, the data is getting imported properly, but the return
value is incorrect because I don't how to use quasiquotation in the context of $
operator. How can I do this?
Upvotes: 2
Views: 217
Reputation: 43334
You can use dplyr::pull
to extract a column using similar semantics to select
. Using rlang 0.4's {{...}}
for interpolation (enquo
and !!
in one) and simplifying a bit,
library(tidyverse)
tryfn <- function(data, x, y) {
data <- data %>% transmute({{x}} := as.factor({{x}}), {{y}})
print(data)
data %>% pull({{x}}) %>% nlevels()
}
tryfn(ggplot2::msleep, vore, brainwt)
#> # A tibble: 83 x 2
#> vore brainwt
#> <fct> <dbl>
#> 1 carni NA
#> 2 omni 0.0155
#> 3 herbi NA
#> 4 omni 0.00029
#> 5 herbi 0.423
#> 6 herbi NA
#> 7 carni NA
#> 8 <NA> NA
#> 9 carni 0.07
#> 10 herbi 0.0982
#> # … with 73 more rows
#> [1] 4
Upvotes: 1
Reputation: 886928
We can convert to the character
class with as_name
and extract with [[
. To avoid repeating conversion with enquo
, do it in once, store in an identifier and reuse
tryfn <- function(data, x, y) {
x <- rlang::enquo(x)
y <- rlang::enquo(y)
# creating a dataframe
data <-
dplyr::select(
.data = data,
!!x,
!!y
) %>% # dropping unused levels
dplyr::mutate(.data = .,
!!x := droplevels(as.factor(!!x)))
# checking if data is getting imported properly
print(data)
# figuring out number of levels in the grouping factor
return(length(levels(data[[rlang::as_name(x)]]))[[1]])
}
-testing
tryfn(ggplot2::msleep, vore, brainwt)
# A tibble: 83 x 2
# vore brainwt
# <fct> <dbl>
# 1 carni NA
# 2 omni 0.0155
# 3 herbi NA
# 4 omni 0.00029
# 5 herbi 0.423
# 6 herbi NA
# 7 carni NA
# 8 <NA> NA
# 9 carni 0.07
#10 herbi 0.0982
# … with 73 more rows
#[1] 4
Upvotes: 4