I am building a shiny app which needs to allow users to define new variables for plotting. Specifically I want to allow users to define an expression to be used in mutate ve
We can use rlang::parse_quosure()
together with !!
(bang bang) to produce the same result:
parse_quosure
: parses the supplied string and converts it into a quosure
!!
: unquotes a quosure so it can be evaluated by tidyeval
verbs
Note that parse_quosure()
was soft-deprecated and renamed to parse_quo()
in rlang 0.2.0
per its documentation. If we use parse_quo()
, we need to specify the environment for the quosures e.g. parse_quo(input_from_shiny, env = caller_env())
library(rlang)
library(tidyverse)
input_from_shiny <- "Petal.ratio = Petal.Length/Petal.Width"
iris_mutated <- iris %>% mutate_(input_from_shiny)
iris_mutated2 <- iris %>%
mutate(!!parse_quosure(input_from_shiny))
head(iris_mutated2)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
#> Petal.ratio = Petal.Length/Petal.Width
#> 1 7.00
#> 2 7.00
#> 3 6.50
#> 4 7.50
#> 5 7.00
#> 6 4.25
identical(iris_mutated, iris_mutated2)
#> [1] TRUE
Edit: to separate LHS & RHS
lhs <- "Petal.ratio"
rhs <- "Petal.Length/Petal.Width"
iris_mutated3 <- iris %>%
mutate(!!lhs := !!parse_quosure(rhs))
head(iris_mutated3)
> head(iris_mutated3)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
Petal.ratio
1 7.00
2 7.00
3 6.50
4 7.50
5 7.00
6 4.25
Created on 2018-03-24 by the reprex package (v0.2.0).
Package friendlyeval is a simplified interface to tidy eval that tries to make things a bit more straight forward in cases like these.
Splitting your string in two, you obtain part of the string you wish to use as a column name and part of a string you wish to use as an expression. So you could write:
library(friendlyeval)
library(dplyr)
lhs <- "Petal.ratio"
rhs <- "Petal.Length/Petal.Width"
iris_mutated3 <-
iris %>%
mutate(!!treat_string_as_col(lhs) := !!treat_string_as_expr(rhs))
head(iris_mutated3)
By using the function on the lhs, you gain checking that lhs
can be parsed as plain column name.
friendlyeval
code can be converted to plain tidy eval code at any time using an RStudio addin.