3

I'm trying to capture a summarize_at operation across a bunch of variables. Here's a silly example:

library(dplyr)
library(stringr)

starwars %>%
  summarise_at(c("hair_color", "skin_color"), 
               ~ sum(if_else(str_detect(., "brown"), 1, birth_year), na.rm = TRUE))

# A tibble: 1 x 2
  hair_color skin_color
       <dbl>      <dbl>
1      2399.      3123.

Let's say that I want to capture this into a function, in which I can change birth_year to something else.

myfun <- function(df, var) {
  df %>% 
    summarize_at(c("hair_color", "skin_color"), 
                 ~ sum(if_else(str_detect(., "brown"), 1, !! enquo(var)), na.rm = TRUE))
}

myfun(starwars, birth_year)

Error in is_quosure(e2) : argument "e2" is missing, with no default 

What am I missing? I'm using dplyr v0.8.0.1, stringr v1.4, and rlang v0.3.1, running on R v3.5.3

Phil
  • 7,287
  • 3
  • 36
  • 66
  • `(!!as.symbol(var))`? – M-- Mar 12 '19 at 15:33
  • Are you sure the first code chunk works in a new R session for you? I get an error "object 'birth_year' not found" Is there something missing? – MrFlick Mar 12 '19 at 15:35
  • @MrFlick birth_year is a variable in the starwars dataset that comes with the dplyr package. – Phil Mar 12 '19 at 15:37
  • @M-M Your suggestion returned a "object birth_year not found" error. – Phil Mar 12 '19 at 15:38
  • @Phil Right, but that's not available to the anonymous function you are passing to `sumamrize_at`. Did you run `attach()` or something? Did you run this in a new R session? I guess i'm not using the exact same package versions but i'm surprised that behavior would have changed, – MrFlick Mar 12 '19 at 15:38
  • @MrFlick I'm not using `attach()` and the code above is off a new session. – Phil Mar 12 '19 at 15:40
  • @MrFlick I can run the first chunk with no error. – M-- Mar 12 '19 at 15:44
  • OK. This does seem to be a change in dplyr 0.8. Odd. – MrFlick Mar 12 '19 at 15:44
  • Try `enexpr()` rather than `enquo()`. I think it can't tell what environment you want to grab with your quosure but really you don't seem to care about the environment at all. – MrFlick Mar 12 '19 at 15:48
  • @MrFlick That change gives a "Error in !enexpr(var): invalid argument type" error – Phil Mar 12 '19 at 15:50
  • 2
    @Phil. Sorry. You're right. I had a typo. I seems that this works for me when I wrap the expression in `rlang::eval_tidy(quo(...))` to do the expansion but it seems like you shouldn't have to do that. Maybe this should be posted as an issue at the repo: https://github.com/tidyverse/dplyr/issues – MrFlick Mar 12 '19 at 15:53
  • This seems to be discussed here https://github.com/tidyverse/dplyr/issues/4199 – Phil Mar 12 '19 at 16:26

1 Answers1

2

I guess it is a bug, but in the meanwhile you can do

myfun <- function(df, var) {
  df %>% 
    summarize_at(c("hair_color", "skin_color"), 
                 funs(sum(if_else(str_detect(., "brown"), 1, !! enquo(var)), na.rm = TRUE)))
}
myfun(starwars, birth_year)
# A tibble: 1 x 2
#   hair_color skin_color
#        <dbl>      <dbl>
# 1      2399.      3123.
# Warning message:
# funs() is soft deprecated as of dplyr 0.8.0
# please use list() instead

# # Before:
# funs(name = f(.)

# # After: 
# list(name = ~f(.))  

as a workaround. You get a soft-depreciation warning, but you should not follow the advise there, becasue the bug sits somewhere in teh enquosure of your function.

thothal
  • 16,690
  • 3
  • 36
  • 71
  • Thanks, that's what I've done. I just hope they find a solution before they fully deprecate `funs()`. – Phil Mar 12 '19 at 17:35