見出し画像

Rを使いデータフレームからグラフを連続で画像出力

表から列ごとに順々にグラフ

消費者物価指数」の「光熱・水道代」の推移グラフを描きます。
「光熱・水道代」は6品目に分け、各グラフを画像として連続出力します。
この一連の処理に「R言語」を使いました。

最新の詳細結果表(月報掲載表へ) → 中分類指数(全国)からデータを取得します。
下記が6品目(電気代、都市ガス代、プロパンガス、灯油、水道料、下水道料)のグラフです。
2020年の物価を100とした「指数」の推移です。
総務総統計局が公表している数値データを、「R」を使い加工しています。
データは「e-Stat」から取得しました。

電気代(指数)の推移
都市ガス代(指数)の推移
プロパンガス(指数)の推移
灯油(指数)の推移
水道料(指数)の推移
下水道料(指数)の推移

時間軸をx軸とし、y軸に「電気代」「都市ガス代」・・・と順々に、列を変えながら6種類のライングラフ(折れ線グラフ)を描いています。

「e-Stat」から取得した消費者物価指数。2022年(令和4年)12月分(2023年1月20日公表)までのデータ

R言語で

「R」は、普段使わないので、Googleで調べながら試し試し行いました。
Macを使用しています。

library

使用するパッケージをアクティブにします。

library(tidyverse)
library(readxl)
library(lubridate) 

getwd, list.files

ファイルのパスを確認します。

# ファイルのパスを確認
getwd()
[1] "/Users/username/Desktop/app/画像生成R"
path <- '/Users/username/Desktop/app/画像生成R/'

# ファイルパスを変数に格納
path_list <- list.files(path, full.names = T)
path_list
[1] "/Users/username/Desktop/app/画像生成R//消費者物価指数_230203005831.csv" 
[2] "/Users/username/Desktop/app/画像生成R//消費者物価指数_230203010208.xlsx"
[3] "/Users/username/Desktop/app/画像生成R//画像生成R_整理版.R"              
[4] "/Users/username/Desktop/app/画像生成R//画像生成R.Rproj"   

# 特定のパスのみ取り出せることを確認。[3]で3番目
path_list[3]
[1] "/Users/username/Desktop/app/画像生成R//消費者物価指数_noheader_230203021248.csv"

read_csv, type_convert

csvを読み込みます。
cols(.default = "c")で一旦文字列型として読み込みます。
type_convert()で読み込まれたデータフレームの各列のデータ型を自動的に変換します。
一旦文字列型として読み込むのは、データフレームにデータ型が混在しており、自動的な推定が望ましくない場合や、特定の列を数値型として読み込むとエラーが発生する可能性がある場合に便利な方法です。

# csv読み込み。col_types = colsで全部文字列型で。skipで1行飛ばす
# type_convert()で型変換実行
df_data01 <- read_csv(
  path_list[3], skip = 1, col_types = cols(.default = "c"),
  col_names = TRUE
  ) %>% 
  type_convert()

#確認
df_data01
# A tibble: 36 × 9
`地域(2020年基準)` 時間軸(…¹ /2020…² 3500 …³ 3600 …⁴ 3612 …⁵ 3701 …⁶ 3810 …⁷ 4610 …⁸
<chr>                <chr>      <lgl>     <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
  1 全国                 202212月 NA         130.    140     113.    136.   100.    100. 
2 全国                 202211月 NA         127     133.    113.    137    100.    100. 
3 全国                 202210月 NA         126     129.    112.    138.    99.9    98.7

colnames(df_data01)
[1] "地域(2020年基準)" "時間軸(年・月)"   "2020年基準品目"    "3500 電気代"       
[5] "3600 都市ガス代"    "3612 プロパンガス"  "3701 灯油"          "3810 水道料"       
[9] "4610 下水道料" 

# 列名変更
colnames(df_data01) <- c("地域", "時間軸", "2020年基準品目" , "電気代", "都市ガス代" , "プロパンガス", "灯油", "水道料", "下水道料" )


グラフを確認

「ggplot」でグラフ作成の手順を確認しました。
以下では「電気代」の指数を使っています。

ggplot, geom_line

### 棒グラフ
# x, y軸両方に値を指定するには, geom_bar()の引数として, stat="identity"を指定
# element_text で目盛回転。ただしtheme_grayを後ろにすると上書きで横のまま
df_data01 %>% 
  ggplot(aes(x = 時間軸, y = 電気代, family = "HiraKakuPro-W3")) +
  geom_bar(stat="identity") +
  theme_gray (base_family = "HiraKakuPro-W3") +
  theme(axis.text.x = element_text(angle = 45, hjust=1))
「geom_bar」を使った棒グラフ

「geom_line」を使用した折れ線グラフでは、x軸の「時間軸」が文字列型なのでエラーが出ました。

### 折れ線グラフ
# 「HiraKakuPro-W3」でMacで起きる文字化けを防ぐ
df_data01 %>% 
  ggplot(aes(x = 時間軸, y = 電気代, family = "HiraKakuPro-W3")) +
  geom_line() +
  theme_gray (base_family = "HiraKakuPro-W3") +
  theme(axis.text.x = element_text(angle = 45, hjust=1))

# 以下 メッセージが出る
geom_path: Each group consists of only one observation. Do you need to adjust the group
aesthetic?

mutate, ym

時間軸列の型を「日付型」に変更します。

# 日付型に変更した値の列「時間軸2」を作成
df_data02 <- df_data01 %>% 
  mutate(時間軸2 = ym(時間軸))

# 「ym」についてメモ
# 折れ線グラフのx軸は文字列型では使えないので「lubriate」を使って型変換
# 実行例
mdy("1-19-2017")
[1] "2017-01-19"
ym("2022年12月")
[1] "2022-12-01"

目盛りを調整

上記の「時間軸2」をX軸目盛りの表記を「YY年MM月」に調整します。

geom_line

シンプルに「geom_line」(折れ線グラフ)を描くと、「YYYY」というフォーマットの目盛になりました。

df_data02 %>% 
  ggplot(aes(x = 時間軸2, y = 電気代, family = "HiraKakuPro-W3")) +
  geom_line() +
  theme_gray (base_family = "HiraKakuPro-W3") +
  theme(axis.text.x = element_text(angle = 45, hjust=1))
「geom_line」を使った折れ線グラフ(目盛調整前) scale_x_date

「scale_x_date」を使って目盛の表記を変更します。

# 「scale_x_date」で目盛の表記調整
# 「date_breaks = "1 months"」で一ヶ月ごと、「date_labels = "%y/年%m月"」で「YY年MM月」に
df_data02 %>% 
  ggplot(aes(x = 時間軸2, y = 電気代, family = "HiraKakuPro-W3")) +
  geom_line() +
  scale_x_date(date_breaks = "1 months",
               date_labels = "%y/年%m月") +
  theme_gray (base_family = "HiraKakuPro-W3") +
  theme(axis.text.x = element_text(angle = 45, hjust=1))
「geom_line」を使った折れ線グラフ(目盛調整後)

列調整

各品目のグラフを連続で生成する前に、列の並び順と列名を調整しました。

select

まず並び順を変更します。

# 列の数確認
ncol(df_data02)
[1] 10

# 「select」 を使い使う列だけ残す。かつ列の並び順を変更
# 「everything」で指定した列以外の越の並び順はそのままに
colnames(df_data02)
[1] "地域"           "時間軸"         "2020年基準品目" "電気代"         "都市ガス代"    
[6] "プロパンガス"   "灯油"           "水道料"         "下水道料"       "時間軸2"    

df_data03 <- df_data02[, -c(1, 3)] %>% 
  select(時間軸, 時間軸2, everything())

df_data03
# A tibble: 36 × 8
時間軸     時間軸2    電気代 都市ガス代 プロパンガス  灯油 水道料 下水道料
<chr>      <date>      <dbl>      <dbl>        <dbl> <dbl>  <dbl>    <dbl>
  1 2022122022-12-01   130.       140          113.  136.  100.     100. 
2 2022112022-11-01   127        133.         113.  137   100.     100. 

sapply, paste

### 数値列名の後ろに「(指数)」を付ける
df_data03_t <- df_data03 # 元に戻す時使う

# 列の数を変数に入れる
col_n <- ncol(df_data03)

# 「sapply」を使い各列に「指数」を付ける
names(df_data03)[(3:col_n)] <- 
  sapply(colnames(df_data03[, -(1:2)]), function(x){paste(x, "(指数)")}
)

# 確認
colnames(df_data03)
[1] "時間軸"                "時間軸2"               "電気代 (指数)"      
[4] "都市ガス代 (指数)"   "プロパンガス (指数)" "灯油 (指数)"        
[7] "水道料 (指数)"       "下水道料 (指数)"  

列を順々に(準備編)

順々に各列をY軸値とした折れ線グラフを描きます。
まずその準備として動作確認。
軸を設定する「aes」の中で変数を使っています。

aes, .data[[]]

### forループを使って列単位で順々にグラフを描く(準備編)
# Y軸を変数として「for」で回す。ただし以下について注意
# Y軸を変数として扱ってうまくいかなかったケース

# aesの中の「y_ch」を「"電気代"」として認識せず「y_ch」のまま表記。Y軸の値がない状態になる
y_ch <- "電気代(指数)"
ggplot(data = df_data03, 
       aes(x = 時間軸2, y = y_ch, family = "HiraKakuPro-W3")) +
  geom_line() 

# df_data03[, x]の中で変数を使おうとしたがエラーが出る
x = 3
ggplot(data = df_data03, 
       aes(x = 時間軸2, y = df_data03[, x], family = "HiraKakuPro-W3")) +
  geom_line() 
# 以下のエラーが表示される
Don't know how to automatically pick scale for object of type tbl_df/tbl/data.frame. Defaulting to continuous.
Error in is.finite(x) : default method not implemented for type 'list'

# そもそも「df_data03[, x]」は型が異なる(tibble形式のままな)ので適切ではない
df_data03$"電気代 (指数)" 
 [1] 130.1 127.0 126.0 124.7 122.9 120.8 
# A tibble: 36 × 1
   `電気代 (指数)`
               <dbl>
 1              130.
 2              127 
 3              126 

「aes」の中に変数を使う場合は「[[]]」と二重囲みを使います。

# 以下のように「.data[[y_ch]]」とと二重囲みを使う
y_ch <- "電気代"
ggplot(data = df_data03, 
       aes(x = 時間軸2, y = .data[[y_ch]], family = "HiraKakuPro-W3")) +
  geom_line() 

### (準備編ここまで)

列を順々に(本番編)

「for」を使い、順々にグラフを作成し、画像を保存します。

for, paste, ggsave

前述同様に「scale_x_date」を使いX軸目盛の表記を「YY年MM月」とし、グラフを生成します。
保存する画像ファイル名は、「paste」を使い「列名.png」としています。

# 「for (i in 3:ncol(df_data03))」で、3列目から列の最後まで順々に列(Y軸)を変更
gg_df <- NULL

for (i in 3:ncol(df_data03)) {

  y_col <- colnames(df_data03[, i])
  gg_df[[i]] <- df_data03 %>%
    ggplot(aes(x = 時間軸2, y = .data[[y_col]], family = "HiraKakuPro-W3")) +
    geom_line() +
    scale_x_date(date_breaks = "1 months",
                 date_labels = "%y/年%m月") +
    theme_gray (base_family = "HiraKakuPro-W3") +
    theme(axis.text.x = element_text(angle = 45, hjust=1))
  #グラフ保存
  image.file = paste('./images/', y_col, '.png', sep = '') 
  ggsave(image.file, plot = gg_df[[i]], dpi = 300, width = 6.4)
  
}

再掲となりますが上記コードを実行し、連続して生成したグラフの画像が以下の6枚です。

電気代(指数)の推移
都市ガス代(指数)の推移
プロパンガス(指数)の推移
灯油(指数)の推移
水道料(指数)の推移
下水道料(指数)の推移

いいなと思ったら応援しよう!