如何在带有 tidyr 和 ggplot2 的函数中使用 dplyr 的 enquo 和 quo_name
How to use dplyr's enquo and quo_name in a function with tidyr and ggplot2
library(dplyr) #Devel version, soon-to-be-released 0.6.0
library(tidyr)
library(ggplot2)
library(forcats) #for gss_cat data
我正在尝试编写一个函数,将即将发布的 dplyr
开发版本的 quosures 与 tidyr::gather
和 ggplot2
结合起来。到目前为止,它似乎适用于 tidyr
,但我在绘图时遇到了问题。
以下函数似乎适用于 tidyr's gather
:
GatherFun<-function(gath){
gath<-enquo(gath)
gss_cat%>%select(relig,marital,race,partyid)%>%
gather(key,value,-!!gath)%>%
count(!!gath,key,value)%>%
mutate(perc=n/sum(n))
}
但我不知道如何让情节发挥作用。我尝试将 !!gath
与 ggplot2
一起使用,但没有用。
GatherFun<-function(gath){
gath<-enquo(gath)
gss_cat%>%select(relig,marital,race,partyid)%>%
gather(key,value,-!!gath)%>%
count(!!gath,key,value)%>%
mutate(perc=n/sum(n))%>%
ggplot(aes(x=value,y=perc,fill=!!gath))+
geom_col()+
facet_wrap(~key, scales = "free") +
geom_text(aes(x = "value", y = "perc",
label = "perc", group = !!gath),
position = position_stack(vjust = .05))
}
为了完成这项工作,我不得不使用 dplyr::quo_name
将 quosure 更改为字符串。我还必须使用 ggplot2::aes_string
,这也要求所有输入都是字符串,因此用 ""
引用。
GatherFun <- function(gath){
gath <- enquo(gath)
gathN <- quo_name(gath)
gss_cat %>%
select(relig, marital, race, partyid) %>%
gather(key, value, -!!gath) %>%
count(!!gath, key, value) %>%
mutate(perc = round(n/sum(n), 2)) %>%
ggplot() +
geom_col(aes_string(x = "value", y = "perc", fill = gathN)) +
facet_wrap(~key, scales = "free") +
geom_text(aes_string(x = "value", y = "perc", label = "perc", group = gathN),
position = position_stack(vjust = .05))
}
我觉得主要的问题是 ggplot
在尝试计算 !!gath
和 !(!gath)
时贪婪,因为 not(gath)
没有意义而抛出错误。当我尝试使用 !!
时,这个问题经常出现,所以我有点厌倦了以糖形式使用它。
如果更精确的人能够正确识别问题,那肯定会有所帮助。
gather_func = function(gath) {
gath = enquo(gath)
gss_cat %>%
select(relig, marital, race, partyid) %>%
gather(key, value, -!!gath) %>%
count(!!gath, key, value) %>%
mutate(perc = round(n/sum(n), 2)) %>%
ggplot(aes(x = value, y = perc, fill = eval(rlang::`!!`(gath)))) +
geom_col() +
facet_wrap(~key, scales = "free") +
geom_text(
aes(
x = value,
y = perc,
label = perc,
group = eval(rlang::`!!`(gath))
),
position = position_stack(vjust = .05)
)
}
你在问题中写的函数调用似乎有一些错误。适当地间隔您的代码将有助于避免这种情况。
您也没有使用 rlang
调用,我只是没有安装最新的 dplyr
版本。
编辑 使用更简单的 mtcars
示例的一些想法:
Tbh 我不太确定这里发生了什么,但我想这与 ggplot2
现在相对较旧并且设计略有不同的事实有关?用debug
步入aes
,我们发现类似于
的结构
structure(list(x = mpg, y = eval(rlang::UQE(var))), .Names = c("x",
"y"), class = "uneval")
(这不会 运行 通过解释器,但大致是结构的样子)。我认为这说明了为什么 eval
调用在这里是必要的,o/w ggplot 试图将 rlang::UQE(var)
映射到 y
美学并报告它不知道如何处理class name
的东西。 eval
将名称评估为 cyl
,然后可以正常映射审美。
我想 dplyr
动词没有这个额外的映射步骤,其中参数以相同的方式被操纵到一些中间结构中,所以我们没有这个问题。
此外,当我说您不必使用 rlang
调用时,那是因为我假设此函数已重新导出到新的 dplyr
版本中。由于我之前提到的整个 !!(...)
或 !(!(...))
,我更喜欢使用 rlang::"!!"
或 rlang::UQE
(我相信它们完全等同)。
不过大部分都是猜测,如果有人可以纠正我的任何错误,我们将不胜感激。
我最近在别处回答了这个问题 (Use dplyr SE with ggplot2)。不确定如何标记重复项,所以我会在这里重复。
If you are already handling quosures the syntax is cleaner if you use
aes_
rather than aes_string
.
这段代码应该适用于您的示例。请注意,所有硬编码变量(value、perc、key)都用 tilda 引用,而直接使用 quosure(gath)。
ggplot(aes_(x = ~value, y = ~perc, fill = gath) +
geom_col() +
facet_wrap(~key, scales = "free") +
geom_text(aes_(x = ~value, y = ~perc, label = ~perc, group = gath),
position = position_stack(vjust = .05))
现在可以在 ggplot2 v3.0.0
中的 aes
中使用 tidy 求值。因此不再需要aes_string
。
# install.packages("ggplot2", dependencies = TRUE)
library(tidyverse)
GatherFun2 <- function(gath) {
gath <- enquo(gath)
gss_cat %>%
select(relig, marital, race, partyid) %>%
gather(key, value, -!! gath) %>%
count(!!gath, key, value) %>%
mutate(perc = round(n/sum(n), 2)) %>%
ggplot() +
geom_col(aes(x = value, y = perc, fill = !! gath)) +
facet_wrap(~ key, scales = "free") +
xlab(NULL) +
geom_text(aes(x = value, y = perc,
label = ifelse(perc == 0, "", perc),
group = !! gath),
position = position_stack(vjust = .2)) +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 90, hjust = 1.0))
}
GatherFun2(marital)
library(dplyr) #Devel version, soon-to-be-released 0.6.0
library(tidyr)
library(ggplot2)
library(forcats) #for gss_cat data
我正在尝试编写一个函数,将即将发布的 dplyr
开发版本的 quosures 与 tidyr::gather
和 ggplot2
结合起来。到目前为止,它似乎适用于 tidyr
,但我在绘图时遇到了问题。
以下函数似乎适用于 tidyr's gather
:
GatherFun<-function(gath){
gath<-enquo(gath)
gss_cat%>%select(relig,marital,race,partyid)%>%
gather(key,value,-!!gath)%>%
count(!!gath,key,value)%>%
mutate(perc=n/sum(n))
}
但我不知道如何让情节发挥作用。我尝试将 !!gath
与 ggplot2
一起使用,但没有用。
GatherFun<-function(gath){
gath<-enquo(gath)
gss_cat%>%select(relig,marital,race,partyid)%>%
gather(key,value,-!!gath)%>%
count(!!gath,key,value)%>%
mutate(perc=n/sum(n))%>%
ggplot(aes(x=value,y=perc,fill=!!gath))+
geom_col()+
facet_wrap(~key, scales = "free") +
geom_text(aes(x = "value", y = "perc",
label = "perc", group = !!gath),
position = position_stack(vjust = .05))
}
为了完成这项工作,我不得不使用 dplyr::quo_name
将 quosure 更改为字符串。我还必须使用 ggplot2::aes_string
,这也要求所有输入都是字符串,因此用 ""
引用。
GatherFun <- function(gath){
gath <- enquo(gath)
gathN <- quo_name(gath)
gss_cat %>%
select(relig, marital, race, partyid) %>%
gather(key, value, -!!gath) %>%
count(!!gath, key, value) %>%
mutate(perc = round(n/sum(n), 2)) %>%
ggplot() +
geom_col(aes_string(x = "value", y = "perc", fill = gathN)) +
facet_wrap(~key, scales = "free") +
geom_text(aes_string(x = "value", y = "perc", label = "perc", group = gathN),
position = position_stack(vjust = .05))
}
我觉得主要的问题是 ggplot
在尝试计算 !!gath
和 !(!gath)
时贪婪,因为 not(gath)
没有意义而抛出错误。当我尝试使用 !!
时,这个问题经常出现,所以我有点厌倦了以糖形式使用它。
如果更精确的人能够正确识别问题,那肯定会有所帮助。
gather_func = function(gath) {
gath = enquo(gath)
gss_cat %>%
select(relig, marital, race, partyid) %>%
gather(key, value, -!!gath) %>%
count(!!gath, key, value) %>%
mutate(perc = round(n/sum(n), 2)) %>%
ggplot(aes(x = value, y = perc, fill = eval(rlang::`!!`(gath)))) +
geom_col() +
facet_wrap(~key, scales = "free") +
geom_text(
aes(
x = value,
y = perc,
label = perc,
group = eval(rlang::`!!`(gath))
),
position = position_stack(vjust = .05)
)
}
你在问题中写的函数调用似乎有一些错误。适当地间隔您的代码将有助于避免这种情况。
您也没有使用 rlang
调用,我只是没有安装最新的 dplyr
版本。
编辑 使用更简单的 mtcars
示例的一些想法:
Tbh 我不太确定这里发生了什么,但我想这与 ggplot2
现在相对较旧并且设计略有不同的事实有关?用debug
步入aes
,我们发现类似于
structure(list(x = mpg, y = eval(rlang::UQE(var))), .Names = c("x",
"y"), class = "uneval")
(这不会 运行 通过解释器,但大致是结构的样子)。我认为这说明了为什么 eval
调用在这里是必要的,o/w ggplot 试图将 rlang::UQE(var)
映射到 y
美学并报告它不知道如何处理class name
的东西。 eval
将名称评估为 cyl
,然后可以正常映射审美。
我想 dplyr
动词没有这个额外的映射步骤,其中参数以相同的方式被操纵到一些中间结构中,所以我们没有这个问题。
此外,当我说您不必使用 rlang
调用时,那是因为我假设此函数已重新导出到新的 dplyr
版本中。由于我之前提到的整个 !!(...)
或 !(!(...))
,我更喜欢使用 rlang::"!!"
或 rlang::UQE
(我相信它们完全等同)。
不过大部分都是猜测,如果有人可以纠正我的任何错误,我们将不胜感激。
我最近在别处回答了这个问题 (Use dplyr SE with ggplot2)。不确定如何标记重复项,所以我会在这里重复。
If you are already handling quosures the syntax is cleaner if you use
aes_
rather thanaes_string
.
这段代码应该适用于您的示例。请注意,所有硬编码变量(value、perc、key)都用 tilda 引用,而直接使用 quosure(gath)。
ggplot(aes_(x = ~value, y = ~perc, fill = gath) +
geom_col() +
facet_wrap(~key, scales = "free") +
geom_text(aes_(x = ~value, y = ~perc, label = ~perc, group = gath),
position = position_stack(vjust = .05))
现在可以在 ggplot2 v3.0.0
中的 aes
中使用 tidy 求值。因此不再需要aes_string
。
# install.packages("ggplot2", dependencies = TRUE)
library(tidyverse)
GatherFun2 <- function(gath) {
gath <- enquo(gath)
gss_cat %>%
select(relig, marital, race, partyid) %>%
gather(key, value, -!! gath) %>%
count(!!gath, key, value) %>%
mutate(perc = round(n/sum(n), 2)) %>%
ggplot() +
geom_col(aes(x = value, y = perc, fill = !! gath)) +
facet_wrap(~ key, scales = "free") +
xlab(NULL) +
geom_text(aes(x = value, y = perc,
label = ifelse(perc == 0, "", perc),
group = !! gath),
position = position_stack(vjust = .2)) +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 90, hjust = 1.0))
}
GatherFun2(marital)