4

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.

Will Oldham
  • 704
  • 3
  • 13
  • `dplyr::filter_at(df, dplyr::vars(element_filter), dplyr::all_vars(. == 0))` works for me without any warning. `R version 3.5.2` – Ronak Shah May 15 '19 at 02:14
  • Agree that the posted code works, but when trying to change to `dplyr::filter_at(df, dplyr::vars(element_filter), dplyr::all_vars(.data == 0))`, it doesn't. Why is that? – Will Oldham May 15 '19 at 02:19
  • 1
    hmmm..I am not sure but maybe because `all_vars` doesn't expect `.data` argument? `?all_vars` says it wants input as `expr`. Though I maybe wrong here to interpret. – Ronak Shah May 15 '19 at 02:23
  • Your example can be accomplished with just `filter`. Are there cases where the table would have more than two different chemical elements? Also, do you only want cases where there is exactly one element that's isotopically enriched, or no more than one element that's isotopically enriched? – eipi10 May 15 '19 at 04:58
  • Yes on both counts. `expression_filter` is determined based on a user-provided molecular formula that can also include N, O, S and their isotopes as well as an argument to indicate which element(s) are label-able. – Will Oldham May 15 '19 at 11:41

1 Answers1

3

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.

Artem Sokolov
  • 13,196
  • 4
  • 43
  • 74
  • 2
    I had been wondering if this was the case and did not know how to track down the answer. Thank you! I like the `. <- "Shut up"` solution I had seen elsewhere... – Will Oldham May 17 '19 at 21:17