combine formula and tidy eval (plotly)

眉间皱痕 提交于 2020-12-31 07:57:03

问题


I'm struggling to understand this.

The below lets me filter my data.frame in a "tidy" way, and draw a plot using plotly. In this case, I'm using plotly's formula-based API to say which columns of a data frame to use:

library(plotly)

tidy_filter = function(data, x) {
  x = enquo(x)
  filter(data, !!x > 5)
}

mtcars %>% 
  tidy_filter(wt) %>% 
  plot_ly(x = ~wt, y = ~wt)

I can wrap this in a single function to get the same result:

tidy_ply = function(data, x) {
  x = enquo(x)
  data = filter(data, !!x > 5)
  plot_ly(data, x = x, y = x)
}

tidy_ply(mtcars, wt)

Now:

  1. I assume that enquo(x) in this case is at least in part equivalent to ~wt since that's how it seems to work. But they are two different things (quosure VS formula). What is the relationship between them, and why does the above work?

  2. The advantage of plotly's formula API is that if I want to manipulate the input value, I can do things like ~wt/2. But in the above, doing plot_ly(data, x = x, y = x/2) produces an error. Is there a way to make this work?

I guess the general question is how to best combine the tidy eval approach with plotly's formula approach?


回答1:


From this answer by @alistaire:

The plotly R package was created a little before rlang, and has its own non-standard evaluation (NSE) system, that as far as I can tell is mostly only documented in the examples.

When NSE systems go sideways, the quickest way to get it to work is to rewrite all the code dynamically and then evaluate it. Here, wrap the whole plotly pipeline in quo with !! substitution wherever you like, then call quo_squash on it to collapse it to a single expression (instead of nested quosures), and then call eval_tidy on the whole lot to actually run it.

In plotly, ~ is used to refer to a column in the dataset to be visualized (@cpsievert).

In your example, x is a quosure thus you have to first unquote it before applying any base operator. That's what the error message told you:

Error: Base operators are not defined for quosures.
Do you need to unquote the quosure?

  # Bad:
  myquosure / rhs

  # Good:
  !!myquosure / rhs

Here is a working solution:

library(rlang)
library(plotly)

tidy_ply2 <- function(data, x) {
  x = enquo(x)
  print(x)
  
  data = filter(data, !!x > 5)
  
  # https://rlang.r-lib.org/reference/quasiquotation.html
  cat('\nUse qq_show() to debug the effect of unquoting operators\n')
  qq_show(plot_ly(data, x = ~!!x, y = ~!!x/2))
  
  # `base::eval` works too
  eval_tidy(
    quo_squash(
      quo({
        plot_ly(data, x = ~!!x, y = ~!!x/2)
      })
    )
  )
}

tidy_ply2(mtcars, wt)
#> <quosure>
#> expr: ^wt
#> env:  global
#> 
#> Use qq_show() to debug the effect of unquoting operators
#> plot_ly(data, x = ~^wt, y = ~(^wt) / 2)
#> 

Created on 2019-04-03 by the reprex package (v0.2.1.9000)



来源:https://stackoverflow.com/questions/55505599/combine-formula-and-tidy-eval-plotly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!