web-dev-qa-db-ja.com

tidyrとggplot2を使用する関数でdplyrのenquoとquo_nameを使用する方法

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

間もなくリリースされるdplyrdevelバージョンのクォージャーと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))
}

しかし、プロットを機能させる方法がわかりません。 !!gathggplot2と一緒に使用しようとしましたが、機能しませんでした。

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))
}
14
Mike

主な問題は、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_(私が信じているのとまったく同じ)を使用することを好みます。

しかし、これのほとんどは推測であり、誰かが私が間違っていることについて私を訂正することができれば、それはありがたいです。

8
Akhil Nair

この作業を行うには、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))
}
12
Mike

ggplot2 v3.0.0aes内で整然とした評価を使用できるようになりました。したがって、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)

enter image description here

2
Tung

私は最近他の場所でこの質問に答えました( 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))
0
Stanwood