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

我正在尝试编写一个函数,它将即将发布的dplyr开发版本中的 quosures 与tidyr::gatherand结合起来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))
}

但我不知道如何使情节发挥作用。我尝试使用!!gathwith 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))
}
4

4 回答 4

13

为了完成这项工作,我不得不使用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))
}
于 2017-04-25T03:25:48.627 回答
10

我觉得主要问题是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现在相对较旧并且设计略有不同的事实有关?进入aeswith debug,我们发现一个类似的结构

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

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

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

另外,当我说您不必使用该rlang调用时,那是因为我假设此功能已重新导出到新dplyr版本中。由于我之前提到的整体!!(...)或事物,我更喜欢使用, or (我相信它们完全等效)。!(!(...))rlang::"!!"rlang::UQE

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

于 2017-04-30T16:46:43.453 回答
3

现在可以aesggplot2 v3.0.0. 因此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)

在此处输入图像描述

于 2018-05-28T08:12:40.173 回答
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))
于 2017-11-01T20:22:58.183 回答