ggplot2ベースの図から凡例 (legend) のみ得る方法あれこれ
タイトルに書いたように「凡例だけが描画したい」ことが時々あるかと思います(止むを得ずに凡例の位置が図から分断されてしまうときとか)。そんな時には、ここで紹介する方法を使うと良いです。やり方はいくつかあります。ここではgtableパッケージを使う場合の2例とlemonパッケージを使う方法の3通りを紹介します。
⚠️ ggplot2の図の描画に使われているgridシステムやこの記事で扱うgtableとの関係について知りたい人は、毎度おなじみ id:yutannihilation さんの下記の記事を読みましょう。
まずは凡例を含む図を作りましょう🎨
library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point(aes(color = factor(cyl), shape = factor(cyl))) + guides(color = guide_legend(title = "Number of cylinders"), shape = guide_legend(title = "Number of cylinders")) + theme(legend.position = "bottom") p
📈gtableパッケージを使う場合
最初の方法では、gtableパッケージを使います。このパッケージではggplot2ベースの図を構成する要素を表形式に整理したgtableオブジェクトに対して処理を適用することが可能です。
まず先ほどggplot2で作ったオブジェクトをggplotGrob()
に渡し、gtableオブジェクトを得ます。
p_gtable <- ggplotGrob(p) class(p_gtable)
## [1] "gtable" "gTree" "grob" "gDesc"
オブジェクトを表示してみると、グラフを構成する情報がつらつらと出力されます。ここでname列はggplot2の図のパーツというか、描画に使われている部位を指しており、マッピングが行われる部位だけでなく、背景やタイトルについて確認できます。
p_gtable
## TableGrob (14 x 9) "layout": 19 grobs
## z cells name grob
## 1 0 ( 1-14, 1- 9) background rect[plot.background..rect.3427]
## 2 5 ( 6- 6, 4- 4) spacer zeroGrob[NULL]
## 3 7 ( 7- 7, 4- 4) axis-l absoluteGrob[GRID.absoluteGrob.3388]
## 4 3 ( 8- 8, 4- 4) spacer zeroGrob[NULL]
## 5 6 ( 6- 6, 5- 5) axis-t zeroGrob[NULL]
## 6 1 ( 7- 7, 5- 5) panel gTree[panel-1.gTree.3374]
## 7 9 ( 8- 8, 5- 5) axis-b absoluteGrob[GRID.absoluteGrob.3381]
## 8 4 ( 6- 6, 6- 6) spacer zeroGrob[NULL]
## 9 8 ( 7- 7, 6- 6) axis-r zeroGrob[NULL]
## 10 2 ( 8- 8, 6- 6) spacer zeroGrob[NULL]
## 11 10 ( 5- 5, 5- 5) xlab-t zeroGrob[NULL]
## 12 11 ( 9- 9, 5- 5) xlab-b titleGrob[axis.title.x.bottom..titleGrob.3391]
## 13 12 ( 7- 7, 3- 3) ylab-l titleGrob[axis.title.y.left..titleGrob.3394]
## 14 13 ( 7- 7, 7- 7) ylab-r zeroGrob[NULL]
## 15 14 (11-11, 5- 5) guide-box gtable[guide-box]
## 16 15 ( 4- 4, 5- 5) subtitle zeroGrob[plot.subtitle..zeroGrob.3423]
## 17 16 ( 3- 3, 5- 5) title zeroGrob[plot.title..zeroGrob.3422]
## 18 17 (12-12, 5- 5) caption zeroGrob[plot.caption..zeroGrob.3425]
## 19 18 ( 2- 2, 2- 2) tag zeroGrob[plot.tag..zeroGrob.3424]
凡例部位も独立しており、次の処理により抽出可能です。
p_gtable[["grobs"]][[grep("guide-box", p_gtable$layout$name)]]
## TableGrob (5 x 5) "guide-box": 2 grobs
## z cells name
## 99_ba71de4077ba9ca80dafe2aa749ab62d 1 (3-3,3-3) guides
## 0 (2-4,2-4) legend.box.background
## grob
## 99_ba71de4077ba9ca80dafe2aa749ab62d gtable[layout]
## zeroGrob[NULL]
gtableにはこれらの部位を指定して抽出する関数が用意されていて、上記の処理は次のように書き換えられます。また、抽出したgtableオブジェクト(凡例のみ)は、gridパッケージの関数でグラフとして出力できます。
p_legend <- gtable::gtable_filter(p_gtable, pattern = "guide-box") grid::grid.draw(p_legend)
一方でファイルへの保存にはgtableの状態で行います。
ggsave("legend.png", p_legend)
📉lemonパッケージを使う場合🍋
いちいちggplotGrob()
にして、凡例のgrobを指定して〜、という手続きが煩わしい場合、lemonパッケージのg_legend()
でggplot2ベースの図から凡例部分を取り出すことができます。私はこっちの方法が好みです。
p_legend <- lemon::g_legend(p)
このパッケージを使った場合も描画と保存の処理はgtableの時と同じです。
grid::grid.newpage() # 先ほど描画したオブジェクトを消します grid::grid.draw(p_legend)
あとは煮るなり焼くなりお好みでどうぞ。 Enjoy!