I am re-writing a function that produces a plot, so that the output is powered by plotly.
The original function uses dplyr programming style. It has a data-variable in the function arguments and it embraces "the argument by surrounding it in doubled braces, like filter(df, {{ var }})".
So far so good, it works fine to pre-process the data and the result can be used to create the plot. reprex below works and produces this silly plot.
foo <- function(data, var) {
plot_data <- data |>
dplyr::summarise(min = min({{ var }}), max = max({{ var }}))
plot_data
}
foo(mtcars, mpg)
#> min max
#> 1 10.4 33.9
plotly::plot_ly(data = foo(mtcars, mpg)) |>
plotly::add_trace(
x = ~min,
y = ~max,
type = "scatter",
mode = "markers"
)

Created on 2022-05-31 by the reprex package (v2.0.1)
Now, if I want to integrate the plot in the function, I get the error below.
bar <- function(data, var) {
plot_data <- data |>
dplyr::summarise(min = min({{ var }}), max = max({{ var }}))
plotly::plot_ly(data = plot_data) |>
plotly::add_trace(
x = ~min,
y = ~max,
type = "scatter",
mode = "markers"
)
}
bar(mtcars, mpg)
#> Error in as.list.environment(x, all.names = TRUE): object 'mpg' not found
Created on 2022-05-31 by the reprex package (v2.0.1)
It's like plotly does not get along with having a variable var that should only be evaluated within the data environment, even though the code never explicitly passes var to plotly. plotly should only be aware of plot_data passed to the data argument, and the expressions ~min and ~max, passed to the x and y arguments of the add_trace function. But still, it tries to find mpg in the function environment.
It seems somewhere in the plotly code they call as.list.environment(x, all.names = TRUE), effectively evaluating all objects in the function environment. But I do not really get why is this and how to circumvent it.
A clear workaround could be to pass the variable name as a character vector and use the .data pronoun for wrangling the data.
bar <- function(data, var) {
plot_data <- data |>
dplyr::summarise(min = min(.data[[var]]), max = max(.data[[var]]))
plotly::plot_ly(data = plot_data) |>
plotly::add_trace(
x = ~min,
y = ~max,
type = "scatter",
mode = "markers"
)
}
bar(mtcars, "mpg")

Created on 2022-05-31 by the reprex package (v2.0.1)
That works, I guess because the character vector can always be successfully evaluated in the function environment. But I would really like to keep the interface as in the first attempt.
Any ideas how to deal with this?