ggplot2でのfacet_grid()使用時に、それぞれのパネルごとに直線(geom_segment)や塗りつぶし領域(geom_rect)を設定して描画する方法です。

解決策は一言で書くととてもシンプル。
geon_segment()geom_rect()で指定するデータにも、facet_grid()で使った要因と同じものを変数として用意しておくだけ」です。

以下、プログラム例です。
permutation testで実測値とシミュレーション値の比較結果を図示したいときなどに使えるかも。

目次

環境

  • Mac
  • R
  • R Studio
  • Tidyverseパッケージ

ダミーデータ生成

まずは乱数生成関数を使い、ダミーのデータセットdf_dataを作成します。

df_data <- data.frame(
  x = rnorm(1000, mean = 0, sd = 2),        #平均0、標準偏差2
  y = rnorm(1000, mean = 0.3, sd = 1.5),    #平均0.3、標準偏差1.5
  z = rnorm(1000, mean = -0.2, sd = 1)      #平均-0.2、標準偏差1
    ) %>%
  pivot_longer(
    cols = everything(),
    names_to = "Variable",
    values_to = "sample"
  )

これで、このような構造のデータフレームができます。

Variable	sample
x	1.3785482
y	-0.5488806
z	-2.0488779
x	-2.5268924
y	1.3306550
z	-0.4958901
# 以下、省略

x,y,zそれぞれに、平均と標準偏差が異なる正規分布に従うデータが1000個ずつ入っています。

以下、このデータをベースにグラフを描いていきます。

基本のプロット

まずは、TidyVerseパッケージに含まれるggplot2パッケージでヒストグラムを描いてみます。

#最初にパッケージを読み込む
library(tidyverse) #インストール済みと想定

その際、facet_grid()で変数x,y,zのデータを別々のパネルに分けて描画します。

df_data %>%
  ggplot() +
    geom_histogram(aes(x = sample)) + #ヒストグラム
    facet_grid(~ factor(Variable)) + #x,y,zのデータを別々のパネルに
    theme_classic() + #自分好みの設定
    theme( #自分好みの設定
      strip.background = element_rect(linewidth = 0.5),
      strip.placement = "outside",
      panel.spacing = unit(1, "lines")
    )

そうすると、このようなグラフが出力されます。

gplot2でfacet_grid()を用いたヒストグラム

直線を追加する

次に、上で描画した基本のヒストグラムに、実測値データの場所を直線で追加したいといった場合は、以下のようにします。

たとえば、

  • パネルxでは、sample = -3.8
  • パネルyでは、sample = -6.0
  • パネルzでは、sample = 0.0

に直線を引きたいとします。

そのときはまず、以下のようなデータフレームdf_real_dataを作成します。

#facet_gird()で指定した要因と同じものを変数として追加するのが肝
df_real_data <- data.frame(
  Variable = c("x", "y", "z"), #肝
  sample = c(-3.8, -6.0, 0.0)
)

geom_vline() ver.

ただ直線を引けばいいという時は、geom_vline()を使います。

df_data %>%
  ggplot() +
    geom_histogram(aes(x = sample)) + #ヒストグラム
    geom_vline( #ここが追加部分
      data = df_real_data, #先ほど作成したデータを指定
      aes(xintercept = sample, colour = "orange")
    ) + 
    facet_grid(~ factor(Variable)) + #x,y,zのデータを別々のパネルに
    theme_classic() + #自分好みの設定
    theme( #自分好みの設定
      strip.background = element_rect(linewidth = 0.5),
      strip.placement = "outside",
      panel.spacing = unit(1, "lines"),
      legend.position = "none" #ここも追加(vlineの色が凡例として表示されないように)
    )

そうすると、このようなグラフが出力されます。(sampleの値がオレンジ色の直線で表示されています)

gplot2でfacet_grid()を用いたヒストグラムに、各パネル別にvlineを追加したもの

geom_segment() ver.

上記の「geom_vline() ver.」では、y = 0を貫通して直線が引かれます。なので、見た目のために、直線の範囲をy = 0からにしたい場合もあると思います。

そんなときは、geom_segment()で線を引く範囲を指定すればOK。

df_data %>%
  ggplot() +
    geom_histogram(aes(x = sample)) + #ヒストグラム
    geom_segment( #変更部分。yendは、元データから適当に設定
      data = df_real_data, #先ほど作成したデータを指定
      aes(x = sample, xend = sample, y = 0, yend = 180, colour = "orange")
    ) + 
    facet_grid(~ factor(Variable)) + #x,y,zのデータを別々のパネルに
    theme_classic() + #自分好みの設定
    theme( #自分好みの設定
      strip.background = element_rect(linewidth = 0.5),
      strip.placement = "outside",
      panel.spacing = unit(1, "lines"),
      legend.position = "none"
    )

このようなグラフが出力されます。

gplot2でfacet_grid()を用いたヒストグラムに、各パネルごとにsegmentを追加したもの

領域を追加する

さらに、元データの分布から、有意水準5%や1%のエリアを示したいときもあるかと思います。そんなときは、geom_rect()を使います。

そのためにまず有意水準1%の閾値を計算し、その結果をdf_data_thresholdsに代入します。(閾値の計算には、Rのデフォルト関数quantile()を使用)

df_data %>%
  group_by(Variable) %>%
  summarise(
    threshold_1 = quantile(sample, 0.01), #1%閾値
    threshold_99 = quantile(sample, 0.99) #99%閾値
  ) -> df_data_thresholds

元データをgroup_byしたので、df_data_thresholdsにはfacet_grid()で指定した要因と同じものが、すでに変数「Variable」として入っています。

あとはgeom_rect()で、1%および99%の閾値をdf_data_thresholdsから指定すればOK。

df_data %>%
  ggplot() +
    geom_histogram(aes(x = sample)) + #ヒストグラム
    geom_segment( #直線描画部分
      data = df_real_data,
      aes(x = sample, xend = sample, y = 0, yend = 200, colour = "orange")
    ) +
    geom_rect( #領域描画部分(99%以上)
      data = df_data_thresholds, #閾値の計算結果データを指定
      aes(xmin = threshold_99, xmax = 8, ymin = 0, ymax = 200), #xminやxmaxは、元データから適当に設定
      fill = "gray", alpha = 0.3
      ) +
    geom_rect( #領域描画部分(1%以下)
      data = df_data_thresholds, #閾値の計算結果データを指定
      aes(xmin = -8, xmax = threshold_1, ymin = 0, ymax = 200), #xminやxmaxは、元データから適当に設定
      fill = "gray", alpha = 0.3
      ) +
    facet_grid(~ factor(Variable)) + #x,y,zのデータを別々のパネルに
    theme_classic() + #自分好みの設定
    theme( #自分好みの設定
      strip.background = element_rect(linewidth = 0.5),
      strip.placement = "outside",
      panel.spacing = unit(1, "lines"),
      legend.position = "none"
    )

x軸やy軸のラベルはlabs()で適宜変更すればOK。

これで以下のようなグラフが出力されます。

gplot2でfacet_grid()を用いたヒストグラムに、各パネルごとにsegmentとrectを追加したもの

以上で完成です。

参考情報