library(dplyr) #Devel version, soon-to-be-released 0.6.0
library(tidyr)
library(ggplot2)
library(forcats) #for gss_cat data
J'essaie d'écrire une fonction qui combine les quosures de la version de développement dplyr
à paraître prochainement avec tidyr::gather
et ggplot2
. Jusqu’à présent, cela semble fonctionner avec tidyr
, mais j’ai de la difficulté avec le complot.
La fonction ci-dessous semble fonctionner avec 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))
}
Mais je n'arrive pas à comprendre comment faire fonctionner les parcelles. J'ai essayé d'utiliser !!gath
avec ggplot2
, mais cela n'a pas fonctionné.
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))
}
Je pense que le problème principal est ggplot
est gourmand quand il essaie d'évaluer !!gath
et fait !(!gath)
, émettant une erreur car not(gath)
n'a pas de sens. J'ai souvent rencontré ce problème lorsque j'ai essayé d'utiliser !!
, donc je suis un peu fatigué de l'utiliser sous sa forme sucrée.
Si quelqu'un de plus précis pouvait identifier correctement le problème, ce serait certainement utile.
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)
)
}
Il semble y avoir quelques erreurs dans l'appel de fonction que vous avez écrit dans la question. en espaçant correctement votre code, vous éviterez cela.
De plus, vous n'avez pas utilisé l'appel rlang
, la version la plus récente dplyr
n'est pas installée.
EDITQuelques réflexions utilisant un exemple mtcars
plus simple:
Tbh Je ne suis pas sûr de ce qui se passe ici, mais j'imagine que cela a à voir avec le fait que le ggplot2
est relativement vieux maintenant et a un design légèrement différent? En entrant dans aes
avec debug
, nous trouvons une structure similaire à
structure(list(x = mpg, y = eval(rlang::UQE(var))), .Names = c("x",
"y"), class = "uneval")
(Cela ne passera pas par l’interprète, mais correspond plus ou moins à la structure). Je pense que cela montre pourquoi l'appel eval
est nécessaire ici, o/w ggplot tente de mapper rlang::UQE(var)
avec l'esthétique y
et indique qu'il ne sait pas quoi faire avec quelque chose de classe name
. eval
évalue le nom à, par exemple, cyl
, alors l'esthétique peut être mappée comme d'habitude.
J'imagine que les verbes dplyr
n'ont pas cette étape de mappage supplémentaire dans laquelle les arguments sont manipulés de la même manière dans une structure intermédiaire, de sorte que nous n'avons pas ce problème.
De plus, lorsque j'ai dit que vous ne deviez pas utiliser l'appel rlang
, c'était parce que je supposais que cette fonction avait été réexportée dans la nouvelle version dplyr
. En raison de la totalité de !!(...)
ou !(!(...))
que j'ai mentionné plus tôt, je préfère utiliser rlang::"!!"
ou rlang::UQE
(qui sont exactement équivalents, je crois).
La plupart de ceci est cependant de la spéculation et si quelqu'un pouvait me corriger sur quelque chose que je me suis trompé, ce serait apprécié.
Pour que cela fonctionne, je devais utiliser dplyr::quo_name
pour changer le contenu en chaîne. J'ai également dû utiliser ggplot2::aes_string
, qui requiert également que toutes les entrées soient des chaînes, et donc cité avec ""
.
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))
}
Il est maintenant possible d'utiliser l'évaluation nettoie dans aes
dans ggplot2 v3.0.0
. Ainsi, aes_string
n'est plus nécessaire.
# 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)
J'ai récemment répondu à cette question ailleurs récemment ( Utilisez dplyr SE avec ggplot2 ). Vous ne savez pas comment marquer les doublons, je vais donc répéter ici.
Si vous gérez déjà des quosures, la syntaxe est plus propre si vous utilisez
aes_
plutôt queaes_string
.
Ce morceau de code devrait fonctionner dans votre exemple. Notez que toutes les variables codées en dur (valeur, perc, clé) sont citées avec un tilda alors que le quosure (gath) est utilisé directement.
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))