结合公式和整洁的评估(情节)
combine formula and tidy eval (plotly)
我很难理解这一点。
下面让我以 "tidy" 的方式过滤我的 data.frame,并使用 plotly 绘制绘图。在这种情况下,我使用 plotly 的基于公式的 API 来说明要使用数据框的哪些列:
library(plotly)
tidy_filter = function(data, x) {
x = enquo(x)
filter(data, !!x > 5)
}
mtcars %>%
tidy_filter(wt) %>%
plot_ly(x = ~wt, y = ~wt)
我可以将它包装在一个函数中以获得相同的结果:
tidy_ply = function(data, x) {
x = enquo(x)
data = filter(data, !!x > 5)
plot_ly(data, x = x, y = x)
}
tidy_ply(mtcars, wt)
现在:
我假设 enquo(x)
在这种情况下至少部分等同于 ~wt
因为它似乎是这样工作的。但它们是两个不同的东西(quosure VS formula)。它们之间有什么关系,为什么上面的方法有效?
plotly的公式API的优点是,如果我想操作输入值,我可以做~wt/2
这样的事情。但是在上面,做 plot_ly(data, x = x, y = x/2)
会产生错误。有什么办法可以做到吗?
我想一般的问题是如何最好地将 tidy eval 方法与 plotly 的公式方法结合起来?
来自@alistaire 的answer:
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).
在您的示例中,x
是一个 quosure,因此您必须先取消引用它,然后再应用任何基本运算符。这就是错误消息告诉您的内容:
Error: Base operators are not defined for quosures.
Do you need to unquote the quosure?
# Bad:
myquosure / rhs
# Good:
!!myquosure / rhs
这是一个可行的解决方案:
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)
#>
由 reprex package (v0.2.1.9000)
创建于 2019-04-03
我很难理解这一点。
下面让我以 "tidy" 的方式过滤我的 data.frame,并使用 plotly 绘制绘图。在这种情况下,我使用 plotly 的基于公式的 API 来说明要使用数据框的哪些列:
library(plotly)
tidy_filter = function(data, x) {
x = enquo(x)
filter(data, !!x > 5)
}
mtcars %>%
tidy_filter(wt) %>%
plot_ly(x = ~wt, y = ~wt)
我可以将它包装在一个函数中以获得相同的结果:
tidy_ply = function(data, x) {
x = enquo(x)
data = filter(data, !!x > 5)
plot_ly(data, x = x, y = x)
}
tidy_ply(mtcars, wt)
现在:
我假设
enquo(x)
在这种情况下至少部分等同于~wt
因为它似乎是这样工作的。但它们是两个不同的东西(quosure VS formula)。它们之间有什么关系,为什么上面的方法有效?plotly的公式API的优点是,如果我想操作输入值,我可以做
~wt/2
这样的事情。但是在上面,做plot_ly(data, x = x, y = x/2)
会产生错误。有什么办法可以做到吗?
我想一般的问题是如何最好地将 tidy eval 方法与 plotly 的公式方法结合起来?
来自@alistaire 的answer:
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 inquo
with!!
substitution wherever you like, then callquo_squash
on it to collapse it to a single expression (instead of nested quosures), and then calleval_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).
在您的示例中,x
是一个 quosure,因此您必须先取消引用它,然后再应用任何基本运算符。这就是错误消息告诉您的内容:
Error: Base operators are not defined for quosures.
Do you need to unquote the quosure?
# Bad:
myquosure / rhs
# Good:
!!myquosure / rhs
这是一个可行的解决方案:
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)
#>
由 reprex package (v0.2.1.9000)
创建于 2019-04-03