LoginSignup
1
1

Rのggplotで列名を変数として引数に与えたい

Last updated at Posted at 2022-11-14

用途

ggplotなどtidyverse系列で列名に対して
繰り返し処理や関数を作成したいことがある。

一筋縄でいけないことが多いので、ここに攻略法をまとめた。

そもそも、mapやfacet、acrossでうまくいくことが多いので、それらでは本当にだめか確認する。

Code

  • R / 4.1.0
  • Install packages
    • tidyverse

テストCode

irisについて、各指標で箱ひげ図を得たいとする
一つならこう書ける

iris %>%
    ggplot(aes(x = Species, y = Sepal.Length)) +
    geom_boxplot()
image.png (6.7 kB)

ミス Code

あるあるケース

sp_boxplot <- function(var) {
    iris %>%
        ggplot(aes(x = Species, y = var)) +
        geom_boxplot()
}

sp_boxplot("Sepal.Length")
image.png (5.5 kB)

クリアCode

いくつか列挙する出力の図はどれも同じ

aesのパワープレイ

aesは ... を介すると受け取った引数をいい感じに処理するのでうまくいく

sp_boxplot <- function(...) {
    iris %>% 
        ggplot(aes(x=Species,...)) +
        geom_boxplot()
}

sp_boxplot(y=Sepal.Length)

aes_string

引数を文字列で与える
""との組合せのみうまくいく

sp_boxplot <- function(var) {
    iris %>%
        ggplot(aes_string(x = "Species", y = var)) +
        geom_boxplot()
}

sp_boxplot("Sepal.Length")

aes_

引数を列名として宣言する
quote と as.name の適用のみうまくいく

sp_boxplot <- function(var) {
    iris %>%
        ggplot(aes_(x = quote(Species), y = as.name(var))) +
        geom_boxplot()
}

sp_boxplot("Sepal.Length")

!!のアンクォートとquo

クォージャーとして与えて、関数内部で!!によってアンクォート
使うときに、quoで包む必要があるがうまくいく

sp_boxplot <- function(var) {
    iris %>%
        ggplot(aes(x = Species, y = !!var)) +
        geom_boxplot()
}

sp_boxplot(quo(Sepal.Length))

enquo

上のquo処理を関数内部に移管したイメージ
使うときに裸の変数名となるがうまくいく

sp_boxplot <- function(var) {
    var <- enquo(var)
    iris %>%
        ggplot(aes(x = Species, y = !!var)) +
        geom_boxplot()
}

sp_boxplot(Sepal.Length)

{{ }} curly-curly

enquoの後継としてでてきたらしい
使うときに裸の変数名となるがうまくいく

sp_boxplot <- function(var) {
    iris %>%
        ggplot(aes(x = Species, y = {{ var }})) +
        geom_boxplot()
}

sp_boxplot(Sepal.Length)

データ要素として指定

.data(ここではパイプで渡されたiris)の要素ということを明示的にかく

sp_boxplot <- function(var) {
    iris %>%
        ggplot(aes(x = Species, y =.data[[ var ]])) +
        geom_boxplot()
}


sp_boxplot("Sepal.Length")

結論

公文書に従うなら、
aes(){{ でやっていくのが妥当だが、
普段使いには、文字列を渡すことが多いので、文字指定できるものが便利

あとがき

基本的に問題は2つ

  • 引数を変数名か、定数(文字列)のどちらで処理するか
  • 変数名として、グローバルなのかデータ内の列名なのか
    でうまく回らないことが多い。
    そもそも、tidyverseの世界で、列名なら裸(クォーテーション無)で指定できているのが便利でありながらも、問題を生む温床である。
    気になる人は、「非標準評価(NSE)」や「tidy eval」で検索検索!

また、今回はaesのなかで分けているが、group_byや別のところでも使うことは可能

今回の手法をまとめると

  • aes × enquo のグループ
    • aes × {{ は aes × enquo と等価
    • aes × … は aes × {{ と仕組みは同じだが、関数がどういうふうに使われるべきかによって選択する
  • aes_ (aes_q) × quote (ないし ~) のグループ
    • aes_string に比べると X$1 などの扱いが楽
    • ただし soft-deprecated
  • aes_string × 文字列のグループ
    • aes_ に比べると X$1 などの扱いがやや面倒
    • ただし soft-deprecated
      -ただし aes_string の代わりに aes(x = .data[[var]]) などとすれば文字列で変数を指定することが可能

参考文献

公文書1:aes_string と aes_
公文書2:enquo や {{
メモ:dplyr・ggplot2 で {{ }} を使う
読書日記-2017年8月19日 (土)

スペシャルサンクス

本質問は、Rのslackコミュニティ「r-wakalang」にて議論させていただきました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1