Search code examples
rdplyrnse

Non standard evaluation of date condition with filter function


I'm trying to use dplyr::filter() with NSE, but I can't make it work when the filtered variable is as.Date().

Here the function that almost works:

foo <- function(d, f, var) {
  d %>% 
    filter_(paste0(var, ">=", f))
}

d <- data.frame(a=1:10, b=1)
foo(d, f=5, var="a")
#    a b
# 1  5 1
# 2  6 1
# 3  7 1
# 4  8 1
# 5  9 1
# 6 10 1

But if a is a date it won't work:

d <- data.frame(a=seq.Date(as.Date("2019-01-01"), length.out = 7, by="day"), b=1)

foo(d, f=as.Date("2019-01-05"), var="a") # or foo(d, f="2019-01-05", var="a")
#            a b
# 1 2019-01-01 1
# 2 2019-01-02 1
# 3 2019-01-03 1
# 4 2019-01-04 1
# 5 2019-01-05 1
# 6 2019-01-06 1
# 7 2019-01-07 1

Also I've tried with this:

foo2 <- function(d, f, var) {
  d %>% 
    filter(!!var >= f)
}
#foo2(d, f=5, var="a")
#foo2(d, f="2019-01-05", var="a")

Which doensn't work in neither cases, I'm interested in knowing also why foo2 it's not working.


Solution

  • You don't need !! (rlang::). Enclose var into as.name (or as.symbol) to make into a symbol and then use eval() inside filter to evaluate the object at the function environment:

    library(magrittr)
    library(dplyr)    
    
    d <- data.frame(a=seq.Date(as.Date("2019-01-01"), length.out = 7, by="day"), b=1)
    
    foo2 <- function(d, f, var) {
      sym <- as.name(var)
    
      d %>% 
        filter(eval(sym) >= f)
    }
    

    Result:

    > foo2(d, f="2019-01-05", var="a")
               a b
    1 2019-01-05 1
    2 2019-01-06 1
    3 2019-01-07 1