🐤

ggplot2で画像を自動で書き出して自動で保存する

2023/11/02に公開

画像を自動で作成する方法については他のサイトに書かれていたが、自動で保存する方法は描かれていなかったため流れも合わせてメモしておく。

使用データの読み込み

今回はirisのデータを使用する。パッケージと合わせて読み込んでおく。

library(tidyverse) #tidyverseの読み込み
data(iris) #irisデータの読み込み
head(iris) #irisデータを見てみる
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

グラフの作成

適当にグラフを作成する。今回は箱ひげ図を使って、萼片(がくへん)長、萼片幅、花弁長、花弁幅をそれぞれ3種で比較する。まずは萼片長(Sepal.Length)。

ggplot(iris , aes(x = Species, y = Sepal.Length, group = Species))+
     geom_boxplot()+
     ggtitle(label = "萼片長")

グラフを自動で書き出す

ただ、いちいち変数を変えたりタイトルを変えるのは面倒くさいので、forループを使って画像を書き出す。

vars <- names(iris)[1:4] #データの1~4列の列名を変数として格納
#vars <- c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")でもよい
for(i in 1:length(vars)){
  title <- c("萼片長", "萼片幅", "花弁長", "花弁幅") #グラフの見出しに使う名前を格納しておく。長さはiの個数と合わせておく。
  (ggplot(iris , aes_string(x = "Species", y = vars[i], group = "Species"))+
     geom_boxplot()+
     ggtitle(label = title[i]))%>%
    print()
}

for(i in 1:length(vars))では、変数varの長さ(つまり、1,2,3,4)を入れているので、iには1 2 3 4の数値がループしながら入っている。

ggplot()関数の中にあるaes_string()が、文字型を読み込める関数となっている。ループされる変数は文字型になってしまいaes()では読み込めないので、その対策として使用する。

ちなみに、それぞれのグラフを別々の変数に格納したいときは、空のリストを作ってその中に入れることも出来る。

boxs <- list() #空のリストを作成
vars <- names(iris)[1:4]
for(i in 1:length(vars)){
  title <- c("萼片長", "萼片幅", "花弁長", "花弁幅")
  #boxsの中にグラフをそれぞれ格納
  boxs[[i]] <- ggplot(iris , aes_string(x = "Species", y = vars[i], group = "Species"))+
     geom_boxplot()+
     ggtitle(label = title[i])
     #↓タイトルアレンジver
     #ggtitle(label = paste0("(",i,")",vars[i],"のグラフ")
}

元のデータの名前("Sepal.Length""Sepal.Width")をタイトルに使いたいときには、ggtitle(label = paste0(vars[i],"のグラフ")と表記すればいい。
そして、iの数値そのものをグラフ名に使いたい場合は(",,")を使用する。ふつう、""を使うと文字列として認識されるが、"(",i,")"だと、iに格納された変数がそのまま引き出されるらしい。

グラフを自動で保存する

しかし、グラフがいくつもあると保存するのも面倒くさい。自動化するためには先ほどのforループの中に「○○.png」という文字列を代入した変数をつくる。

#画像を保存したいファイルのパスを指定
setwd("画像を保存したいファイルのパス")

vars <- names(iris)[1:4]
for(i in 1:length(vars)){
  title <- c("萼片長", "萼片幅", "花弁長", "花弁幅")
  png <- paste(title[i], ".png", sep = "") #「○○.png」を作成
  (ggplot(iris , aes_string(x = "Species", y = vars[i], group = "Species"))+
     geom_boxplot()+
     ggtitle(label = title[i]))%>%
    print()
  ggsave(png, unit = "cm", height = 10, width = 10, dpi = 150) #グラフの保存
}

titleという変数に入れておいた値をpaste()でPNGの拡張子.pngとくっつけたあと、pngという変数に入れておく。

グラフの保存にはggtitle()を使う。この場合、iの値がループするごとに萼片長.png萼片幅.png花弁長.png花弁幅.pngを呼び出して保存する。保存場所については、あらかじめsetwd()で画像の保存ファイルを指定しておく。

アレンジ

setwd("画像を保存したいファイルのパス")
#種別にグラフを書き出す
Spe <- unique(iris$Species) #Species列の重複しない要素をとりだす
for(i in 1:length(Spe)){
  png <- paste(Spe[i], ".png", sep = "")
  (ggplot(iris %>% filter(Species == Spe),  #特定の種の行のみ取りだす
          aes_string(x = "Sepal.Length", y = "Sepal.Width"))+
     geom_point()+ #プロット図
     ggtitle(label =  Spe))%>%
    print()
  ggsave(png, unit = "cm", height = 10, width = 10, dpi = 150)
}

unique()でSpecies列の重複しない要素をとりだし、filter()で特定の種の行のみを取り出しておくことで、種別のグラフを書き出すこともできる。

以上です。

参考文献

ggplot2で変数だけをloopで変えていきながら同じ設定の図をたくさん描く
・(書籍)Rグラフィックスクックブック 第2版 ―ggplot2によるグラフ作成のレシピ集
・(書籍)Rをはじめよう生命科学のためのRStudio入門

Discussion