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))
}
主な問題は、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
バージョンがインストールされていないだけです。
[〜#〜] edit [〜#〜]より単純なmtcars
の例を使用したいくつかの考え:
Tbhここで何が起こっているのかよくわかりませんが、_ggplot2
_が比較的古く、デザインが少し異なるという事実に関係していると思いますか? aes
を使用してdebug
にステップインすると、次のような構造が見つかります。
_structure(list(x = mpg, y = eval(rlang::UQE(var))), .Names = c("x",
"y"), class = "uneval")
_
(これはインタープリターを通過しませんが、おおよそ構造はどのように見えるかです)。これは、ここでeval
呼び出しが必要な理由を示していると思います。o/ wggplotはrlang::UQE(var)
をy
美学にマッピングしようとしており、何をすべきかわからないと報告しています。クラスname
の何かで行います。 eval
は名前をたとえばcyl
に評価し、美学を通常どおりにマッピングできます。
dplyr
動詞には、引数が同じ方法で中間構造に操作されるこの追加のマッピングステップがないので、この問題は発生しないと思います。
また、rlang
呼び出しを使用する必要がないと言ったとき、これは、この関数が新しいdplyr
バージョンに再エクスポートされたと想定したためです。先に述べた!!(...)
または!(!(...))
全体のため、私は_rlang::"!!"
_または_rlang::UQE
_(私が信じているのとまったく同じ)を使用することを好みます。
しかし、これのほとんどは推測であり、誰かが私が間違っていることについて私を訂正することができれば、それはありがたいです。
この作業を行うには、dplyr::quo_name
を使用して定足数を文字列に変更する必要がありました。また、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))
}
ggplot2 v3.0.0
のaes
内で整然とした評価を使用できるようになりました。したがって、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)
私は最近他の場所でこの質問に答えました( ggplot2でdplyr SEを使用 )。重複をマークする方法がわからないので、ここで繰り返します。
すでにクォージャーを処理している場合、
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))