データ分析メモと北欧生活

旧Untitled Note. データ分析、計量経済・統計とR、水産管理、英語勉強、海外生活などについて備忘録や自分の勉強のOutputの場所として

MENU

【R】とりあえず簡単にggpplot2で2軸目を書きたい時はsec.axis

数ヶ月に一回ググってる気がするので自分用にメモ。

問題

とりあえずggplot2でエクセル的な2軸プロット(左右に別のY軸があってグラフが重なってるやつ)を書きたい。
ググっても丁寧なブログはたくさん見つかるのだが、とりあえずどれやればいいの!となる。
ggplot2以外に追加的にパッケージとかも使いたくない。

解決策

sec.axisscale_y_continuous()で使う。

# 適当な例
ggplot(data, aes(x=x,y=y, col=group)) +
   geom_line()+
   scale_y_continuous(sec.axis=sec_axis(~.*10, name="y2")) #ココ!

解説

準備

標準装備airqualityのデータを例に使います。

# パッケージ
library(tidyverse) # ggplot2含む

# データロード
data(airquality) 

# 時系列データにするためにDate変数を作成
airquality = airquality %>%
  # 元データに月と日はあり(MonthとDay)。年は適当に今年になる。
  mutate(date = as.Date(paste(Month,Day,sep="-"), format="%m-%d")) 

ステップ1:とりあえず描画

ワイドデータ(異なる変数がそれぞれの列で記録されているデータ)をそのまま描画する場合です。
ロングデータ(変数の値が一つの列に記録され、もう一つの列に変数名やカテゴリが記録されてるようなデータ)は後述。

まずとりあえずデータをそのまま描画すると以下のようになる。

ggplot(data=airquality,
       aes(x=date)) +
  geom_line(aes(y=Wind,col="Wind"))+
  geom_line(aes(y=Temp,col="Temp"))


なんかちょっと離れてるので重ねたい、みたいなときありますよね。

ステップ2:スケールする

一方の変数に係数をかけたり足し引きしたりすることでスケールする。
このスケールは、使うデータによるので、ここは数字みながら試行錯誤する必要ありです。
今回はシンプルに2つ目の変数である温度(temp)の数値が高いのでいい感じの数を引いてます。

# トライ2 スケールする
ggplot(data=airquality,
       aes(x=date)) +
  geom_line(aes(y=Wind,col="Wind"))+
  geom_line(aes(y=Temp-70,col="Temp"))


ステップ3:2軸目を足す

ここが一番の肝。
scale_y_continousの中でsec.axisという引数を使う。
このときに、sec_axisという関数で、数値をスケールすることができる。
上で70引いているので、ここでは70を足すことで本来の数値を表示できる。

# トライ3 2軸目を足す
ggplot(data=airquality,
       aes(x=date)) +
  geom_line(aes(y=Wind,col="Wind"))+
  geom_line(aes(y=Temp-70,col="Temp"))+
  scale_y_continuous(sec.axis = sec_axis(~.+70)) # 2軸目のY軸


ステップ4:2軸目のラベルを足す

2軸目がなんなのか表示する。
nameという引数で表示できるが、sec_axis関数の中でつかうこと!
カッコを見間違えてsec_axisの外、scale_y_continuousの引数としてnameを使うと、エラーが返されずに第1軸のラベルとして認識されてしまう。
2軸だと単位が異なる事が多いので、軸ラベルに単位を明示すると丁寧ですよね。

ggplot(data=airquality,
       aes(x=date)) +
  geom_line(aes(y=Wind,col="Wind"))+
  geom_line(aes(y=Temp-70,col="Temp"))+
  scale_y_continuous(sec.axis = sec_axis(~.+70, 
                                         name="Temp (F)"),
                     name="Wind (m2/s)"
                     )

なんでこんな気温高いんだと思ったら華氏(F)だからでした。

さらに細かくカスタマイズしたりスケールを設定するには「ggplot 2軸」とかで検索するとたくさんひっかかるのですが、とりあえず2軸!じゃあsec.axis!というのを覚えるために書きました。

おまけ:ロングデータ

ggplotだとロングデータ使って、color引数とかでカテゴリを色分けすることとか多いんですが、その場合はデータに予めスケールをかけとくほうがいいかもです。

以下はロングデータとワイドデータの違い。今回はOzoneとSolar.Rは無視してます。

#ロングデータに変換
airquality_long = airquality %>%
  pivot_longer(cols=c(Temp,Wind),names_to = "variable",values_to = "value")

# ロングデータ
> head(airquality_long)
# A tibble: 6 × 7
  Ozone Solar.R Month   Day date       variable value
  <int>   <int> <int> <int> <date>     <chr>    <dbl>
1    41     190     5     1 2022-05-01 Temp      67  
2    41     190     5     1 2022-05-01 Wind       7.4
3    36     118     5     2 2022-05-02 Temp      72  
4    36     118     5     2 2022-05-02 Wind       8  
5    12     149     5     3 2022-05-03 Temp      74  
6    12     149     5     3 2022-05-03 Wind      12.6

#ワイドデータ
> head(airquality)
  Ozone Solar.R Wind Temp Month Day       date
1    41     190  7.4   67     5   1 2022-05-01
2    36     118  8.0   72     5   2 2022-05-02
3    12     149 12.6   74     5   3 2022-05-03
4    18     313 11.5   62     5   4 2022-05-04
5    NA      NA 14.3   56     5   5 2022-05-05
6    28      NA 14.9   66     5   6 2022-05-06

スケールした新しい変数を作成

airquality_long = airquality_long %>%
  # もしvariableがTempなら70引く
  mutate(value2 = ifelse(variable=="Temp",value-70,value))

通常のggplot2の文法で書く。このときvalueではなくvalue2をy変数にセットする。
2軸の書き方は上と全く同じです。

ggplot(data=airquality_long,
       aes(x=date,y=value2,col=variable)) +
  geom_line()+
  scale_y_continuous(sec.axis = sec_axis(~.+70, 
                                         name="Temp (F)"),
                     name="Wind (m2/s)"
  )