ggplot2 v3.6.0?では `theme()` で Geom の色も指定できるようになるっぽい

ちょっと前にでかめの機能追加がマージされたので、それの解説をします。と言っても、まだ機能が全部出揃ってるわけではないし(関連する主な pull request は 3 つあって、まだ 1 つ目がマージされただけ)、正式なリリースもいつになるか分からないので、プレビュー版みたいなものだと思って読んでください。

どういう変更なのか

上の pull request では、 theme()geom というパラメータが追加されました。 ここには、各 Geom のデフォルトの色やサイズ、線の種類などを指定する element_geom() を渡します。

なんのこっちゃ、って感じだと思うので、とりあえずコードを見てみましょう。こんな感じです。

library(ggplot2)

p <- ggplot(mpg, aes(displ, hwy)) +
  theme(geom = element_geom(ink = "purple"))

p + geom_point()

theme() で指定した色が、geom_point() の点に使われていることが分かると思います。

これまで、ここは theme() では設定できない部分でした。 「スタイルの設定が一発でキマるテーマを作るぞ!」と思っても、設定できるのはタイトルとか軸とか背景までで、肝心のデータ可視化部分のプロットは範囲外でした。 update_geom_defaults() でデフォルトを指定することはできますが、ggplot2 のちょっとわかりづらいポイントのひとつになっています。 こうしたペインポイントが完全に解消されるのはもうちょっと時間がかかるのですが、重要な一歩です。

theme() を使い込んでいる人以外にとってはちょっとマニアックな解説になってしまいますが、もうちょっと詳しく見ていきましょう。

element_geom() に指定できるもの

element_geom() の引数は以下のようになっています。

    • ink
    • paper
    • accent
    • linewidth
    • borderwidth
    • linetype
    • bordertype
    • pointsize
    • pointshape
  • フォント

    • family
    • fontsize

なんとなくわかると思いますが、ちょっとわかりづらそうなところを説明します。

基本的には ink がメインの色です。geom_point() の点とか、 geom_line() の線とか、だいたいこの色が使われると思っておけばいいです。

accent は、ggplot2 にはデフォルトの色が黒ではなくて青色の Geom がありますが、あれです。geom_smooth() の線の部分とか、geom_contour() とかです。

paper は、概念が難しいですが、背景の色です。 例えば geom_label() の枠の内側の部分とか、geom_boxplot()geom_violin() の塗りの部分は paper の色になります。

塗りというと、geom_bar()fill の部分とか?、と思うかもしれませんが、あそこは inkpaper が混ざった色になります。 こんな感じです。

g <- ggplot(mpg, aes(class)) +
  theme(geom = element_geom(ink = "blue", paper = "red"))

g + geom_bar()

なんで?、と思うかもしれませんが、paper は紙の色なので、ink = "blue", paper = "red" というのは、赤い紙の上に青いインクで描いている、というような状況です。 つまりこんな感じです。

基本的に、paper には背景の色と同じものを指定すると思っていればいいようです。 これはちょっと目にどぎつい例を選んでしまいましたが(すみません...)、例えばダークモードみたいなことをやろうとするときにこの paper のような概念があった方が便利なのでこうなっているようです。

だいたいわかると思いますが、linewidthlinetypegeom_line() など単体で線のもの用、 borderwidthbordertypegeom_bar()geom_polygon() などポリゴンの輪郭のもの用です。 輪郭があるタイプの point なんかにも border* の方が使われます。

フォント

歴史的経緯で ggplot2 の中で size の単位が theme() ではポイント、geom_text()geom_label() では mm になっていてややこしいんですが、この element_geom()fontsize はポイントになっています。なので、何も考えず element_text() と同じサイズを指定すると geom_text() でも同じサイズで文字列を描画することができます。

library(ggplot2)

set.seed(10)
d <- data.frame(Foo = runif(30), Bar = runif(30), label = rep(c("Foo", "Bar"), 15))
ggplot(d, aes(Foo, Bar, label = label)) +
  geom_text() +
  labs(title = "Foo") +
  theme(
    plot.title = element_text(size = 30),
    axis.title = element_text(size = 30),
    axis.text = element_text(size = 30),
    geom = element_geom(fontsize = 30)
  )

気になるところ

これがどのように実現されているのかというと、from_theme() という特殊な関数をそれぞれの Geom の default_aes に指定することで成り立っています。

GeomPoint$default_aes
#> Aesthetic mapping: 
#> * `shape`  -> `from_theme(pointshape)`
#> * `colour` -> `from_theme(ink)`
#> * `size`   -> `from_theme(pointsize)`
#> * `fill`   -> NA
#> * `alpha`  -> NA
#> * `stroke` -> `from_theme(borderwidth)`

なので、直接 ggplot2 によって提供されている Geom については整合性が取れてるんですが、拡張パッケージが提供している Geom はおそらくその拡張パッケージがそれぞれこういった対応をする必要があります。アクティブに開発されているパッケージであればすぐに対応されるとは思いますが、リリース後しばらくは「あれ、テーマの色が反映されないんだけど?」みたいなことがあるかもしれません。

残りの pull request

関連する pull request はざっと見た感じあと2つあります。

既存の theme_*() にも inkpaper を指定できるようにする

これはシンプルなのですぐにマージされそうな感じがします。theme() で個別に指定しなくても theme_bw()theme_minimal() といったテーマ関数にも inkpaper を直接指定できるようにしよう、という変更です。

ちょっとベースの色を変えたいだけならこんな感じでシンプルに書けるようになるみたいです。便利そう。

library(ggplot2)

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  theme_bw(ink = "dodgerblue")

colourfill などの scale も theme から指定できるようにする

これはかなり待望の機能なんですが、でかい変更なのでちょっと時間がかかりそうです。 今は options(ggplot2.continuous.colour = ) とかでグローバルにしか設定できないものを、やはり theme() からも指定できるようにしよう、という試みです。

まとめ

まだ次のリリースがいつになるかはわかりませんが、いろいろ開発が進んでますよ、という紹介でした(最近はぜんぜんコントリビュートできてないですが...)。