Tidy Evaluation Not Substituting in Complex Mutate

rlang

#1

I’m trying to build a rather complex function using text inputs to define a column and make names. But, when I put everything together it doesn’t substitute one of the instances.

library(tidyverse)


do_something <-
	function(df, check1, check2, trait) {
		
		trait_sym <- rlang::sym(trait)
		
		check1_pred <- rlang::sym(paste0(check1,"_pred"))
		check1_cor 	<- rlang::sym(paste0(check1,"_cor"))
		trait_cor 	<- rlang::sym(paste0(trait,"_cor"))
		
	
		#predictions <-
			quo(df %>%
				# add predictions from krige and computes mean_centered corrections
				mutate(
					!!check1_pred := 1:nrow(df),
					!!check1_cor := (!!trait_sym + mean(!!check1_pred) - !!check1_pred)
					)
			)
	}

do_something(iris, "text", "text2", "Petal.Width")

The output is:

<quosure>
  expr: ^df %>% mutate(text_pred := 1:nrow(df), text_cor := (Petal.Width + mean(!!check1_pred) - text_pred))
  env:  0x7fa068a05e70

It should be:

<quosure>
  expr: ^df %>% mutate(text_pred := 1:nrow(df), text_cor := (Petal.Width + mean(text_pred) - text_pred))
  env:  0x7fa068a05e70

The !!check1_pred isn’t being substituted for some reason. Anyone familiar with rlang enough to help?

> devtools::session_info()
Session info ---------------------------------------------------------------------------------------------------
 setting  value                       
 version  R version 3.4.3 (2017-11-30)
 system   x86_64, darwin15.6.0        
 ui       AQUA                        
 language (EN)                        
 collate  en_US.UTF-8                 
 tz       America/Los_Angeles         
 date     2018-02-08                  

Packages -------------------------------------------------------------------------------------------------------
 package    * version    date       source                              
 assertthat   0.2.0      2017-04-11 CRAN (R 3.4.0)                      
 base       * 3.4.3      2017-12-07 local                               
 bindr        0.1.0.9000 2018-02-05 Github (krlmlr/bindr@4b20179)       
 bindrcpp     0.2.0.9000 2018-02-05 Github (krlmlr/bindrcpp@7553d4f)    
 broom        0.4.2      2018-02-05 Github (tidyverse/broom@4d0c83a)    
 cellranger   1.1.0      2016-07-27 cran (@1.1.0)                       
 cli          1.0.0      2017-11-05 cran (@1.0.0)                       
 colorspace   1.3-2      2016-12-14 CRAN (R 3.4.0)                      
 compiler     3.4.3      2017-12-07 local                               
 crayon       1.3.4      2017-10-31 Github (r-lib/crayon@b5221ab)       
 datasets   * 3.4.3      2017-12-07 local                               
 devtools     1.13.0     2017-05-08 CRAN (R 3.4.0)                      
 digest       0.6.15     2018-01-28 cran (@0.6.15)                      
 dplyr      * 0.7.4.9000 2018-02-05 Github (tidyverse/dplyr@18a65f6)    
 forcats    * 0.2.0      2017-01-23 cran (@0.2.0)                       
 foreign      0.8-69     2017-06-22 CRAN (R 3.4.3)                      
 ggplot2    * 2.2.1.9000 2018-02-05 Github (thomasp85/ggplot2@f53b99f)  
 glue         1.2.0      2017-10-29 cran (@1.2.0)                       
 graphics   * 3.4.3      2017-12-07 local                               
 grDevices  * 3.4.3      2017-12-07 local                               
 grid         3.4.3      2017-12-07 local                               
 gtable       0.2.0      2016-02-26 CRAN (R 3.4.0)                      
 haven        1.1.0      2017-07-09 cran (@1.1.0)                       
 hms          0.4.0      2017-11-23 cran (@0.4.0)                       
 httr         1.3.1      2017-08-20 cran (@1.3.1)                       
 jsonlite     1.5        2017-06-01 cran (@1.5)                         
 lattice      0.20-35    2017-03-25 CRAN (R 3.4.3)                      
 lazyeval     0.2.1      2017-10-29 cran (@0.2.1)                       
 lubridate    1.7.1      2017-11-03 cran (@1.7.1)                       
 magrittr     1.5        2014-11-22 CRAN (R 3.4.0)                      
 memoise      1.1.0      2017-04-21 CRAN (R 3.4.0)                      
 methods    * 3.4.3      2017-12-07 local                               
 mnormt       1.5-5      2016-10-15 cran (@1.5-5)                       
 modelr       0.1.1      2017-07-24 cran (@0.1.1)                       
 munsell      0.4.3      2016-02-13 CRAN (R 3.4.0)                      
 nlme         3.1-131    2017-02-06 CRAN (R 3.4.3)                      
 parallel     3.4.3      2017-12-07 local                               
 pillar       1.1.0      2018-02-05 Github (hadley/pillar@872357a)      
 pkgconfig    2.0.1      2017-03-21 cran (@2.0.1)                       
 plyr         1.8.4      2016-06-08 CRAN (R 3.4.0)                      
 psych        1.7.3.21   2017-03-22 cran (@1.7.3.2)                     
 purrr      * 0.2.4.9000 2018-02-05 Github (tidyverse/purrr@b6a0304)    
 R6           2.2.2      2017-06-17 cran (@2.2.2)                       
 Rcpp         0.12.15    2018-01-20 cran (@0.12.15)                     
 readr      * 1.1.1      2017-05-16 cran (@1.1.1)                       
 readxl       1.0.0      2017-04-18 cran (@1.0.0)                       
 reshape2     1.4.3      2017-12-11 cran (@1.4.3)                       
 rlang        0.1.6.9003 2018-02-05 Github (tidyverse/rlang@c6747f9)    
 rstudioapi   0.7        2017-09-07 cran (@0.7)                         
 rvest        0.3.2      2016-06-17 cran (@0.3.2)                       
 scales       0.5.0.9000 2017-10-10 Github (hadley/scales@d767915)      
 stats      * 3.4.3      2017-12-07 local                               
 stringi      1.1.6      2017-11-17 cran (@1.1.6)                       
 stringr    * 1.2.0      2017-02-18 CRAN (R 3.4.0)                      
 tibble     * 1.4.2      2018-01-22 cran (@1.4.2)                       
 tidyr      * 0.8.0      2018-01-29 cran (@0.8.0)                       
 tidyselect   0.2.3      2017-11-06 cran (@0.2.3)                       
 tidyverse  * 1.2.1      2017-12-08 Github (tidyverse/tidyverse@3769ff2)
 tools        3.4.3      2017-12-07 local                               
 utils      * 3.4.3      2017-12-07 local                               
 withr        2.1.1.9000 2018-01-15 Github (jimhester/withr@df18523)    
 xml2         1.1.1      2017-01-24 CRAN (R 3.4.0)   

#2

The code you have pasted into your question doesn’t run as is. We need run-able code to help you.

You should include a reprex in your code so that we can be sure we can run it. Here is a pointer to reprex.

http://reprex.tidyverse.org/articles/reprex.html

When you make the reprex it will show the results you are getting and make it a lot easier for us to help you. There a many people here who want to help but you have to make it easy for us to do that. The way to do that is to include a reprex.

You’ve have included the results you expect, that’s good but now include a reprex what you are trying to do.


#3

This is incorrect @danr .

In a fresh session of R this is a reproducible example of my problem using the iris dataset.

Perhaps you need to update your packages? See attached session_info() for what I’m working with.

> library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 2.2.1.9000     ✔ purrr   0.2.4.9000
✔ tibble  1.4.2          ✔ dplyr   0.7.4.9000
✔ tidyr   0.8.0          ✔ stringr 1.2.0     
✔ readr   1.1.1          ✔ forcats 0.2.0     
── Conflicts ─────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
> 
> 
> do_something <-
+ 	function(df, check1, check2, trait) {
+ 		
+ 		trait_sym <- rlang::sym(trait)
+ 		
+ 		check1_pred <- rlang::sym(paste0(check1,"_pred"))
+ 		check1_cor 	<- rlang::sym(paste0(check1,"_cor"))
+ 		trait_cor 	<- rlang::sym(paste0(trait,"_cor"))
+ 		
+ 	
+ 		#predictions <-
+ 			quo(df %>%
+ 				# add predictions from krige and computes mean_centered corrections
+ 				mutate(
+ 					!!check1_pred := 1:nrow(df),
+ 					!!check1_cor := (!!trait_sym + mean(!!check1_pred) - !!check1_pred)
+ 					)
+ 			)
+ 	}
> 
> do_something(iris, "text", "text2", "Petal.Width")
<quosure>
  expr: ^df %>% mutate(text_pred := 1:nrow(df), text_cor := (Petal.Width + mean(!!check1_pred) - text_pred))
  env:  0x7fdeb686f2d0
> 

#4

@jimhester provided an answer in another forum.

You are being bitten by the precedence between ! and +
You can either 1. only use !! for the whole left hand expression, e.g.
!!trait_sym + mean(check1_pred) - max(check1_pred)
Or force tight binding by closing in parens

The solution that works is wrapping things in parentheses:

library(tidyverse)


do_something_paren <-
	function(df, check1, check2, trait) {
		
		trait_sym <- rlang::sym(trait)
		
		check1_pred <- rlang::sym(paste0(check1,"_pred"))
		check1_cor 	<- rlang::sym(paste0(check1,"_cor"))
		trait_cor 	<- rlang::sym(paste0(trait,"_cor"))
		
	
		#predictions <-
			quo(df %>%
				# add predictions from krige and computes mean_centered corrections
				mutate(
					!!check1_pred := 1:nrow(df),
					!!check1_cor := (!!trait_sym) + mean( !!check1_pred ) - (!!check1_pred)
					)
			)
	}

do_something_paren(iris, "text", "text2", "Petal.Width")


#5

My packages are up to date. Your code produces this:

do_something(iris, “text”, “text2”, “Petal.Width”)
Error in !check1_pred : invalid argument type

It is much more helpful if you run your code in a reprex. That way your code is running in a fresh session with no variables left over in the environment which might be by happenstance making it run.

Also the output reprex create can be copied into a question and then copied out for us to run. The code you show in this post just can’t be copied without a lot of editing.


#6

I know what you’re saying @danr. Truly I do, I’ve been asking for reprex examples on the ggplot2 mailing list for almost 9 years.

But, this is a reprex. I have nothing loaded in R.
ls() returns character(0). Iris is available in base.

In this session, I copy and paste from this page (without editing) and it works exactly as I have stated. It works in both R-GUI an R-studio.
I have listed my session_info. I typically run on the cutting edge from github because the tidyverse is under very active development, so perhaps I have some things you don’t?
Check your package versions and see where we don’t agree and perhaps that is why you see an error and I don’t.

Beyond that. I appreciate your effort at helping.


#7

Hey,

One other solution is to use UQ() instead of !!. It allows you to precisely control what you need to unquote, and can save some headache when combining tidyeval and infix operators :slight_smile:

library(tidyverse)
library(rlang)


do_something <-
  function(df, check1, check2, trait) {
    
    trait_sym <- rlang::sym(trait)
    
    check1_pred <- rlang::sym(paste0(check1,"_pred"))
    check1_cor 	<- rlang::sym(paste0(check1,"_cor"))
    trait_cor 	<- rlang::sym(paste0(trait,"_cor"))
    
    
    #predictions <-
    quo(df %>%
          # add predictions from krige and computes mean_centered corrections
          mutate(
            !!check1_pred := 1:nrow(df),
            !!check1_cor := UQ(trait_sym) + mean(UQ(check1_pred)) - UQ(check1_pred)
          )
    )
  }

do_something(iris, "text", "text2", "Petal.Width")

Colin


#8

@bhive01 Could you try again with the latest development version of rlang please? This should be fixed.


#9

@lionel, indeed this now works.

> library(tidyverse)
── Attaching packages ─────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 2.2.1.9000     ✔ purrr   0.2.4.9000
✔ tibble  1.4.2          ✔ dplyr   0.7.4.9000
✔ tidyr   0.8.0          ✔ stringr 1.2.0     
✔ readr   1.1.1          ✔ forcats 0.2.0     
── Conflicts ────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
> 
> 
> do_something <-
+ 	function(df, check1, check2, trait) {
+ 		
+ 		trait_sym <- rlang::sym(trait)
+ 		
+ 		check1_pred <- rlang::sym(paste0(check1,"_pred"))
+ 		check1_cor 	<- rlang::sym(paste0(check1,"_cor"))
+ 		trait_cor 	<- rlang::sym(paste0(trait,"_cor"))
+ 		
+ 	
+ 		#predictions <-
+ 			quo(df %>%
+ 				# add predictions from krige and computes mean_centered corrections
+ 				mutate(
+ 					!!check1_pred := 1:nrow(df),
+ 					!!check1_cor := (!!trait_sym + mean(!!check1_pred) - !!check1_pred)
+ 					)
+ 			)
+ 	}
> 
> do_something(iris, "text", "text2", "Petal.Width")
<quosure>
  expr: ^df %>% mutate(text_pred := 1:nrow(df), text_cor := (Petal.Width + mean(
          text_pred) - text_pred))
  env:  0x7fb1f9370350

How did you fix the precedence issue?
CC: @jimhester


#10

The algorithm is described there: https://github.com/r-lib/rlang/blob/master/src/internal/expr-interp-rotate.c