Search code examples
rtidyversense

- operator with gather using non standard evaluation


I'd like to write a function that takes a quosure as an argument, appends - to the quosure, and passes that to gather, like so:

library(tidyverse)
my_gather <- function(d, not.columns) {
  dg <- tidyr::gather(d, key = k, value = v, .dots = -!!!not.columns)
  dg
}

de <- my_gather(mtcars, not.columns = quos(mpg, cyl, disp))

> Error in `-`(~mpg, ~cyl, ~disp) : operator needs one or two arguments

This is clearly because I need to append each element of the quosure with -, rather than appending the entire quosure with -. But in my work, it won't be easy to create this quosure in the form of quos(-mpg, -cyl, -disp) - so how can I modify quos(mpg, cyl, disp) to add the -?

I would like to see a result that is identical to gather(mtcars, key = k, value = v, -mpg, -cyl, -disp), the first 3 rows of which are

   mpg cyl disp  k   v
1 21.0   6  160 hp 110
2 21.0   6  160 hp 110
3 22.8   4  108 hp  93

There's a similar question here, but it is unanswered and doesn't seem to deal with the issue of quos() rather than quo().


Solution

  • We can do

    my_gather <- function(d, not.columns) {
      tidyr::gather(d, key = k, value = v, .dots =  -c(UQS(not.columns)))
      #or use !!! instead of UQS
      #tidyr::gather(d, key = k, value = v, .dots =  -c(!!!(not.columns)))
    
    }
    de <- my_gather(mtcars, not.columns = quos(mpg, cyl, disp))
    head(de, 3)
    #   mpg cyl disp  k   v
    #1 21.0   6  160 hp 110
    #2 21.0   6  160 hp 110
    #3 22.8   4  108 hp  93
    

    Checking with the output without the function

    de1 <- gather(mtcars, key = k, value = v, -mpg, -cyl, -disp)
    identical(de, de1)
    #[1] TRUE