ggplot2で多軸プロットを書きたくない

# 初めに
Excelではy軸が左右にある2軸プロットを簡単に作れるが、ggplot2では簡単には作れない。
現在の業務では2軸グラフだけではなく、3~4軸の多軸なグラフが要求されることがある。
これまでは黒魔術と化したExcelテンプレートでなんとかしてきているが、黒魔術な上、100以上のデータセットに適応しなければならない未来が見えているため、どうにか冬休み中には解法を考えたい。

Baseのプロットを使ったり力技で書く方法もあるが、ggplot2の簡便できれいな図に魂を売った身としてはggplot2で簡単になんとかしたい。

ここに心拍数[bpm]と歩数[steps/min]と速度[m/min]がそろっている1分毎の経時データがある。これをモデルとしてつかっていく。速度(Speed)を折れ線グラフ、心拍数(HeartRate)を、歩数(Steps)を棒グラフで示す。

|DateTime            |     Speed| HeartRate| Steps|
|:-------------------|---------:|---------:|-----:|
|2022-12-01 12:00:00 |  93.41503|  85.43951|   107|
|2022-12-01 12:01:00 |  87.36342|  91.94734|   110|
|2022-12-01 12:02:00 |  94.70084|  88.93372|    97|
|2022-12-01 12:03:00 |  84.55080|  94.74760|    97|
|2022-12-01 12:04:00 |  84.42936|  83.16780|    99|

```R
## データセット
df <- tibble(
  DateTime = seq(lubridate::ymd_hms("2022-12-01 12:00:00", tz="Asia/Tokyo"), by= 60, length.out=120),
  Speed = rnorm(120, mean = 90, sd = 5),
  HeartRate = c(rnorm(40, mean = 90, sd = 5),rnorm(40, mean = 110, sd = 10),rnorm(40, mean = 130, sd = 15)),
  Steps = floor(c(rnorm(40, mean = 100, sd = 5),rnorm(40, mean = 110, sd = 10),rnorm(40, mean = 120, sd = 15))),
)
```
# グラフを並べる方法について
ggplot2のグラフを並べる方法は、[こちらの記事](https://qiita.com/nozma/items/cd98ec7938e0783d5d89)にあるようにいろいろ方法はあるが、x軸を共通にしたいという要望が強いため（できないことはないが）少し目的と外れる。

# 今回の解法：Facet_wrap

多軸プロットにしたいということは、共通のx軸を持ったグラフを縦方向で比較したいということである。
Facet_wrapを使って、縦一列に並べてあげればいい。

```R
df %>%
  pivot_longer(cols = c(Speed, HeartRate, Steps)) %>%
  ggplot(aes(x = DateTime, y = value)) +
  geom_point(data = ~ filter(.x, name == "HeartRate")) +
  geom_line(data = ~ filter(.x, name == "Speed")) +
  geom_bar(data = ~ filter(.x, name == "Steps"), stat = "identity") +
  facet_wrap(~ name, ncol = 1, scale = "free_y")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078267/b0588ded-046a-eeb1-673f-174a20dcbeb2.png)

```facet_wrap(~ name, ncol = 1, scale = "free_y")```ではncol=1で縦一列を指定し、scale = "free_y"でｙ軸の範囲を適切にしている。ここでは、```geom_***(data = ~ filter(.x, name == "***")) ```としてあげることで、縦持ちのデータから必要なものだけをを個別にプロットすることができる。

## 微調整

### 並び順
グラフの並び順は2通りあるが、1つめの前処理がおすすめである。
1. 前処理で対応する方法
    縦持ちに変換した後の属性列（name）をFactor化する。この時のlevelsを縦に並べたい順にしておく。
    ```R
    df %>%
      pivot_longer(cols = c(Speed, HeartRate, Steps)) %>%
      mutate(across(name, factor, levels=c("Speed", "HeartRate", "Steps"))) %>% 
      ggplot(aes(x = DateTime, y = value)) +
      geom_point(data = ~ filter(.x, name == "HeartRate")) +
      geom_line(data = ~ filter(.x, name == "Speed")) +
      geom_bar(data = ~ filter(.x, name == "Steps"), stat = "identity") +
      facet_wrap(~name, ncol = 1, scale = "free_y")
    ```
1. facet_wrapの段階でコントロールする方法(非推奨)
    原理は一緒であるが、Factor化する場所の違いである。
    ```R:非推奨.R
    df %>%
      pivot_longer(cols = c(Speed, HeartRate, Steps)) %>%
      ggplot(aes(x = DateTime, y = value)) +
      geom_point(data = ~ filter(.x, name == "HeartRate")) +
      geom_line(data = ~ filter(.x, name == "Speed")) +
      geom_bar(data = ~ filter(.x, name == "Steps"), stat = "identity") +
      facet_wrap(~factor(name, levels=c("Speed", "HeartRate", "Steps"))
    , ncol = 1, scale = "free_y")
    ```
どちらも結果は一緒である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078267/c67adc88-ede2-7b15-c214-864ef541d613.png)

### ラベルのタイトルと位置
ここまでやれば、最低限はできていますがラベルのタイトルに単位を入れたり、位置を変えた方が見やすいかもしれません。この時facet_wrapでコントロールすると、labeller内での表記が難しくなります。

```R
df %>%
  pivot_longer(cols = c(Speed, HeartRate, Steps)) %>%
  mutate(across(name, factor, levels = c("Speed", "HeartRate", "Steps"))) %>%
  ggplot(aes(x = DateTime, y = value)) +
  geom_point(data = ~ filter(.x, name == "HeartRate")) +
  geom_line(data = ~ filter(.x, name == "Speed")) +
  geom_bar(data = ~ filter(.x, name == "Steps"), stat = "identity") +
  facet_wrap(~ name,
             ncol = 1,
             scale = "free_y",
             strip.position = "right",
             labeller = labeller(
               name =
                 c(
                   "HeartRate" = "HeartRate [BPM]",
                   "Speed" = "Speed [m/min]",
                   "Steps" = "Steps [steps/min]"
                 )
             ))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078267/be589d0d-ea43-04f3-3c91-fc2db84b945c.png)


後は、Y軸の調整がありますが、12/25までに投稿にはここまでが限界でした。 ggh4x::facetted_pos_scalesがうまく動かない。