21
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RAdvent Calendar 2021

Day 5

【ggplot2】themeの使い方まとめ2021:作ったグラフの見た目をきれいにコントロールするために

Last updated at Posted at 2021-12-04

ggplot2でグラフを作っているときに困ること

ggplot2を用いてR上で作図を行っていると

  • なんかデフォルトだとx軸とy軸見えないから書き込みたいな
  • 背景を灰色じゃなくて白にしたい!
  • x軸のタイトルを消して、x軸のラベルをななめ書きにしたいな…

などのグラフの見た目に関わる変更を行いたいときがあると思います。
しかし、このような変更をどのようなコードで実行すればよいのかわからず困るかもしれません。
そんな時には…

themeで軸の書き込み!

.R
# Before
ggplot(iris, aes(x = Sepal.Length, Sepal.Width, color = Species)) + geom_point()
# After
ggplot(iris, aes(x = Sepal.Length, Sepal.Width, color = Species)) + geom_point() + 
    theme(axis.line = element_line(color = "black"))
Before After
test.png test1.png

themeで背景の変更!

.R
# Before
ggplot(iris, aes(x = Sepal.Length, Sepal.Width, color = Species)) + geom_point()
# After
ggplot(iris, aes(x = Sepal.Length, Sepal.Width, color = Species)) + geom_point() + 
    theme(panel.background = element_blank())
Before After
test.png test2.png

themeでx軸の編集!

.R
# Before
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) + geom_boxplot()
# After
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) + geom_boxplot() + 
    theme(
        axis.title = element_blank(), 
        axis.text.x = element_text(size = 15, angle = -30, vjust = 0.5, hjust = 0)
     )
Before After
test3a.png test3b.png

こんなふうにtheme関数を用いると、希望通りに見た目をいい感じにコントロールできます。

ggplot2におけるthemeとは何か

ggplot2を用いる場合に限らず、Rで作図を行っていると、ラベルや軸の表現の仕方などの調整を行いたくなる場合があります。
ggplot2でこのような変更を行いたい際に出てくるのがtheme関数です。この関数を用いて設定を行うことでレイアウトを調整することができます。

ではtheme関数とは何なのでしょうか?公式のレファレンスにはこのように書いてありました。

Themes are a powerful way to customize the non-data components of your plots: i.e. titles, labels, fonts, background, gridlines, and legends.

テーマとは、あなたのプロットのデータではない構成要素(例えば、タイトル、ラベル、フォント、背景、罫線、凡例)をカスタマイズするための強力な手段である(拙訳)

from https://ggplot2.tidyverse.org/reference/theme.html

そう、つまりthemeとはggplotにおいてgeom_関数などでは操作できない見た目の部分をコントロールするための関数なのです。
しかし、レファレンスなどを見ても設定できる項目が膨大で、使いこなすのは大変そうに見えます。けれど冒頭に示した通り、少しでも使いこなせたら絶対に便利!
そこでここでは自分の勉強もかねて、themeの使い方をまとめてみようと思います。

以下のページなどを参考にしました。

※ 以下のコードを実行するにはggplot2パッケージが必要です(library(ggplot2)で読み込んでください)
※ プロットの際に警告が出ますが、見た目の確認には問題ありません

themeを使うにあたって知っておいたら良さそうな3項目!

themeを扱う際にこれだけ抑えておければいいかな、と思ったポイントが以下の3つです。

1. 引数名は住所みたいになっているので、コントロールしたい部分に対応する引数名を選べばよい
2. 構成要素のコントロールは基本的にelement_関数で行う
3. 作成したテーマは保存して使いまわせる

ここではこの3項目に沿って、例を交えながらthemeの使い方を見ていきます。

1. 引数名は住所みたいになっているので、コントロールしたい部分に対応する引数名を選べばよい

themeのレファレンスを見ていただければわかるのですが、themeがとる引数の名前は単語が「.」をはさんで連続する形になっています。
例えば、短いとtext、長くなるとaxis.text.xのようになります。
これの仕組みは簡単で、***「コントロールしたい構成要素に対応してそうな引数名を選んで設定を指定すれば、そのように見た目が変更される」***だけです。
たとえば以下の図

.R
g1 <- ggplot(msleep, aes(x = sleep_total, y = sleep_rem, color = vore)) + geom_point()
plot(g1)

g1.png
text(グラフ上のすべてのテキスト)を(後述する方法で)描画しないように設定してみると…

.R
g2 <- g1 + theme(text = element_blank())
plot(g2)

g1.blanktext.png
ことごとくすべての文字が消えます。
一方で、axis.text.x(x軸上の文字)を描画しないように設定してみると…

.R
g3 <- g1 + theme(axis.text.x = element_blank())
plot(g3)

g1.blankaxistextx.png

このようにx軸の目盛の数値だけが消えます。

もう一例見てみると、例えばpanel.grid(描画領域内のグリッド線)とpanel.grid.minor.x(x軸に垂直な小目盛りのグリッド線)の場合…
panel.gridをコントロールすると…

.R
g4 <- g1 + theme(panel.grid = element_line(color = "red", size = 2))
plot(g4)

g1.red.panel.grid.png

panel.grid.minor.xをコントロールすると…

.R
g5 <- g1 + theme(panel.grid.minor.x = element_line(color = "red", size = 2))
plot(g5)

g1.red.panel.grid.minor.x.png

のようになります。
厳密に引数に階層性がある訳ではないのですが、基本的に上位の構成要素について設定を行うと下位の構成要素はそれに従います。よって、***「大まかに指定したいときには大まかな引数を、細かく指定したいときには細かい引数を」***でいい感じに調整できると思います。

対応する引数名はどうやって探すか?

個人的にはtheme関数のレファレンスのなかから探すのがよいと思います。

ブラウザ上でCtrl+Fを使って関連がありそうな言葉から探すのもありですし、「axis」や「legend」などの言葉をもとに探してみるのもありです。
そこまでわかりにくい名づけにはなっていないので、すぐに目当ての引数を見つけられると思います。

axis.args_2.png

引数名の一例 from https://ggplot2.tidyverse.org/reference/theme.html

2. 構成要素のコントロールは基本的にelement_*関数で行う

theme関数の場合、引数に渡すのは基本的にelement_*関数というものであり、これで該当箇所のレイアウトをコントロールすることになります。
element_*関数には、element_blankelement_rectelement_lineelement_textの4つがあります。

element_blank:「何もない」を指定(=消す)

グラフ上の何かの構成要素を消したい場合にはelement_blankを使います。

たとえば、軸上の目盛りの目印(axis.ticks)と凡例のタイトル(legend.title)と描画領域の背景(panel.background)を消したい場合は以下のようになります。

.R
g6 <- g1 + theme(
              axis.ticks = element_blank(), 
              legend.title = element_blank(), 
              panel.background = element_blank()
            )
plot(g6)

g1.blank.ticks.legend.title.panel.background.png

とりあえず消したいときにはelement_blankです。
ちなみにpanel.backgroundや後述するplot.backgroundに対してelement_blanck()を指定してベクタに出力すると、これらの領域を透過背景にすることができるようです。逆に言うと確実に白色背景にしたい場合にはelement_blankは適さないかもしれません。

element_rect:境界と背景のコントロール

境界や背景(ようするに四角いもの)をコントロールしたい際にはelement_rectを使います。
たとえば、描画領域の背景(panel.background)や凡例の点の背景(legend.key)をコントロールしたい場合には

.R
g7 <- g1 + theme(
               panel.background = element_rect(fill = "#e9e4d4", color = "black", linetype = 4, size = 2), 
               legend.key = element_rect(fill = "#e9e4d4", color = "black")
            )
plot(g7)

g1.rect.panel.background.legend.key.png
のようになります。
※ ただし、panel.backgroundpanel.borderの設定には少し注意が必要なようです(詳しくは前掲したこちらのページを参照してください)

element_line:線のコントロール

線全般のコントロールはelement_lineで行います。
たとえば、x、y軸の線(axis.line)や軸上の目盛りの目印(axis.ticks)、描画領域内のグリッド線(panel.grid.major)、描画領域内の小グリッド線(panel.grid.minor)をコントロールしたい場合には以下のようになります。

.R
g8 <- g1 + theme(
               axis.line = element_line(arrow = arrow()), 
               axis.ticks = element_line(color = "red", size = 2), 
               panel.grid.major = element_line(color = "pink"), panel.grid.minor = element_blank()
            )
plot(g8)

g1.line.axis.line.axis.ticks.panel.grid.major.panel.grid.minor.png

element_text:テキストのコントロール

テキスト全般のコントロールはelement_textで行います。もちろん、文字の回転、フォント指定などもできます。
たとえば、x軸タイトル(axis.title.x)、y軸タイトル(axis.title.y)、y軸上のテキスト(axis.text.y)をコントロールしたい場合には以下のようになります。

.R
g9 <- g1 + theme(
               axis.title.x = element_text(family = "serif", face = "bold", size = 20), 
               axis.title.y = element_text(family = "serif", face = "bold", size = 20, angle = -90), 
               axis.text.y = element_text(angle = -90, size = 15, hjust = 0.5)
            )
plot(g9)

g1.text.axis.title.axis.text.y.png

その他のelement_*関数の詳しい使い方についてはレファレンスにのっています。

3.作成したテーマは保存して使いまわせる

上記のように、themeを用いればプロットの見た目を様々に変えることができます。
さらに、自分が作成したテーマはオブジェクトに保存することで何回でも使いまわすことができます。
たとえば以下のようにテーマを作成して

.R
# テーマの保存
theme_new <- theme(      
                 # 背景を消す
                 panel.background = element_rect(fill = "white", color = "black"),
                 # 凡例の設定
                 legend.position	= c(0.15, 0.85), 
                 legend.title = element_blank(), 
                 legend.text = element_text(size = 15),
                 legend.key = element_blank(), 
                 # テキスト形式の設定
                 axis.title.x = element_text(family = "serif", face = "bold", size = 20), 
                 axis.title.y = element_text(family = "serif", face = "bold", size = 20, angle = -90), 
                 axis.text.x = element_text(angle =   0, size = 15, hjust = 0.5), 
                 axis.text.y = element_text(angle = -90, size = 15, hjust = 0.5)
              )

あるプロットで呼び出すと

.R
h1 <- ggplot(msleep, aes(x = sleep_total, y = sleep_rem, color = vore)) + 
    geom_point(size = 2) + theme_new
plot(h1)

g2.png

別のプロットで呼び出すと

.R
h2 <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + 
    geom_point(size = 2) + theme_new
plot(h2)

g3.png

このように、別々のプロットでも同様の見た目に調整することができます。

その他のTips

上記の3項目でおおまかには使い方をカバーできると思うのですが、以下を使うとさらに見た目をコントロールすることができます。

凡例のコントロール

先ほどのtheme_newですでに使ってしまっているのですが、凡例は位置などをthemeでコントロールすることができます。
※ ただし、色分けなどについては後述するscale系の関数で行う必要あり

.R
g1 + theme(
         legend.direction = "horizontal",
         legend.position = c(0.35, 0.95), 
         legend.background = element_blank(), 
         legend.title = element_text(size = 15)
      )

g1.legend.png

追記:凡例を消す場合
凡例を消したい場合、特にすべての凡例を消したい場合には、legend.position"none"を指定することで凡例を消すことができます。
ただし一部の凡例のみを消したい場合には、guides関数や対応するscale_*関数で特定の凡例を指定して消す必要があります。

.R
# そのまま
ggplot(msleep, aes(x = sleep_total, y = sleep_rem, color = vore, shape = conservation)) + 
    geom_point()

# すべての凡例を消す
ggplot(msleep, aes(x = sleep_total, y = sleep_rem, color = vore, shape = conservation)) + 
  geom_point() + theme(legend.position = "none")

# 一部の凡例を消すやり方①
ggplot(msleep, aes(x = sleep_total, y = sleep_rem, color = vore, shape = conservation)) + 
  geom_point() + guides(color = "none") # `shape = "none"にすればshapeの凡例が消える

# 一部の凡例を消す やり方②
ggplot(msleep, aes(x = sleep_total, y = sleep_rem, color = vore, shape = conservation)) + 
  geom_point() + scale_shape_discrete(guide = "none") # scale_color_discrete(guide = "none")にすればcolorの凡例が消える
そのまま すべて消す やり方① やり方②
i0.png i1.png i2.png i3.png

参考

長さのコントロール

unit関数を使用することで、長さ、大きさを一部の引数に対して直接指定することができます。
※ unitについては勉強中のため、ここでは見た目がいい感じになるように単位をcmにして適宜設定しています(実際に使う際にもそれが手っ取り早いかも?)

.R
ggplot(msleep, aes(x = sleep_total, y = sleep_rem, color = vore, shape = conservation)) + 
      geom_point(size = 3) + 
    theme(axis.ticks.length = unit(0.5, "cm"), legend.key.width = unit(3.5, "cm"))

gc.png

ビルトインテーマ

またggplot2には、すでにいい感じにパラメータの設定がなされた、ビルトインのテーマが複数あります(ggplotのthemeの話ではむしろこっちの方がよく出てくるかもしれません)。
簡便に見た目を変更したい場合などにこれらは非常に有用です。

theme_grey() theme_bw() theme_linedraw() theme_light()
g1_gray.png g1_bw.png g1_linedraw.png g1_light.png
theme_dark() theme_minimal() theme_classic() theme_void()
g1_dark.png g1_minimal.png g1_classic.png g1_void.png
詳しくはこちらなどから

注意点

このようにtheme関数は見た目のコントロールを行うのに非常に強力なツールなのですが、以下のような注意点もあります。

###「データが関わる部分」はコントロールできない
少しわかりにくい表現なのですが、theme関数では「データが関わる部分」をコントロールできません。つまり紙の上の点を移動させるようなレイアウト操作ができません。
これらの「紙の上ではどこにどのようにデータが描画されるか」という部分については、geom_*関数やScale関連の関数でコントロールする必要があります。
たとえばプロットする範囲を動かしたい場合はxlimylimを使う、対数軸にしたい場合はscale_*_log10()を使う、目盛りの区切り数を変えたい場合はscale_:_continuousを使う、などのようにtheme関数の適用前に調整を行う必要があります。

.R
theme_tmp <- theme_new + 
    theme(
        panel.grid.major.x = element_line(color = "black"), 
        panel.grid.minor.x = element_line(color = "grey")
     )

# Scaleの設定なし
g1.no_scale <- g1 + theme_tmp
plot(g1.no_scale)
# Scaleの設定あり
g1.with_scale <- g1 + scale_x_continuous(breaks = seq(0, 20, 2), minor_breaks = seq(0, 20, 1)) + theme_tmp
plot(g1.with_scale)
Scaleの設定なし Scaleの設定あり
g1.nobreaks.png g1.withbreakss.png

余白の設定は結構難しいかも

themeをいじくるとわかってくるのですが、ggplotのプロット領域は実際にデータが描画される「panel領域(下図青色)」とその周囲も含む領域である「plot領域(下図青色+赤色)」に分かれています。

.R
g1 + theme(
         panel.background = element_rect(fill = "#2a83a2"), 
         plot.background = element_rect(fill = "#e95464")
     )

g1.area.png
よって、panel.*の引数はpanel領域を、plot.*の引数は(おそらくレイヤ的には下になるため)その外側をコントロールするものということになります。
つまりこの領域の設定をいじればプロットの余白を変えられるのですが、margin関数の引数を微調整しながら変更していく必要があるため「panel領域だけ切り抜く」というのをコード上で行おうとすると結構難しいかもしれません。

たとえば以下のように設定して、自分の環境で出力すると下図のようになります。

.R
g1.margin <- g1 + theme(
                      panel.background = element_rect(fill = "#2a83a2"), 
                      plot.background = element_rect(fill = "#e95464"), 
                      plot.margin = margin(1, -3, 0, -1, "cm")
                   )
ggsave(g1.margin, file = "g1.margin.png", width = 7, height = 7)

g1.margin.png
もしかしたら画像編集ソフトとかで切り出した方が楽かも?

余白コントロールの参考

まとめ:themeの使い方が分かればきっと便利!

このように、theme関数は非常に便利な関数です。
このような機能もあるため、ggplotではRのデフォルトのplotに比べて見た目の変更が格段に行いやすいと思います。
自分もまだ不慣れで、つたない説明だったと思いますが、グラフ作成の際のお役に立てたら幸いです!
(年末にグラフをたくさん描くみなさまがんばってください!)

21
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?