備忘ログ

チラシの裏的備忘録&メモ

グラフが格納された、リストの入れ子を解消したい

入れ子forループでグラフを複数出力したものを、{gridExtra}パッケージのgrid.arrange()か何かで並べたい。解決策案の一つ、入れ子状態のlist形式のオブジェクトの入れ子状態を解消し実現する。

これを見て

qiita.com

すでに回答済みなので必要ないと思うが、自分のブログ記事が引用されているので別解を書いてみる(この質問のそのものを最近見つけた、質問そのものはクローズ済)。

解決策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))