LoginSignup
0
0

More than 3 years have passed since last update.

R & ggplot2 で 2 軸目ぽいのを描くことができた

Posted at

R で円グラフが何とかやっとかさ描けるようになった話 」のの続きみたいなところです。2 軸目と言ってよいのかは分かりませんが、以下みたいな感じにそれっぽく見えるのを描くことに成功したので、その時のメモです。

image.png

今回は気象庁が提供してくれている「世界の天候データツール(ClimatView 月統計値)」から名古屋の「月平均気温」と「月降水量」のデーターをダウンロードして使っています。以下のようにして data.frame に変換しておきます。

"名古屋の気象データー(2020年)"
library(dplyr)

weather <- '
年,月,月平均気温,月降水量
2020, 1, 7.6, 56
2020, 2, 7.1, 54
2020, 3, 10.7, 150
2020, 4, 13.4, 111
2020, 5, 20.6, 135
2020, 6, 24.6, 230
2020, 7, 25.4, 406
2020, 8, 30.3, 13
2020, 9, 25.4, 231
2020, 10, 18.0, 269
2020, 11, 14.0, 37
2020, 12, 7.4, 22
' %>% data.table::fread()

月降水量をプロットしてみる

まずは「月降水量」をプロットしてみます。たったこれだけのコードでもなかなか良い感じです。

"月降水量をプロットしてみる"
library(dplyr)
library(ggplot2)

(weather %>%
    ggplot(aes(x = ))
    + geom_bar(aes(y = 月降水量), stat = "identity", fill="gray", color="black", size=0.5)
    + geom_text(aes(y = 月降水量, label = 月降水量), vjust = -0.5, hjust = 0.5)
    + scale_x_continuous(breaks = seq(1,12,1))
    + cowplot::theme_cowplot()
)

実行結果
image.png

月平均気温を追加

続けて先のグラフに「月平均気温」を追加してみます。

実行結果を見ると「月平均気温」が下方にプロットされていることがわかります。どうやら 2 つ目の値をプロットしたら新たな軸を追加してくれるわけではなさそうです。

これじゃあ「月平均気温」の変化が分かりにくいなーっていうのもそうですが、そもそも「月降水量」の単位は mm で「月平均気温」の単位は ℃ なのにそれを同じ軸で描くんかい、なーんて思ったりすると別の軸がほしい、てな話になるみたいです。

個人的にはグラフをひとつにまとめようなんて考えずに、素直に2つ描けばいいじゃん、なんて思ってしまうんですが…。

"月平均気温を追加"
library(dplyr)
library(ggplot2)

(weather %>%
    ggplot(aes(x = ))
    + geom_bar(aes(y = 月降水量), stat = "identity", fill="gray", color="black", size=0.5)
    + geom_text(aes(y = 月降水量, label = 月降水量), vjust = -0.5, hjust = 0.5)
    + geom_line(aes(y = 月平均気温))
    + geom_point(aes(y = 月平均気温), size=2)
    + geom_text(aes(y = 月平均気温, label = 月平均気温), vjust = -0.5, hjust = 0.5)
    + scale_x_continuous(breaks = seq(1,12,1))
    + cowplot::theme_cowplot()
)

実行結果
image.png

軸を追加できない?

というわけで「月平均気温」の軸を追加しよう!と探しだしたものの良い方法が見つかりません。scale_y_continuous に sec.axis が指定できることはわかったんですが、それを指定しても目盛りが追加されるだけで、その目盛りにあわせてそれにプロットできるわけではなさそうでした。

あきらめてごまかしてみる

いろいろと悩んだあげく、仕方ないので軸を追加することはあきらめてそれっぽく見せることを考えることにしました。具体的には「月降水量」を基準として「月平均気温」のY座標を計算してみたいと思います。以下みたいな感じでしょうか。

"月降水量の値を基準にして月平均気温の座標を求める"
月平均気温y <- (月平均気温 - min(月平均気温)) / (max(月平均気温) - min(月平均気温)) * (max(月降水量) - min(月降水量)) + min(月降水量)

慣れていないと正直分かりにくいですし、本当にこれ合ってるの?っていう話もありますので、自分でゴリゴリ書くんじゃなくって既にある scales パッケージを使ってみたいと思います。パッケージ使うことで簡単でかつ見た目も分かりやすくなりました。素晴らしいです。

"月降水量の値を基準にして月平均気温の座標を求める(scales使用)"
月平均気温y <- scales::rescale(月平均気温, to = range(月降水量), from = range(月平均気温))

念のため結果を確認してみます。どっちも同じ結果になっているようです。

"月降水量の値を基準にして月平均気温の座標を求める(念のため確認)"
library(dplyr)
library(ggplot2)

weather %>%
    mutate(月平均気温y = (月平均気温 - min(月平均気温)) / (max(月平均気温) - min(月平均気温)) * (max(月降水量) - min(月降水量)) + min(月降水量)) %>%
    mutate(月平均気温y2 = scales::rescale(月平均気温, to = range(月降水量), from = range(月平均気温))) %>%
    select(月平均気温, 月平均気温y, 月平均気温y2) %>% head(5)
"月降水量の値を基準にして月平均気温の座標を求める(念のため確認)(実行結果)"
 weather %>%
+ mutate(月平均気温y = (月平均気温 - min(月平均気温)) / (max(月平均気温) - min( 月平均気温)) * (max(月降水量) - min(月降水量)) + min(月降水量)) %>%
+ mutate(月平均気温y2 = scales::rescale(月平均気温, to = range(月降水量), from = range(月平均気温))) %>%
+ select(月平均気温, 月平均気温y, 月平均気温y2) %>% head(5)
   月平均気温 月平均気温y 月平均気温y2
1:        7.6    21.46983     21.46983
2:        7.1    13.00000     13.00000
3:       10.7    73.98276     73.98276
4:       13.4   119.71983    119.71983
5:       20.6   241.68534    241.68534

で作ったのが以下のものとなります。座標は計算したものを使って、ラベルに実数を表示することでそれっぽく見せています。

"あきらめてごまかしてみる"
library(dplyr)
library(ggplot2)

(weather %>%
    mutate(月平均気温y = scales::rescale(月平均気温, to = range(weather$月降水量), from = range(weather$月平均気温))) %>%
    ggplot(aes(x = ))
    + geom_bar(aes(y = 月降水量), stat = "identity", fill="gray", color="black", size=0.5)
    + geom_text(aes(y = 月降水量, label = 月降水量), vjust = -0.5, hjust = 0.5)
    + geom_line(aes(y = 月平均気温y))
    + geom_point(aes(y = 月平均気温y), size=2)
    + geom_text(aes(y = 月平均気温y, label = 月平均気温), vjust = -0.5, hjust = 0.5)
    + scale_x_continuous(breaks = seq(1,12,1))
    + cowplot::theme_cowplot()
)

実行結果
image.png

月平均気温の目盛りを追加

さっき発見した sec.axis を使って「月平均気温」の目盛りを追加してみたいと思います。

簡単に追加できると思ったんですが、マニュアルを読んでいくと自由な値が設定できるわけではなく計算式を指定する必要があるようです。10 足すとかべき乗するといった単純な計算式なら良いんですが、今回はそうじゃないので、うーん、てな感じです。

うーん、てな感じで考えていたところ、さっき使った scales::rescale 使えばいいじゃん!てなことに気づいたので、使ってみたところ、あれま、というくらいそれっぽいのができてしまいました。

"月平均気温の目盛りを追加"
library(dplyr)
library(ggplot2)

(weather %>%
    mutate(月平均気温y = scales::rescale(月平均気温, to = range(weather$月降水量), from = range(weather$月平均気温))) %>%
    ggplot(aes(x = ))
    + geom_bar(aes(y = 月降水量), stat = "identity", fill="gray", color="black", size=0.5)
    + geom_text(aes(y = 月降水量, label = 月降水量), vjust = -0.5, hjust = 0.5)
    + geom_line(aes(y = 月平均気温y))
    + geom_point(aes(y = 月平均気温y), size=2)
    + geom_text(aes(y = 月平均気温y, label = 月平均気温), vjust = -0.5, hjust = 0.5)
    + scale_x_continuous(breaks = seq(1,12,1))
    + scale_y_continuous(sec.axis = sec_axis(~ scales::rescale(., to = range(weather$月平均気温), from = range(weather$月降水量))
        ,name = "月平均気温(℃)"
        )
        )
    + ylab("降水量(mm)")
    + cowplot::theme_cowplot()
)

実行結果
image.png

本当にあってるの?

あまりに簡単にできてしまって怪しすぎるので本当にあっているかを確認したいと思います。座標を細かく表示させて、適当な値の水平線を引いて目視してみます。

まぁまぁあってるっぽいです。

"本当にあってるの?"
library(dplyr)
library(ggplot2)

(weather %>%
    mutate(月平均気温y = scales::rescale(月平均気温, to = range(weather$月降水量), from = range(weather$月平均気温))) %>%
    ggplot(aes(x = ))
    + geom_bar(aes(y = 月降水量), stat = "identity", fill="gray", color="black", size=0.5)
    + geom_text(aes(y = 月降水量, label = 月降水量), vjust = -0.5, hjust = 0.5)
    + geom_line(aes(y = 月平均気温y))
    + geom_point(aes(y = 月平均気温y), size=2)
    + geom_text(aes(y = 月平均気温y, label = 月平均気温), vjust = -0.5, hjust = 0.5)
    + geom_hline(yintercept = scales::rescale(14, to = range(weather$月降水量), from = range(weather$月平均気温)), size = 0.5) 
    + geom_hline(yintercept = scales::rescale(18, to = range(weather$月降水量), from = range(weather$月平均気温)), size = 0.5) 
    + geom_hline(yintercept = scales::rescale(25.4, to = range(weather$月降水量), from = range(weather$月平均気温)), size = 0.5) 
    + geom_hline(yintercept = scales::rescale(30.3, to = range(weather$月降水量), from = range(weather$月平均気温)), size = 0.5) 
    + scale_x_continuous(breaks = seq(1,12,1))
    + scale_y_continuous(sec.axis = sec_axis(~ scales::rescale(., to = range(weather$月平均気温), from = range(weather$月降水量))
        ,name = "月平均気温(℃)"
        ,breaks = seq(0, 100, 0.5)
        )
        )
    + ylab("降水量(mm)")
    + cowplot::theme_cowplot()
)

実行結果
image.png

もうちょい調整

凡例を追加して更にそれっぽくしてみます。

"もうちょい調整"
library(dplyr)
library(ggplot2)

(weather %>%
    mutate(月平均気温y = scales::rescale(月平均気温, to = range(weather$月降水量), from = range(weather$月平均気温))) %>%
    ggplot(aes(x = ))
    + geom_bar(aes(y = 月降水量, fill="降水量(mm)"), stat = "identity", color="black", size=0.5)
    + geom_text(aes(y = 月降水量, label = 月降水量), vjust = -0.5, hjust = 0.5)
    + geom_line(aes(y = 月平均気温y, color="月平均気温(℃)"))
    + geom_point(aes(y = 月平均気温y, color="月平均気温(℃)"), size=2, show.legend=F)
    + geom_text(aes(y = 月平均気温y, label = 月平均気温), vjust = -0.5, hjust = 0.5)
    + scale_x_continuous(breaks = seq(1,12,1))
    + scale_y_continuous(sec.axis = sec_axis(~ scales::rescale(., to = range(weather$月平均気温), from = range(weather$月降水量))
        ,name = "月平均気温(℃)"
        )
        )
    + ylab("降水量(mm)")
    + scale_fill_manual(values=c("gray"))
    + scale_color_manual(values=c("black"))
    + cowplot::theme_cowplot()
    + theme(legend.position = c(0.2, 0.95)
        ,legend.box = "horizontal"
        ,legend.title = element_blank()
        )
)

実行結果
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0