Menu

R の ggplot2: グラフィックスの文法 入門ガイド

ggplot2 の仕組み — data + aes() + geom という心的モデル、マッピングと設定の違い、labs()、facet_wrap()、テーマ、そして ggsave() による保存。

ggplot2 はレイヤーからグラフを組み立てる

ggplot2 は R で最も広く使われている作図パッケージであり、人々がこれを支持する理由は設計思想にあります。グラフィックスの文法 です。base R はグラフごとに 1 つの関数 — plot()hist()barplot() — を与え、それぞれに固有の引数があります。それに対して ggplot2 は、組み合わせ可能な少数の部品 — データセット、列から視覚的属性へのマッピング、描画レイヤー — を与え、それらを + で結合してあらゆるグラフを作ります。文法を一度覚えれば、新しいグラフの種類はどれも、1 語だけ変わった同じ文になります。おまけとして、既定の見た目(灰色のパネル、妥当な軸、自動的な凡例)は装飾の努力なしでも見せられる水準です。

追加パッケージなので、1 度のインストールとセッションごとの読み込みが必要です。

install.packages("ggplot2")   # once, on your machine
library(ggplot2)              # at the top of every script that uses it

最初に知っておくべき前提がひとつあります。ggplot2 は(ばらばらのベクトルではなく)データフレーム を求め、理想的には整然とした縦長の形式 — 観測値ごとに 1 行、変数ごとに 1 列 — を求めます。データが横長なら、先に縦長に変換すれば、作図の問題に見えていたものはたいてい解消します。

心的モデル: データ、マッピング、ジオメトリ

すべての ggplot は、部品ごとに 1 つずつ、3 つの問いに答えます。

  1. データ — どのデータフレームか? ggplot(mtcars, ...)
  2. マッピング — どの列がどの視覚的属性を動かすか? aes(x = wt, y = hp)
  3. ジオメトリ — 観測値をどう描くか? + geom_point()

構造をトークンごとに見ていきましょう。

ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point()
  • ggplot(mtcars, ...) は既定のデータが mtcars であるグラフを開始します。これだけでは空の灰色パネルが描かれます。まだレイヤーがないからです。
  • aes(x = wt, y = hp)審美的マッピング です。横方向の位置は wt 列から、縦方向の位置は hp から決まります。mtcars$wt ではなく裸の列名を書く点に注意してください。マッピングは指定したデータの内側で評価されます。
  • + geom_point() は各行を点として描くレイヤーを追加します。この + は本当にレイヤーの加算です。グラフは積み上げて作るオブジェクトであり、別の geom、ラベル、テーマなどを + で追加し続けられます。

実行すると、散布図のガイドの base R 版と同じ重量対馬力の散布図が、白いグリッド線の入った灰色パネルの上に描かれます。geom_point()geom_line() に替えれば、同じマッピングが折れ線グラフになります。これが文法の働きです。

実際によく使う geom

十数個の geom で日々の作業のほぼすべてがまかなえます。

geom_point()       # scatter plot: two numeric variables
geom_line()        # line chart: trends over an ordered variable
geom_col()         # bar chart from pre-computed heights (needs y)
geom_bar()         # bar chart that counts raw rows for you (no y)
geom_histogram()   # distribution of one numeric variable (set binwidth)
geom_boxplot()     # distributions compared across groups
geom_smooth()      # fitted trend line; method = "lm" for straight

レイヤーは積み重なり、そこが ggplot2 が表現力で base R を上回り始めるところです。geom_point() + geom_smooth(method = "lm") は、散布図に回帰直線 信頼帯を加えたものを、読みやすい 1 行で表します。グラフはオブジェクトなので、土台を保存して分岐させることもできます。

p <- ggplot(mtcars, aes(x = wt, y = hp)) + geom_point()

p + geom_smooth(method = "lm")   # one variant
p + geom_smooth()                # another (loess curve)

マッピングと設定: 定番の aes() の混乱

ggplot2 の初学者が必ず、たいていは 1 週目にやる間違いが、リテラルな色を aes()内側 に置くことです。ルールは短く — aes() の内側は「データに応じて変化する」、外側は「固定の設定」 — この 2 つの配置はまったく別のことをします。

# MAPPING: color varies by a column - each cylinder count gets its own
# color, and a legend appears automatically
ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
    geom_point(size = 2)

# SETTING: every point is literally steelblue - no legend, no mapping
ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point(color = "steelblue", size = 2)

そして落とし穴そのものがこちらです。

# WRONG: "blue" inside aes() is treated as data, not as a color
ggplot(mtcars, aes(x = wt, y = hp, color = "blue")) +
    geom_point()

これは サーモンピンク の点を描き、"blue" とラベルの付いた単一項目の凡例を付けます。理由はこうです。aes() は列を属性に対応づけるので、color = "blue" はすべての値が "blue" という語である架空の 1 カテゴリの列を作り出し、ggplot はそのカテゴリに既定の第 1 色 — たまたま赤みがかったサーモン色 — を割り当てます。「点を青くしたい」のであれば、色はマッピングの外側に置きます: geom_point(color = "blue")。同じルールが sizeshapefillalpha にも当てはまります。(マッピングの例にある factor(cyl) にも注目してください。cyl は数値なので、factor() で包むことで、連続的な色のグラデーションではなくグループごとに異なる色を要求しています。)

ラベル、ファセット、テーマ

labs() は 1 か所ですべてに名前を付けます。そして、本物のラベルが付くまでグラフは完成していません。

ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
    geom_point(size = 2) +
    labs(title = "Horsepower vs. weight",
         x     = "Weight (1000 lbs)",
         y     = "Horsepower",
         color = "Cylinders")

ファセット は ggplot2 の目玉機能です。1 つのグラフをスモールマルチプルに分割し、グループごとに 1 パネルを作ります。軸が共有されるので、パネル同士を公正に比較できます。

ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point() +
    facet_wrap(~ cyl)

4、6、8 シリンダーの車に 1 つずつ、計 3 つのパネルがグリッド状に配置され、各パネルの上にグループの値がキャプションとして付きます。base R ではこれは par(mfrow) の曲芸と手作業での軸範囲の共有が必要ですが、ここでは 1 行です。ファセットは整然としたデータで真価を発揮します。だからこそ ggplot2 は dplyr のパイプラインと自然に組み合わさります。フィルタして集約し、その結果をそのまま ggplot() にパイプで渡せます。

テーマ は 1 回の呼び出しでデータ以外のインクの見た目を変えます。+ theme_minimal()(すっきりした白背景)、+ theme_bw()+ theme_classic()(軸のみ、グリッドなし)、あるいは既定の灰色です。プロジェクトごとに 1 つ選び、一貫させましょう。すべての図がテーマを共有するレポートは、スクラップブックではなくひとつの文書として読めます。

ggsave() で保存する — そして base R で十分な場面

ggsave() は最後に作ったグラフをディスクに書き出し、形式はファイル拡張子から推測します。

ggsave("hp-vs-weight.png", width = 8, height = 5)          # last plot shown
ggsave("hp-vs-weight.pdf", plot = p, width = 8, height = 5) # a saved object

widthheight の既定単位はインチです。明示的に指定しましょう。フォントサイズは出力寸法に応じてスケールされ、既定値が図の届け先に合っていることはめったにないからです。

どちらを使うべきかについては、分析中に 1 変数を 5 秒眺めるだけなら、base R の plot() とその仲間の方が入力量が少なく依存関係もゼロです。どこでも ggplot2 を使ったからといって賞がもらえるわけではありません。ggplot2 が価値を発揮するのは、図にグループ、凡例、ファセット、あるいは読み手が関わる瞬間です。文法は、base の作図が努力してようやく扱える複雑さにまでスケールします。

この章のまとめ

  • ggplot2 はすべてのグラフを、データ + aes() のマッピング + geom レイヤーを + でつないで組み立てます。文法を一度覚えれば、あらゆるグラフの種類に再利用できます。
  • aes() は列を視覚的属性に対応づけます。裸の列名を書き、データフレームの内側で評価されます。
  • aes() の内側 = データに応じて変化する(凡例が付く)、外側 = 固定の設定。aes(color = "blue") が定番のバグです。
  • タイトルには labs()、スモールマルチプルには facet_wrap(~ group)、装飾には theme_minimal() とその仲間、書き出しには寸法を明示した ggsave() を使います。
  • 単独の変数をさっと見るなら base R。グループ、ファセット、読み手が関わるなら ggplot2。

これで作図の章は終わりです。ここからの自然な次の一歩は記述統計 — これらのグラフが明らかにした形に数値を与えることです。

よくある質問

R の ggplot2 とは何ですか?

ggplot2 は R で最も人気のある作図パッケージです。グラフの種類ごとに関数が用意されているのではなく、すべてのグラフを同じ 3 つの部品 — データフレーム、列を視覚的属性に対応づける aes() マッピング、1 つ以上の geom_*() レイヤー — を + でつないで組み立てます。tidyverse の一部です。

ggplot2 はどうやってインストールしますか?

install.packages("ggplot2") を 1 度実行し、使用するスクリプトの先頭で毎回 library(ggplot2) を書きます。インストールはパッケージをマシンに置く操作で、library() は現在のセッションに読み込む操作です。

ggplot2 の aes() は何をしますか?

aes() はデータの列を視覚的属性に対応づけます。aes(x = wt, y = hp, color = factor(cyl)) は、横方向の位置は wt から、縦方向の位置は hp から、点の色はシリンダー数から決まる、という意味です。aes() の内側にあるものはデータに応じて変化し、外側にあるものは固定の設定です。

ggplot の点が指定した色にならないのはなぜですか?

色を aes() の内側に置いているからです。aes(color = "blue") は色を設定するのではなく、"blue" という架空のカテゴリをマッピングするので、ggplot は自分の既定色を選び、凡例を追加します。リテラルな色を設定するには、マッピングの外側に置きます: geom_point(color = "blue")

Coddy programming languages illustration

Coddyでコードを学ぼう

始める