I am trying to wrap my head around why in one function a dplyr command will work with !! on one line but a dplyr function in another line will need eval().
I have a dataset with one column of UTC time and one of PT time and I want users to be able to pick which timezone their visualization is in.
Setup toy dataset and helper function:
library(tibble)
library(dplyr)
repro_data <- tribble(
~created_at, ~created_at_pt,
"2017-12-31 00:33:11", "2017-12-31 00:33:11",
"2018-01-01 00:03:57", "2017-12-31 16:03:57",
"2018-01-01 14:40:18", "2018-01-01 14:40:18") %>%
mutate(created_at = as.POSIXct(created_at),
created_at_pt = as.POSIXct(created_at_pt))
set_timezone <- function(timezone_str){
if(timezone_str == 'pt'){
tz <- quo(created_at_pt)
}else{
tz <- quo(created_at)
}
tz
}
I have been going over the Advanced R section on this but something isn't clicking for me in understanding why !! works in the mutate but not the filter:
broken_fun <- function(timezone) {
report_tz <- set_timezone(timezone)
repro_data %>%
filter(!!report_tz >= lubridate::ymd('2018-01-01')) %>%
mutate(bought_day = lubridate::floor_date(!!report_tz, 'day'))
}
broken_fun('pt')
broken_fun('utc')
# Both return empty dataframes
# I think because it's comparing a date object to a... something else
However, by using eval in the filter it works as expected:
working_fun <- function(timezone) {
report_tz <- set_timezone(timezone)
repro_data %>%
filter(eval(report_tz) >= lubridate::ymd('2018-01-01')) %>%
mutate(bought_day = lubridate::floor_date(!!report_tz, 'day'))
}
working_fun('pt')
working_fun('utc')
# Both return expected results filtered with new column
Using eval for both also seems to work... although when I look at other people's code it appears that !! is preferred by most people (at least in open source)?
working_fun2 <- function(timezone) {
report_tz <- set_timezone(timezone)
repro_data %>%
filter(eval(report_tz) >= lubridate::ymd('2018-01-01')) %>%
mutate(bought_day = lubridate::floor_date(eval(report_tz), 'day'))
}
working_fun2('pt')
working_fun2('utc')
# Both return expected results filtered with new column
So I no have it working which is nice, but I would love to understand why the initial way did not work since I am hoping to do a lot more work with user inputs. Thanks in advance!
Edit: Apparently multiple exclamation points are replaced with a single one in the title section of a new post.