Как использовать 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))