Rで解析:箱ひげ図に有意差バーを付ける「ggsignif」パッケージ
「ggplot2」パッケージで作ったプロットに、群と群をつなぐ有意差バーを重ねられるパッケージです。比べたい2群の名前をlistで渡すと、検定を実行して、結果を表す記号までプロットに載せます。バーの位置と載せる文字を自分で決めることもできます。「ggsignif」パッケージは「ggplot2」パッケージの上で動くため、あわせて読み込んでおく必要があります。箱ひげ図や棒グラフに検定結果を添えたいときに、扱いやすいのではないかと考えます。
パッケージバージョンは0.6.4。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。
<おすすめのRに関する書籍です>
パッケージのインストール
下記コマンドを実行してください。
# パッケージのインストール
install.packages("ggsignif")コマンド例
詳細はコメント、パッケージのヘルプを確認してください。
略語=日本語の意味:
・aes:Aesthetic mappingの略で、データの列をプロットの見た目へ対応づける仕組み
・Brix:果汁や搾汁に溶けている糖の量を表す単位
・p値:検定で得られる確率で、小さいほど群の間の差が偶然では説明しにくい
有意差バーは、2つの群をつなぐ横棒と、その上に載せる記号の組み合わせです。アスタリスクの数はp値の小ささを表し、「***」が0.001未満、「**」が0.01未満、「*」が0.05未満という割り当てがよく使われます。
まず、例で共通して使うデータとプロットを作ります。京都市内で収穫した九条ねぎの糖度を、露地・トンネル・ハウスの3つの栽培方法ごとに30点ずつ集めた想定の架空データです。
# パッケージの読み込み
library("ggplot2")
library("ggsignif")
# 乱数を固定
set.seed(1204)
# 京都市内で収穫した九条ねぎの糖度を、栽培方法ごとにまとめたデータ
TestData <- data.frame(
Field = rep(c("露地", "トンネル", "ハウス"), each = 30),
Brix = c(
round(rnorm(30, mean = 8.4, sd = 1.1), 1),
round(rnorm(30, mean = 9.6, sd = 1.0), 1),
round(rnorm(30, mean = 10.8, sd = 1.2), 1)
)
)
# 栽培方法の並び順を固定
TestData$Field <- factor(TestData$Field, levels = c("露地", "トンネル", "ハウス"))
# 先頭3行を確認
head(TestData, 3)
Field Brix
1 露地 8.3
2 露地 8.6
3 露地 9.0
# 有意差バーを重ねるもとになる箱ひげ図を作る
# バーが切れないように、上側の余白を広げる
BoxPlot <- ggplot(TestData, aes(x = Field, y = Brix)) +
geom_boxplot(fill = "#a8d5a2") +
labs(x = "栽培方法", y = "糖度(Brix)") +
scale_y_continuous(expand = expansion(mult = c(0.05, 0.15)))
<おすすめのRに関する書籍です>
検定結果を有意差バーで重ねる:geom_signifコマンド
comparisonsオプションに比べたい2群の名前を渡すと、testオプションで指定した検定を実行し、結果をバーとしてプロットに重ねます。
| オプション | 意味 | 初期値 |
|---|---|---|
| mapping | aes()で作る見た目の対応づけ。inherit.aes = TRUEなら、プロット側の対応づけと合わせて使われる | NULL |
| data | この層で使うデータ。NULLならggplot()に渡したデータを引き継ぐ | NULL |
| stat | この層で使う統計処理の名前 | “signif” |
| position | 位置の調整方法 | “identity” |
| na.rm | FALSEなら欠損値を警告付きで取り除く。TRUEなら警告を出さずに取り除く | FALSE |
| show.legend | この層を凡例に入れるか。NAなら見た目の対応づけがあるときだけ入れる | NA |
| inherit.aes | FALSEならプロット側の対応づけを引き継がず、この層の指定だけを使う | TRUE |
| comparisons | 比べる2群を並べたベクトルのlist。群の名前か、x軸での位置を表す整数で指定する | NULL |
| test | 2群に当てる検定の名前。t.test、wilcox.testなどを文字列で渡す | “wilcox.test” |
| test.args | 検定に追加で渡すオプション | NULL |
| annotations | バーに載せる文字。指定するとtestオプションは使われない | NULL |
| map_signif_level | p値をそのまま載せるか、アスタリスクに置き換えるか。c(“***” = 0.001, “**” = 0.01, “*” = 0.05)の形で割り当てを決めることもできる | FALSE |
| y_position | バーを置く高さ | NULL |
| xmin | バーの左端の位置 | NULL |
| xmax | バーの右端の位置 | NULL |
| margin_top | データの最大値からどれだけ上にバーを置くか。プロットの高さに対する割合で指定する | 0.05 |
| step_increase | 比較を増やすときに、バーを何割ずつ上へずらすか | 0 |
| extend_line | バーの横線を縮める(負の値)か伸ばす(正の値)か | 0 |
| tip_length | バー両端の縦線の長さ。プロットの高さに対する割合で指定する | 0.03 |
| size | バーの線の太さ | 0.5 |
| textsize | 文字の大きさ | 3.88 |
| family | 文字に使うフォント | “” |
| vjust | バーに対して文字を上下に動かす量 | 0 |
| parse | TRUEなら文字を数式として解釈して表示する | FALSE |
| manual | バーの位置をdata.frameで渡すときにTRUEにする。facetごとに違う文字を載せるときに使う | FALSE |
| orientation | 層の向き。NAなら見た目の対応づけから自動で決まる。決まらないときは”x”か”y”を指定する | NA |
| … | layerに渡すその他のオプション。colour = “red”のように見た目を固定する指定もここに書く | なし |
露地とハウスの2群だけを比べます。map_signif_levelをTRUEにすると、p値の代わりにアスタリスクが載ります。
# 2群を比べて有意差バーを重ねる:geom_signifコマンド
BoxPlot +
geom_signif(
# 比べる2群の組み合わせを指定:comparisonsオプション
comparisons = list(c("露地", "ハウス")),
# 当てる検定を指定:testオプション
test = "t.test",
# 結果をアスタリスクに置き換える:map_signif_levelオプション
map_signif_level = TRUE,
# バーの線の太さと文字の大きさ:size,textsizeオプション
size = 0.8,
textsize = 5,
colour = "red"
)2群を比べて有意差バーを重ねる:geom_signifコマンド

comparisonsのlistを増やすと、複数の組み合わせをまとめて重ねられます。そのままではバーが同じ高さで重なるため、step_increaseオプションで段違いにずらします。
# 3つの組み合わせをまとめて重ねる:geom_signifコマンド
BoxPlot +
geom_signif(
comparisons = list(c("露地", "トンネル"), c("トンネル", "ハウス"), c("露地", "ハウス")),
# 当てる検定を指定:testオプション
test = "wilcox.test",
# アスタリスクの割り当てを自分で決める:map_signif_levelオプション
map_signif_level = c("***" = 0.001, "**" = 0.01, "*" = 0.05),
# バーを段違いにずらす:step_increaseオプション
step_increase = 0.12,
# バー両端の縦線を短くする:tip_lengthオプション
tip_length = 0.01,
size = 0.8,
textsize = 5,
colour = "red"
)3つの組み合わせをまとめて重ねる:geom_signifコマンド

<おすすめのRに関する書籍です>
位置と文字を自分で決める:stat_signifコマンド
検定を実行せず、自分で用意した文字をバーに載せるときに使います。annotationsオプションに文字を渡し、xmin・xmax・y_positionオプションでバーを置く位置を決めます。
| オプション | 意味 | 初期値 |
|---|---|---|
| mapping | aes()で作る見た目の対応づけ。inherit.aes = TRUEなら、プロット側の対応づけと合わせて使われる | NULL |
| data | この層で使うデータ。NULLならggplot()に渡したデータを引き継ぐ | NULL |
| position | 位置の調整方法 | “identity” |
| na.rm | FALSEなら欠損値を警告付きで取り除く。TRUEなら警告を出さずに取り除く | FALSE |
| show.legend | この層を凡例に入れるか。NAなら見た目の対応づけがあるときだけ入れる | NA |
| inherit.aes | FALSEならプロット側の対応づけを引き継がず、この層の指定だけを使う | TRUE |
| comparisons | 比べる2群を並べたベクトルのlist。群の名前か、x軸での位置を表す整数で指定する | NULL |
| test | 2群に当てる検定の名前。t.test、wilcox.testなどを文字列で渡す | “wilcox.test” |
| test.args | 検定に追加で渡すオプション | NULL |
| annotations | バーに載せる文字。指定するとtestオプションは使われない | NULL |
| map_signif_level | p値をそのまま載せるか、アスタリスクに置き換えるか。c(“***” = 0.001, “**” = 0.01, “*” = 0.05)の形で割り当てを決めることもできる | FALSE |
| y_position | バーを置く高さ | NULL |
| xmin | バーの左端の位置 | NULL |
| xmax | バーの右端の位置 | NULL |
| margin_top | データの最大値からどれだけ上にバーを置くか。プロットの高さに対する割合で指定する | 0.05 |
| step_increase | 比較を増やすときに、バーを何割ずつ上へずらすか | 0 |
| tip_length | バー両端の縦線の長さ。プロットの高さに対する割合で指定する | 0.03 |
| size | バーの線の太さ | 0.5 |
| textsize | 文字の大きさ | 3.88 |
| family | 文字に使うフォント | “” |
| vjust | バーに対して文字を上下に動かす量 | 0 |
| parse | TRUEなら文字を数式として解釈して表示する | FALSE |
| manual | バーの位置をdata.frameで渡すときにTRUEにする。facetごとに違う文字を載せるときに使う | FALSE |
| orientation | 層の向き。NAなら見た目の対応づけから自動で決まる。決まらないときは”x”か”y”を指定する | NA |
| … | layerに渡すその他のオプション。colour = “red”のように見た目を固定する指定もここに書く | なし |
露地を基準にした糖度の差を計算し、その値をそのままバーに載せます。
# 露地を基準にした糖度の差を求める
MeanBrix <- tapply(TestData$Brix, TestData$Field, mean)
DiffText <- paste0("+", round(MeanBrix[-1] - MeanBrix[1], 2), " Brix")
# 求めた文字を確認
DiffText
[1] "+0.91 Brix" "+1.83 Brix"
# 検定を使わず、自分で決めた文字をバーに載せる:stat_signifコマンド
BoxPlot +
stat_signif(
# バーに載せる文字:annotationsオプション
annotations = DiffText,
# バーの左端と右端の位置:xmin,xmaxオプション
xmin = c(1, 1),
xmax = c(2, 3),
# バーを置く高さ:y_positionオプション
y_position = c(13.4, 14.6),
size = 0.8,
textsize = 4.5,
colour = "red"
)検定を使わず、自分で決めた文字をバーに載せる:stat_signifコマンド

この記事が誰かの役に立ちますように。
[…] Rで解析:ggplot2のプロットに有意差バーを追加!「ggsignifr」パッケージ […]