如何在tidyr和ggplot2的函数中使用dplyr' s enquo和quo_name

时间:2017-04-14 05:43:03

标签: r ggplot2 dplyr rlang tidyeval

library(dplyr) #Devel version, soon-to-be-released 0.6.0
library(tidyr)
library(ggplot2)
library(forcats) #for gss_cat data

我正在尝试编写一个功能,该功能将即将发布的dplyr devel版本的排序与tidyr::gatherggplot2结合起来。到目前为止它似乎与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))
}

但我无法弄清楚如何让这些情节发挥作用。我尝试将!!gathggplot2一起使用,但它没有用。

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))
}

4 个答案:

答案 0 :(得分:11)

为了完成这项工作,我必须使用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))
}

答案 1 :(得分:8)

我觉得主要问题是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现在相对陈旧并且设计略有不同的事实有关?使用aes进入debug,我们找到类似于

的结构
structure(list(x = mpg, y = eval(rlang::UQE(var))), .Names = c("x", 
"y"), class = "uneval")

(这不会通过解释器运行,但大致是结构的样子)。我认为这说明了为什么eval调用是必要的,o / w ggplot正在尝试将rlang::UQE(var)映射到y美学并报告它不知道如何处理某些内容班nameeval将名称评估为cyl,然后审美可以正常映射。

我想dplyr动词没有这个额外的映射步骤,其中参数以相同的方式被操纵到某个中间结构中,所以我们没有这个问题。

此外,当我说您不必使用rlang调用时,这是因为我假设此函数已重新导出到新的dplyr版本中。由于我前面提到的整个!!(...)!(!(...))事情,我更喜欢使用rlang::"!!"rlang::UQE(我认为这完全相同)。

这大部分都是猜测,如果有人能纠正我的任何错误,我将不胜感激。

答案 2 :(得分:2)

现在可以在ggplot2 v3.0.0aes内使用整洁的评估。因此不再需要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)

enter image description here

答案 3 :(得分:0)

我最近在其他地方回答了这个问题(Use dplyr SE with ggplot2)。不知道如何标记重复,所以我将在此重复。

  

如果您已经在处理quosures,则使用时语法更清晰   aes_而不是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))