Rでのスプリット・バイオリンプロット（Split-Violin Plot）の描画方法

# 背景
論文を読んでいて、以下のような図を見つけました。Split-violinというみたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344524/8810959e-2c4a-4714-842f-021e0cab5b80.png)
（引用：[Lu, X., & Yang, J. (2025). Second language embodiment of action verbs: the impact of bilingual experience as a multidimensional spectrum. *Bilingualism: Language and Cognition*, 1-17.](https://www.cambridge.org/core/journals/bilingualism-language-and-cognition/article/second-language-embodiment-of-action-verbs-the-impact-of-bilingual-experience-as-a-multidimensional-spectrum/0D1294D063290958373BD692BD11DEA2)）

通常、このような2変数の描画場合だと、4つのバイオリンプロットを描画するため、スペースを取ってしまいます。

```R
mtcars$vs <- factor(mtcars$vs)
mtcars$am <- factor(mtcars$am)

colors <- c("1" = "#f79428", "0" = "#5383c3")

ggplot(mtcars, aes(x = am, y = mpg, group = interaction(am, vs), fill = vs)) +
  geom_violin(alpha = 0.5, position = position_dodge(width = 0.9), trim = F) +
  geom_jitter(aes(color = vs), position = position_dodge(width = 0.9), alpha = 0.8) +  
  scale_fill_manual(values = colors) +
  scale_color_manual(values = colors) 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344524/2d4ff089-19f2-4a5b-a2ea-ff7ad601045c.png)


Split-violinでは上述のように、2つのバイオリンプロットを半分ずつくっつけて描画するためスペースを節約できます。また、データの比較も行いやすい気がします。


# 実装
この図専用のRの関数が存在します。2025年3月現在、いまだCRANには登録されていないようです（[パッケージのGithubレポジトリ：introdataviz](https://github.com/PsyTeachR/introdataviz?tab=readme-ov-file)）。CRANに登録がないので、```devtools()```関数で開発版をダウンロードします（私のRのバージョンは、4.3.2で、Windowsを使用しています）。

```R
library(devtools)
install_github("psyteachr/introdataviz")
```

データセットは、```mtcars```を使用しました。描画に使用するデータは因子型に変換しておきます。
```R
mtcars$am <- factor(mtcars$am)
mtcars$vs <- factor(mtcars$vs)
```

## Step 1
分かりやすいように細かい設定は取り払っています。```geom_split_violin()```の中には、```trim = F```を加えたほうが滑らかな描画になります。また、```color = NA```を追加することで枠線が消えます。

- コード
```R
library(ggplot2)
ggplot(mtcars, aes(x = am, y = mpg, fill = vs)) +
  introdataviz::geom_split_violin(trim = F, color = NA) +
  labs(x = "am", y = "mpg") 
```
- 出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344524/97cde158-7d90-45d9-9987-b929accc652f.png)

## Step 2
各データを点で、平均値とエラーバーも図に追加しました。```geom_split_violin()```の中の```alpha```で図の透明度を薄くしないと、各データの点が塗りつぶされて見えません。

- コード
```R
ggplot(mtcars, aes(x = am, y = mpg, fill = vs)) +
  introdataviz::geom_split_violin(alpha = 0.3, trim = F, color = NA) +
  
  # 点を描画するコード
  geom_jitter(aes(color = vs), position = position_dodge(.5), alpha = 0.8) +  
  
  # 平均値とエラーバーを描画するコード
  stat_summary(fun.data = "mean_se", geom = "pointrange", show.legend = F, 
               position = position_dodge(.175)) +
  
  labs(x = "am", y = "mpg") 
```
- 出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344524/879f3bdf-06d7-485c-8c8c-eb800521c079.png)

## Step 2（ボックスプロット）
ボックスプロットを描画することもできます。
- コード
```R
ggplot(mtcars, aes(x = am, y = mpg, fill = vs)) +
  introdataviz::geom_split_violin(, alpha = 0.3, trim = F, color = NA) +
  
  geom_jitter(aes(color = vs), position = position_dodge(.5), alpha = 0.8) +
  
  #ボックスプロットを追加
  geom_boxplot(width = .2, alpha = .6, show.legend = FALSE) +
  
  labs(x = "am", y = "mpg") 
```
- 出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344524/183f7341-15ae-474d-b951-a107de1a9747.png)

## Step 3
上で紹介した論文内の図に近い色を設定してみます。1とコーディングしているデータにオレンジ、0に青を指定します。目視で色を選んでいるので、全く同じ色ではありません。

- コード
```R
colors <- c("1" = "#f79428", "0" = "#5383c3")
```

```alpha```を0.3から0.5に変更し、図の色を少し濃ゆくしています。また、```theme_classic()```を追加し、図の枠線をL字型に変更しています。
```R
ggplot(mtcars, aes(x = am, y = mpg, fill = vs)) +
  introdataviz::geom_split_violin(, alpha = 0.5, trim = F, color = NA) +
  geom_jitter(aes(color = vs), position = position_dodge(.5), alpha = 0.8) +  # データ点散布
  stat_summary(fun.data = "mean_se", geom = "pointrange", show.legend = F, 
               position = position_dodge(.175)) +
  
  #上で指定した色を設定
  scale_fill_manual(values = colors) +
  scale_color_manual(values = colors) +
  
  #図の枠線をL字型に設定
  theme_classic()
  
  labs(x = "am", y = "mpg") 
```
- 出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344524/0195375c-d4d4-4178-b934-2cadcb18a6d4.png)

## 完成版
上で紹介した図には有意差を表すアスタリスクも描画されています。```ggpubr```パッケージの```stat_compare_means```関数を用いて有意差がある条件間にはアスタリスクを描画するように設定します。他にも有意差を表示させる方法があるようです（参考記事：[https://indenkun.hatenablog.com/entry/2020/08/13/233029](https://indenkun.hatenablog.com/entry/2020/08/13/233029)）。今回は、同じam条件内でvs0とvs1の平均値差を検定しています。

- コード
```R
library(ggpubr)
ggplot(mtcars, aes(x = am, y = mpg, fill = vs)) +
  introdataviz::geom_split_violin(alpha = 0.5, trim = FALSE, color = NA) +
  geom_jitter(aes(color = vs), position = position_dodge(0.5), alpha = 0.8) +  
  stat_summary(fun.data = "mean_se", geom = "pointrange", show.legend = FALSE, 
               position = position_dodge(0.175)) +
  
  # グループ間の統計的有意差を表示
  stat_compare_means(aes(group = vs), method = "t.test", label = "p.signif") +
  
  scale_fill_manual(values = colors) +
  scale_color_manual(values = colors) +
  theme_classic() +
  labs(x = "am", y = "mpg")
```
- 出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344524/00fdcd94-eb5e-4492-977e-8c2c5f2fb625.png)

# 最後に
この図を再現してほしい！というものがあればご連絡お願いします。

# 参考資料
- [psyTeachR](https://github.com/PsyTeachR)
- [Second language embodiment of action verbs: the impact of bilingual experience as a multidimensional spectrum](https://www.cambridge.org/core/journals/bilingualism-language-and-cognition/article/second-language-embodiment-of-action-verbs-the-impact-of-bilingual-experience-as-a-multidimensional-spectrum/0D1294D063290958373BD692BD11DEA2)
- [ggplot2を使ったグラフ（棒グラフ）の体裁の調整](https://datator.exblog.jp/24800112/)
- [Rのggplot2でグラフを描いたときに有意差の記号、*とかそういうのをグラフ上に書こうとしたときの方法について](https://indenkun.hatenablog.com/entry/2020/08/13/233029)
- [論文投稿用プロットを瞬時に作図する](https://ponta-bioinformatics.com/ggpubr/)