plotly clashes with dplyr programming?

Viewed 85

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?

0 Answers
Related