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

# 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/082c821a-072a-ca13-d96a-50dbb3f5ea44.png)  | ![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/ec70f0ac-6da0-01cf-e089-60988178d041.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/082c821a-072a-ca13-d96a-50dbb3f5ea44.png)  | ![test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/2fee5fef-8b15-9557-e77a-88ec345e02c7.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/cf09c8ab-c832-6ca1-da52-ebf2779cf155.png) |  ![test3b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9a6ab68e-befd-01f2-d3f2-7c39c1e49a26.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`の使い方をまとめてみようと思います。

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

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

https://ggplot2-book.org/polishing.html#polishing

※　以下のコードを実行するには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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/6d60bd85-6dbe-114c-844e-3bb87fb7eae1.png)
で`text`（グラフ上のすべてのテキスト）を（後述する方法で）描画しないように設定してみると…

```.R
g2 <- g1 + theme(text = element_blank())
plot(g2)
```
![g1.blanktext.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/60e33572-0f16-23ee-d42e-a024a4d7bb44.png)
ことごとくすべての文字が消えます。
一方で、`axis.text.x`（x軸上の文字）を描画しないように設定してみると…

```.R
g3 <- g1 + theme(axis.text.x = element_blank())
plot(g3)
```
![g1.blankaxistextx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/56d3c60c-1b6f-3698-296a-41aa23579918.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/f3def59b-4a83-581f-d81e-7027f4f6f23f.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/e4e292b9-4937-53af-30eb-b73f753e46cb.png)

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

#### 対応する引数名はどうやって探すか？
個人的には`theme`関数のレファレンスのなかから探すのがよいと思います。

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

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

![axis.args_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/4f4d6ad5-f8fe-bd76-720f-02f6b904f41e.png)
> 引数名の一例　from https://ggplot2.tidyverse.org/reference/theme.html

# 2. 構成要素のコントロールは基本的に`element_*`関数で行う
`theme`関数の場合、引数に渡すのは基本的に`element_*`関数というものであり、これで該当箇所のレイアウトをコントロールすることになります。
`element_*`関数には、`element_blank`、`element_rect`、`element_line`、`element_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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/d6bec44b-2236-e6b2-3067-0f2936348368.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/55107c98-968e-5c25-2cc2-e866dfc03abf.png)
のようになります。
※　ただし、`panel.background`と`panel.border`の設定には少し注意が必要なようです（詳しくは前掲した[こちらのページ](https://ggplot2-book.org/polishing.html#panel-elements)を参照してください）

### `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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/a99c9ab1-43f5-8d28-0fca-3e9c8bcd518f.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/beb9c51f-620e-5123-be34-d95d30ca69b2.png)

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

https://ggplot2.tidyverse.org/reference/element.html

# 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/53258671-ee9c-ad84-57b1-08abe7bd889c.png)

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

```.R
h2 <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + 
    geom_point(size = 2) + theme_new
plot(h2)
```
![g3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/5cc44521-6ce3-6d75-a99d-ffef00820772.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9b16a140-013b-2f83-fe0b-6e05c4db3650.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9310c115-9adf-5d63-598c-973fa6a9a606.png) |  ![i1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/8777813f-1ea6-02d8-ca4e-7421176924d8.png) | ![i2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/2fc2c608-fe64-ae7d-cb44-456883630269.png)  |  ![i3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9ef05075-3261-5743-afae-c27f932285f2.png) |

参考

https://qiita.com/xargs/items/0890318b4217627d3314

https://stackoverflow.com/questions/35618260/remove-legend-ggplot-2-2

https://ggplot2.tidyverse.org/reference/guides.html

### 長さのコントロール
`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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/7b5c4ed4-f625-d66f-b1e4-5ecadfd864b3.png)

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

| theme_grey()| theme_bw() | theme_linedraw() | theme_light() |
|:-:|:-:|:-:|:-:|
|  ![g1_gray.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/60cf595d-277d-cf7c-5ac8-9e3d9dc29300.png) |  ![g1_bw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/8e4c7ec5-8427-f6fb-c57b-4c3aec9e18d9.png) | ![g1_linedraw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/c0fc347a-e885-0036-dd29-8b267b17d9cb.png) | ![g1_light.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/5f8207d5-27e8-5160-480b-c9930c608ba2.png)  |

|  theme_dark() |  theme_minimal() |  theme_classic() | theme_void()|
|:-:|:-:|:-:|:-:|
|  ![g1_dark.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/3143b25e-7ab4-8357-32ef-fb7ac125699f.png) |  ![g1_minimal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/cb3e18cb-7eed-fa62-05ce-d536b8cae0ca.png) | ![g1_classic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/8fa9c794-59a8-eafe-6be7-faa312e34c29.png)  | ![g1_void.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/4d32d74f-0b17-9126-1434-85436fc5c6de.png)  |
詳しくはこちらなどから

https://ggplot2.tidyverse.org/reference/ggtheme.html

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

###「データが関わる部分」はコントロールできない
少しわかりにくい表現なのですが、`theme`関数では「データが関わる部分」をコントロールできません。つまり紙の上の点を移動させるようなレイアウト操作ができません。
これらの「紙の上ではどこにどのようにデータが描画されるか」という部分については、`geom_*`関数や[Scale関連の関数](https://ggplot2.tidyverse.org/reference/index.html#section-scales)でコントロールする必要があります。
たとえばプロットする範囲を動かしたい場合は`xlim`や`ylim`を使う、対数軸にしたい場合は`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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/2a02810b-ca3a-3247-17e6-7a215367d339.png) |  ![g1.withbreakss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/25e62f93-4840-de30-7164-fda9e3fac6e3.png) |

### 余白の設定は結構難しいかも
`theme`をいじくるとわかってくるのですが、ggplotのプロット領域は実際にデータが描画される「panel領域（下図青色）」とその周囲も含む領域である「plot領域（下図青色＋赤色）」に分かれています。

```.R
g1 + theme(
         panel.background = element_rect(fill = "#2a83a2"), 
         plot.background = element_rect(fill = "#e95464")
     )
```
![g1.area.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9daa5083-a7fa-6faa-e964-a3f59f4aa51f.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9f989b10-7d19-e139-37eb-54458f7526e5.png)
もしかしたら画像編集ソフトとかで切り出した方が楽かも？


#### 余白コントロールの参考

https://ggplot2.tidyverse.org/reference/element.html

https://qiita.com/yuifu/items/09996de51d4b9e85b28c

https://stackoverflow.com/questions/31254533/when-using-ggplot-in-r-how-do-i-remove-margins-surrounding-the-plot-area/31255629


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