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
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()
.