rdplyrrlangnse

Using quos with empty argument in R NSE


I'm trying to figure out how I can use optional arguments in an NSE function in my tidyverse workflow. This is a little toy function that I'd like to be able to build upon. I want to be able to operate on a grouped data frame; in this example, I'd like to gather the df, excluding whatever columns the df is grouped by (getting these successfully with groups(df)) and any other optional columns, coming in through .... quos has an argument .ignore_empty, but I'm not sure how to use it exactly. I might be misunderstanding what .ignore_empty does.

I know I can start the function off by checking for missing arguments, then setting up two different sets of piped operations for whether or not there are additional arguments given, but I'd prefer keeping this in a single pipeflow.

Data and the toy function:

library(tidyverse)

df <- structure(list(
    town = c("East Haven", "Hamden", "New Haven","West Haven"), 
    region = c("Inner Ring", "Inner Ring", "New Haven", "Inner Ring"),
    Asian = c(1123, 3285, 6042, 2214), 
    Black = c(693,13209, 42970, 10677), 
    Latino = c(3820, 6450, 37231, 10977), 
    Total = c(29015,61476, 130405, 54972), 
    White = c(22898, 37043, 40164, 28864)), 
    class = c("tbl_df","tbl", "data.frame"), row.names = c(NA, -4L))

test_dots <- function(df, ...) {
    grouping_vars <- groups(df)
    gather_vars <- quos(..., .ignore_empty = "all")
    
    df %>%
        gather(key = variable, value = value, -c(!!!grouping_vars), -c(!!!gather_vars))
}

With a grouped df and a column name received as ...:

df %>%
    group_by(town) %>%
    test_dots(region) %>%
    head()
#> # A tibble: 6 x 4
#> # Groups:   town [4]
#>   town       region     variable value
#>   <chr>      <chr>      <chr>    <dbl>
#> 1 East Haven Inner Ring Asian     1123
#> 2 Hamden     Inner Ring Asian     3285
#> 3 New Haven  New Haven  Asian     6042
#> 4 West Haven Inner Ring Asian     2214
#> 5 East Haven Inner Ring Black      693
#> 6 Hamden     Inner Ring Black    13209

With a grouped df but nothing going into ...:

df %>%
    select(-region) %>%
    group_by(town) %>%
    test_dots()
#> Error in -x: invalid argument to unary operator

Solution

  • I think the problem is that you are trying to negate an empty vector. If you are sure there will always be a at least one grouping or gather variable, then you can do

    test_dots <- function(df, ...) {
      grouping_vars <- groups(df)
      gather_vars <- quos(...)
      vars <- quos(c(!!!grouping_vars), c(!!!gather_vars))
    
      df %>%
        gather(key = variable, value = value, -c(!!!vars))
    }
    

    I don't think the .ignore_empty has anything to do with it because that would just appear to control how quos works, not the gather().