6 min read

ggplot2の図をパネル状に並べる (cowplot, patchwork, egg, ggpubr)

ggplot2パネル表示のメモ

とくに論文書きでは関係する図をパネル状に並べて表示する機会が多い。 ggplot2のfacetファミリーでどうにかできる場合はいいが、そうでないとパネル分けでいつももたつく。 いくつかのパネル作成パッケージを比較して頭の中を整理する。

packages

現行でパネル作成可能なパッケージなうち、以下の4パッケージを試す。

そのほかにもまだいくつかあるが省略。

要件

上から順に優先度が高い。

  1. パネル間で軸位置を一致させられる
    • 縦に並んだ2つのパネルでy軸がずれているとがっかりするので
  2. insetが可能
    • 図の中に小さい図を書くことがままあるので
  3. パネルへのラベル付記
    • Fig. 1aと本文で触れるので
    • あれば少し便利くらい
  4. 凡例を共有できる
    • あれば少し便利くらい

各パッケージの仕様を比較する。

packages adjust_axes add_inset label_panels share_legend
base (ggplot2+gridExtra) - annotation_custom() - -
cowplot plot_grid(…, align = “hv”) draw_plot() plot_grid(…, labels), draw_plot_label() -
patchwork default - - -
egg default - ggarrange(…, labels) -
ggpubr ggarrange(…, align = “hv”) - ggarrange(…, labels) ggarrange(…, common.legend)

試用

下準備

結合するパネルをggplot2で作る。 散布図 + inset用2次元確率密度 + 周辺分布を準備。

set.seed(2018070001)
dt <- sample_n(diamonds, 200)
scat <-
  ggplot(dt, aes(carat, price, fill = cut)) +
  geom_point(shape = 21, col = "grey") +
  theme(legend.position = c(.1, .9), legend.justification = c(0, 1))

dens_carat <-
  ggplot(dt, aes(carat, fill = cut)) +
  geom_density(position = "identity", alpha = .5) +
  theme(axis.title.x = element_blank(), axis.ticks.x = element_blank(), axis.text.x = element_blank())

dens_price <-
  ggplot(dt, aes(price, fill = cut)) +
  geom_density(position = "identity", alpha = .5) +
  theme(axis.title.y = element_blank(), axis.ticks.y = element_blank(), axis.text.y = element_blank()) +
  coord_flip()

dens_2d <-
  ggplot(dt, aes(carat, price)) +
  geom_density2d(col = "black")

cowplot

  • Introduction to cowplot | vignette
  • 進化生物学系の研究室 (Wilke lab) が管理者
  • パッケージ読み込み時にtheme_cowplot()を強制
    • theme_classicをベースに背景を透過にしてあるため重ね書きに適している
  • 以下の利点があるため、図の保存にはggsaveの代わりにsave_plotを使うのがよいとある
    • cowplot用に調整済みのサイズ
    • 個別に作った図をplot_gridで並べて保存するときに適した仕様らしい
    • アスペクト比の調節が容易
packageVersion("cowplot")

cowplot::plot_grid(dens_carat + guides(fill = F), # (1, 1)
                   NULL,                          # (1, 2)
                   scat,                          # (2, 1)
                   dens_price + guides(fill = F), # (2, 2)
                   nrow = 2, align = "hv",
                   rel_widths = c(.8, .2), rel_heights = c(.2, .8),
                   labels = c("a", NA, "b", "c"), label_x = .1, label_y = .95) +
  cowplot::draw_plot(dens_2d + cowplot::theme_cowplot(), x = .45, y = .05, width = .3, height = .3)

## [1] '0.9.2'
  • 軸位置合わせ: plot_grid(..., align = c("h", "v", "hv"))
  • inset: draw_plot
  • label: デフォルトで左上
  • legend: 完全に事前設定

patchwork

  • The Composer of ggplots | README
  • gganimateなどのthomasp85氏が管理者
  • 二項演算子を多用してネストしたパネルわけが可能
  • レイアウトの変更が簡単でスピーディ
  • 現行で明らかにバグ (Plot assembly fails on minimal plots) がある
    • plot_layout(..., guides)がバグっているような気がする
library(patchwork)
packageVersion("patchwork")

  dens_carat + guides(fill = F) +
  patchwork::plot_spacer() +
  scat + ggplot2::annotation_custom(grob = ggplotGrob(dens_2d + theme_minimal()), xmin = 1.5, xmax = 2.5, ymin = 0, ymax = 8000) +
 dens_price + guides(fill = F) +
  plot_layout(ncol = 2, heights = c(.2, .8), widths = c(.8, .2))

## [1] '0.0.1'

挙動が怪しい。 凡例を消すと動く。

  dens_carat + guides(fill = F) +
  patchwork::plot_spacer() +
  scat + ggplot2::annotation_custom(grob = ggplotGrob(dens_2d + theme_minimal()), xmin = 1.5, xmax = 2.5, ymin = 0, ymax = 8000) + guides(fill = F) + # legendを消すと動く, legend.position = "right"なんかでも動く
 dens_price + guides(fill = F) +
  plot_layout(ncol = 2, heights = c(.2, .8), widths = c(.8, .2))

  • 軸位置合わせ: デフォルトで揃っている
  • inset: なし (ggplo2::annotation_customで処理)
    • ggplo2::annotation_customであとづけ不可?
  • label: なし
  • legend: 完全に事前設定
  • 備考: バグ多し

egg

  • (fragile) extensions for ggplot2 | README
  • gridExtraのBaptiste氏が管理者
  • ggplotオブジェクトをプロット部と周辺部 (軸・タイトルなど) からなる3x3の要素に分割して並べる
scat_with_inset <- 
  scat +
  ggplot2::annotation_custom(grob = ggplotGrob(dens_2d + theme_minimal()),
                             xmin = 1.5, xmax = 2.5, ymin = 0, ymax = 8000)

egg::ggarrange(dens_carat + guides(fill = F), # (1, 1)
               ggplot() + theme_minimal(),    # (1, 2)
               scat_with_inset,               # (2, 1)
               dens_price + guides(fill = F), # (2, 2)
               nrow = 2,
               widths = c(.8, .2), heights = c(.2, .8),
               labels = c("a", "", "b", "c"),
               label.args = list(gp = grid::gpar(font = 1), 
                                 x = unit(1, "line"),
                                 hjust = 0))

  • 軸位置合わせ: デフォルトで揃っている
  • inset: なし
    • ggplo2::annotation_customであとづけ不可?
  • label: デフォルトで左上にボールドイタリック
  • legend: 完全に事前設定

ggpubr

  • ggpubr: ‘ggplot2’ Based Publication Ready Plots
  • バイオ系研究者のkassambara氏が管理者
  • publication readyな図を作るために、という謳い文句
  • 各種geomに対応したワンライナー (e.g. ggbarplot) がある
    • 独自のエコシステムを作り上げている感じ
packageVersion("ggpubr")

ggpubr::ggarrange(dens_carat, # (1, 1)
                  NULL,       # (1, 2)
                  scat,       # (2, 1)
                  dens_price, # (2, 2)
                  nrow = 2, ncol = 2, align = "hv",
                  widths = c(.8, .2), heights = c(.2, .8),
                  labels = c("a", NA, "b", "c"),
                  common.legend = TRUE) +
  ggplot2::annotation_custom(grob = ggplotGrob(dens_2d + theme_minimal()),
                             xmin = .45, xmax = .75, ymin = .05, ymax = .35)

## [1] '0.1.6'
  • 軸位置合わせ: ggarrange(..., align = c("h", "v", "hv"))
  • inset: なし (ggplo2::annotation_customで事後処理可能)
  • label: デフォルトで左上
  • legend: 共有あり
    • プロット領域外の上下左右に配置
  • 備考: nrowncolとも指定しないと動作しない

雑感

patchwork以外の使い勝手はさほど変わらない。 開発者的に主流になりそうなeggに乗っておいて、patchworkを様子見する。 labelの位置はどのパッケージでも微調整が必要そうなので、annotateでぱぱっと書いた方が楽かもしれない。

Session Info

devtools::session_info()
##  setting  value                       
##  version  R version 3.5.0 (2018-04-23)
##  system   x86_64, darwin15.6.0        
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  tz       Australia/Brisbane          
##  date     2018-07-21                  
## 
##  package     * version    date       source                              
##  assertthat    0.2.0      2017-04-11 CRAN (R 3.5.0)                      
##  backports     1.1.2      2017-12-13 CRAN (R 3.5.0)                      
##  base        * 3.5.0      2018-04-24 local                               
##  bindr         0.1.1      2018-03-13 CRAN (R 3.5.0)                      
##  bindrcpp      0.2.2      2018-03-29 CRAN (R 3.5.0)                      
##  blogdown      0.6        2018-04-18 CRAN (R 3.5.0)                      
##  bookdown      0.7        2018-02-18 CRAN (R 3.5.0)                      
##  broom       * 0.4.4.9000 2018-06-21 Github (tidyverse/broom@2721de4)    
##  cellranger    1.1.0      2016-07-27 CRAN (R 3.5.0)                      
##  cli           1.0.0      2017-11-05 CRAN (R 3.5.0)                      
##  colorspace    1.3-2      2016-12-14 CRAN (R 3.5.0)                      
##  compiler      3.5.0      2018-04-24 local                               
##  cowplot       0.9.2      2017-12-17 CRAN (R 3.5.0)                      
##  crayon        1.3.4      2017-09-16 CRAN (R 3.5.0)                      
##  datasets    * 3.5.0      2018-04-24 local                               
##  devtools    * 1.13.5     2018-02-18 CRAN (R 3.5.0)                      
##  digest        0.6.15     2018-01-28 CRAN (R 3.5.0)                      
##  dplyr       * 0.7.5      2018-05-19 CRAN (R 3.5.0)                      
##  egg           0.4.0      2018-06-17 CRAN (R 3.5.0)                      
##  evaluate      0.10.1     2017-06-24 CRAN (R 3.5.0)                      
##  forcats     * 0.3.0      2018-02-19 CRAN (R 3.5.0)                      
##  ggplot2     * 3.0.0.9000 2018-07-16 Github (hadley/ggplot2@79e8b45)     
##  ggpubr        0.1.6      2017-11-14 CRAN (R 3.5.0)                      
##  glue          1.2.0      2017-10-29 CRAN (R 3.5.0)                      
##  graphics    * 3.5.0      2018-04-24 local                               
##  grDevices   * 3.5.0      2018-04-24 local                               
##  grid          3.5.0      2018-04-24 local                               
##  gridExtra     2.3        2017-09-09 CRAN (R 3.5.0)                      
##  gtable        0.2.0      2016-02-26 CRAN (R 3.5.0)                      
##  haven         1.1.1      2018-01-18 CRAN (R 3.5.0)                      
##  highr         0.6        2016-05-09 CRAN (R 3.5.0)                      
##  hms           0.4.2      2018-03-10 CRAN (R 3.5.0)                      
##  htmltools     0.3.6      2017-04-28 CRAN (R 3.5.0)                      
##  httr          1.3.1      2017-08-20 CRAN (R 3.5.0)                      
##  jsonlite      1.5        2017-06-01 CRAN (R 3.5.0)                      
##  knitr       * 1.20       2018-02-20 CRAN (R 3.5.0)                      
##  labeling      0.3        2014-08-23 CRAN (R 3.5.0)                      
##  lattice       0.20-35    2017-03-25 CRAN (R 3.5.0)                      
##  lazyeval      0.2.1      2017-10-29 CRAN (R 3.5.0)                      
##  lubridate   * 1.7.4      2018-04-11 CRAN (R 3.5.0)                      
##  magrittr    * 1.5        2014-11-22 CRAN (R 3.5.0)                      
##  MASS        * 7.3-49     2018-02-23 CRAN (R 3.5.0)                      
##  memoise       1.1.0      2017-04-21 CRAN (R 3.5.0)                      
##  methods     * 3.5.0      2018-04-24 local                               
##  modelr        0.1.2      2018-05-11 cran (@0.1.2)                       
##  munsell       0.4.3      2016-02-13 CRAN (R 3.5.0)                      
##  nlme          3.1-137    2018-04-07 CRAN (R 3.5.0)                      
##  patchwork   * 0.0.1      2018-07-16 Github (thomasp85/patchwork@7fb35b1)
##  pillar        1.2.3      2018-05-25 cran (@1.2.3)                       
##  pkgconfig     2.0.1      2017-03-21 CRAN (R 3.5.0)                      
##  plyr          1.8.4      2016-06-08 CRAN (R 3.5.0)                      
##  purrr       * 0.2.5      2018-05-29 CRAN (R 3.5.0)                      
##  R6            2.2.2      2017-06-17 CRAN (R 3.5.0)                      
##  Rcpp          0.12.17    2018-05-18 cran (@0.12.17)                     
##  readr       * 1.1.1      2017-05-16 CRAN (R 3.5.0)                      
##  readxl        1.1.0      2018-04-20 CRAN (R 3.5.0)                      
##  reshape2      1.4.3      2017-12-11 CRAN (R 3.5.0)                      
##  rlang         0.2.1      2018-05-30 cran (@0.2.1)                       
##  rmarkdown     1.10       2018-06-11 cran (@1.10)                        
##  rprojroot     1.3-2      2018-01-03 CRAN (R 3.5.0)                      
##  rstudioapi    0.7        2017-09-07 CRAN (R 3.5.0)                      
##  rvest         0.3.2      2016-06-17 CRAN (R 3.5.0)                      
##  scales        0.5.0      2017-08-24 CRAN (R 3.5.0)                      
##  stats       * 3.5.0      2018-04-24 local                               
##  stringi       1.2.3      2018-06-12 cran (@1.2.3)                       
##  stringr     * 1.3.1      2018-05-10 cran (@1.3.1)                       
##  tibble      * 1.4.2      2018-01-22 CRAN (R 3.5.0)                      
##  tidyr       * 0.8.1      2018-05-18 cran (@0.8.1)                       
##  tidyselect    0.2.4      2018-02-26 CRAN (R 3.5.0)                      
##  tidyverse   * 1.2.1      2017-11-14 CRAN (R 3.5.0)                      
##  tools         3.5.0      2018-04-24 local                               
##  utils       * 3.5.0      2018-04-24 local                               
##  viridisLite   0.3.0      2018-02-01 CRAN (R 3.5.0)                      
##  withr         2.1.2      2018-03-15 CRAN (R 3.5.0)                      
##  xfun          0.1        2018-01-22 CRAN (R 3.5.0)                      
##  xml2          1.2.0      2018-01-24 CRAN (R 3.5.0)                      
##  yaml          2.1.19     2018-05-01 cran (@2.1.19)