Reputation: 3367
Is it possible to refer to a variable name after renaming it using tidy evaluation? As an example, I would like to write a function that does the same as the following code but allows to specify the new variable name in a function argument:
library(tidyverse)
mtcars %>%
rename(cylinder = cyl) %>%
group_by(cylinder) %>%
summarize(mean_mpg = mean(mpg))
However, I am stuck in the group_by
line (in the code below) because neither !!varname
nor {{ varname }}
works as a replacement for the question marks. I assume that !!varname
does not work because it expands to a character string; and that {{ varname }}
does not work because no column with the new name exists when the function is called. I don't see a way to use the glue
syntax either because nothing is being assinged in that line.
my_rename <- function(df, varname) {
df %>%
rename("{varname}" := cyl) %>%
group_by(???) %>%
summarize(mean_mpg = mean(mpg))
}
Upvotes: 1
Views: 1170
Reputation: 6803
Regarding the glue syntax, you need "{{ varname }}" :=
instead of "{varname}"
. The simple curly is normal glue syntax, it fetches a string inside a variable. The double curly is extended glue syntax, it looks across function arguments to see what the user typed. So the correct syntax is:
my_rename <- function(df, varname) {
df %>%
rename("{{ varname }}" := cyl) %>%
group_by({{ varname }}) %>%
summarize(mean_mpg = mean(mpg))
}
my_rename(mtcars, cylinder)
#> # A tibble: 3 x 2
#> cylinder mean_mpg
#> <dbl> <dbl>
#> 1 4 26.7
#> 2 6 19.7
#> 3 8 15.1
Now let's unpack the behaviour with your original code:
my_rename <- function(df, varname) {
df %>%
rename("{varname}" := cyl)
}
my_rename(mtcars, cylinder)
#> Error: object 'cylinder' not found
The problem here is that "{varname"}
is essentially doing this:
cylinder
#> Error: object 'cylinder' not found
Instead of this:
rlang::quo(cylinder)
#> <quosure>
#> expr: ^cylinder
#> env: global
Upvotes: 3
Reputation: 21918
In order for your function to work you first have to defuse your custom argument name. For this purpose we could use either ensym
or enquo
function for defusing user defined arguments. After that you should use bang bang (!!)
operator to unquote it.
my_rename <- function(df, varname) {
varname <- ensym(varname)
df %>%
rename(!!varname := cyl) %>%
group_by(!!varname) %>%
summarize(mean_mpg = mean(mpg))
}
my_rename(mtcars, cylinder)
# A tibble: 3 x 2
cylinder mean_mpg
<dbl> <dbl>
1 4 26.7
2 6 19.7
3 8 15.1
Here is another way that we use enquo
function instead of ensym
:
my_rename <- function(df, varname) {
varname <- enquo(varname)
df %>%
rename(!!varname := cyl) %>%
group_by(!!varname) %>%
summarize(mean_mpg = mean(mpg))
}
# A tibble: 3 x 2
cylinder mean_mpg
<dbl> <dbl>
1 4 26.7
2 6 19.7
3 8 15.1
Upvotes: 3
Reputation: 603
Running both with {{varname}} seems work
my_rename <- function(df, varname) {
df %>%
rename({{varname}} := cyl) %>%
group_by({{varname}}) %>%
summarize(mean_mpg = mean(mpg))
}
my_rename(mtcars, cylinder)
# A tibble: 3 x 2
cylinder mean_mpg
<dbl> <dbl>
1 4 26.7
2 6 19.7
3 8 15.1
Upvotes: 6