问题
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:
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?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, doingplot_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 beforerlang
, 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