Search code examples
rdplyrrlangtidyeval

How do I use .data in filter_at?


The following code will filter a table of isotope combinations to identify combinations where only one element is isotopically enriched.

df <- tibble::tibble(
  C12 = rep(c(2:0), 2),
  C13 = rep(c(0:2), 2),
  H1 = rep(c(0, 1), each = 3),
  H2 = rep(c(1, 0), each = 3)
)

element_filter <- "H2"

dplyr::filter_at(df, dplyr::vars(element_filter), dplyr::all_vars(. == 0))

I would like to include this code in a package and avoid the no visible binding for global variable ‘.’ warning. When I change the filter_at call to

dplyr::filter_at(df, dplyr::vars(element_filter), dplyr::all_vars(.data == 0))

I receive the following error, Error: (list) object cannot be coerced to type 'double'. I am successfully using the .data pronoun in other functions, but am unable to figure out how to get it working here. Appreciate the help.


Solution

  • While many functions often support both . and .data, they are not interchangable in general. Specifically, filter_at calls an internal function apply_filter_syms. That function in turn maps the . pronoun to the symbol being looked at, as seen in the following line of source code:

    pred <- map(syms, function(sym) expr_substitute(pred, quote(.), sym))
    

    Note that there is no mention of .data anywhere in that function. Because there is no special treatment of .data, it is treated like any other variable. R will traverse the calling stack until it finds the definition of .data, which in the dplyr world is a pronoun used to refer to "the current data frame". Your filter predicate is then comparing the entire data frame to 0, not just the columns of interest. This results in the error you're observing.

    Rather than trying to get the function working with .data, I suggest instead tackling the original warning instead.