入れ子のfor
ループでグラフを複数出力したものを、{gridExtra}
パッケージのgrid.arrange()
か何かで並べたい。解決策案の一つ、入れ子状態のlist形式のオブジェクトの入れ子状態を解消し実現する。
これを見て
すでに回答済みなので必要ないと思うが、自分のブログ記事が引用されているので別解を書いてみる(この質問のそのものを最近見つけた、質問そのものはクローズ済)。
解決策1.「for
ループの段階で入れ子にならないようにする」はすでに回答済みなので、解決策案2.として書かれている「後からリストの入れ子を解消する」という方法について書いていく。こちらは、{purrr}
パッケージのlist_flatten()
関数を用いると実現できる。
具体的に実行していく。まずはQittaの記事の例にならってplotlist
にグラフを格納していく。
記事中に明示されていないが、{tidyvrese}
パッケージを読んでいることが前提になっているようなので冒頭に呼び出しておく。
# Qittaの記事の通り library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.4.4 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
production.area <- rep(c("a", "b", "c"), times = 50 ) iris <- cbind(iris, production.area) plotlist <- NULL for(i in unique(iris$Species)){ for(j in unique(iris$production.area)){ (plotlist[[i]][[j]] <- iris %>% filter(Species == i) %>% filter(production.area == j) %>% ggplot(aes(x = Sepal.Length, y = Sepal.Width))+ geom_point()+ labs(title=paste0(i, "*", j)) ) } }
これで、plotlist
ができる。plotlist
は入れ子状態のlist形式になっているので{gridExtra}
パッケージのgrid.arrange()
を使ってまとめてグラフを表示しようとすると、{ggplot2}
で作成した図をリスト形式で受け取るgrobs
引数にplotlist
を渡してもリストが深いのでうまく受け取ってくれない。
library(gridExtra)
##
## 次のパッケージを付け加えます: 'gridExtra'
## 以下のオブジェクトは 'package:dplyr' からマスクされています:
##
## combine
grid.arrange(grobs = plotlist)
## Error in gList(...): "gList" 中には 'grobs' のみが許されます
どうしたらいいかというと、単純にlistを浅くすればいいので、list_flatten()
関数でplotlist
の入れ子状態を解消するといい。{purrr}
パッケージのlist_flatten()
関数を使うと一つリストが浅くなってくれる。
# {purrr}は{tidyverse}を読み込んだ時に読み込み済み grid.arrange(grobs = list_flatten(plotlist))