Как использовать enquo и quo_name в dplyr в функции с tidyr и ggplot2

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

Я пытаюсь написать функцию, которая сочетает в себе цитаты из скоро, чтобы быть выпущенным dplyr версия devel вместе с 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))
}

4 ответа

Решение

Я чувствую, что главная проблема 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 пример:

Я совершенно не уверен, что здесь происходит, но я думаю, что это связано с тем, что 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 эстетический и сообщает, что не знает, что делать с чем-то классным name, eval оценивает имя, скажем, cyl, тогда эстетика может быть сопоставлена ​​как обычно.

я представляю себе dplyr У глаголов нет этого дополнительного шага отображения, когда аргументы обрабатываются в некоторой промежуточной структуре таким же образом, поэтому у нас нет этой проблемы.

Кроме того, когда я сказал, что вам не нужно использовать rlang вызов, потому что я предполагал, что эта функция была реэкспортирована в новый dplyr версия. Из-за всего !!(...) или же !(!(...)) То, что я упоминал ранее, я предпочитаю использовать rlang::"!!", или же rlang::UQE (которые точно эквивалентны, я верю).

Большая часть этого - предположение, и если кто-то может исправить меня в чем-то, что я ошибаюсь, это будет оценено.

Для того, чтобы сделать эту работу, мне пришлось использовать 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))
}

Теперь можно использовать аккуратную оценку внутри aes в ggplot2 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)

Я недавно ответил на этот вопрос в другом месте ( используйте dplyr SE с ggplot2). Не уверен, как пометить дубликаты, поэтому я повторю здесь.

Если вы уже обрабатываете предложения, синтаксис будет более чистым, если вы используете aes_ скорее, чем aes_string,

Этот бит кода должен работать в вашем примере. Обратите внимание, что все жестко закодированные переменные (value, perc, key) заключаются в кавычки тильдой, в то время как 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))
Другие вопросы по тегам