ggplot2 を用いたパブリッシュ出来る品質のグラフィックスの作成

概要

講義: 60 分
演習: 20 分
質問
  • R でパブリッシュ出来る品質のグラフィックを作成するにはどうすればよいですか?

目標
  • ggplot2 を用いたパブリッシュ可能なグラフィックスの生成

  • ジオメトリ(点、線などの形状)、エステティック(審美)、および統計のレイヤーを ggplot プロットに適用出来るようになりましょう。

  • 様々な色、形、線を用いた、プロットの審美面の操作が出来るようになりましょう。

  • スケール変換とグループ化による、より良いデータ視覚化が出来るようになりましょう。

  • ggplot で作成したプロットのディスク保存が出来るようになりましょう。

データをプロットすることは、データとその変数間の様々な関係をクイックに探索する最良の方法の一つです。

Rには、主に3つのプロットシステムがあります。 R組み込みplot関数lattice パッケージ、ggplot2 パッケージです。

今回、私たちはggplot2パッケージについて学んでいきます。 なぜなら、ggplot2パッケージは出版品質並のグラフィック作成に最も効果的だからです。

ggplot2はthe grammar of graphics(グラフィックス文法)に基づいており、 一貫した構成記述体系(データセット、座標系、そして一連の配置)でプロットを 表現することができます。

ggplot2を理解するための鍵は、レイヤーについて考えることです。 このアイディアは、Photoshop、Illustrator、Inkscapeなどの画像編集ソフトを使用する場面でお馴染みかもしれません。

それでは、例題から始めましょう。:

library("ggplot2")
ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp)) +
  geom_point()

plot of chunk lifeExp-vs-gdpPercap-scatter

最初に行うことはggplot関数を呼び出すことです。 この関数は、新しいプロットを作成していることをRに知らせます。 ggplot関数に与える引数は、いずれもそのプロットのグローバルオプションであり、すべてのレイヤーに適用されます。

ggplotに2つの引数を渡しました。 一つ目の引数は、ggplotに、どのデータを図に表示するかを示します。この例は、前に読み込んだgapminderデータです。 二つ目の引数には、aes 関数を渡しました。 この関数は、データの変数が図のエステティック属性にどのようにマッピングされるかggplotに指示します。 この場合では、xyを指定しています。 ここでは、ggplotに対して、x軸にgapminderデータフレームの“gdpPercap”列を、 y軸には“lifeExp”列をプロットするように指示しました。 ggplotがその列のデータを調べるのに十分な知識を持っているため、これらの列に明示的にaesを渡す必要はありません。 (例えばx = gapminder [、 "gdpPercap"]など。)

以下のように、ggplotを呼び出すだけでは図を描くことはできません。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp))

plot of chunk unnamed-chunk-2

ggplotにデータを視覚的に表現する方法を指示する必要があります。 これは新しいgeomレイヤを追加することで行います。 この例では、geom_pointを使用しました。 これはggplotに点の散布図としてxとyの関係を視覚的に表現するように指示します。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp)) +
  geom_point()

plot of chunk lifeExp-vs-gdpPercap-scatter2

チャレンジ1

次の例を変更して、時間とともに平均余命がどのように変化しているかを図示して下さい。 changed over time:

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp)) + geom_point()

ヒント:gapminderデータセットには「year」という列がありますので、 「year」列をx軸に指定して下さい。

チャレンジ1の回答例

これは1つの回答例です。:

ggplot(data = gapminder, aes(x = year, y = lifeExp)) + geom_point()

plot of chunk ch1-sol

チャレンジ 2

先の例題とチャレンジでは、aes 関数を使用して、各点のxyの位置について散布図geomを指定しました。 修正できるもう1つのエステティック属性は、点の色です。 先のチャレンジのコードを修正して、“continent” 列で点に色付けして下さい。 データにどはどのような傾向が見られますか? それらの傾向は、あなたが期待したものですか?

チャレンジ 2の回答例

先の例題とチャレンジでは、aes 関数を使用して、各点のxyの位置について散布図geomを指定しました。 修正できるもう1つのエステティック属性は、点の色です。 先のチャレンジのコードを修正して、“continent” 列で点に色付けして下さい。 データにどはどのような傾向が見られますか? それらの傾向は、あなたが期待したものですか?

ggplot(data = gapminder, aes(x = year, y = lifeExp, color=continent)) +
  geom_point()

plot of chunk ch2-sol

レイヤー

散布図を使用することは、時間経過による変化を視覚化するのに、おそらく最適ではありません。 代わりに、データを線グラフとして可視化するようggplotに指示しましょう。

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country, color=continent)) +
  geom_line()

plot of chunk lifeExp-line

geom_pointレイヤーを追加する代わりに、geom_lineレイヤーを追加しました。 *by**エステティックを追加し、各国ごとに線を描くようggplotに指示します。

しかし、線と点の両方をプロット上に視覚化したい場合はどうすればよいでしょうか? プロットに別のレイヤーを追加するだけです。

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country, color=continent)) +
  geom_line() + geom_point()

plot of chunk lifeExp-line-point

各レイヤーは、前のレイヤーの上に描画されることに注意することが重要です。 この例では、点は線の上に描画されています。これはデモです。

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country)) +
  geom_line(aes(color=continent)) + geom_point()

plot of chunk lifeExp-layer-example-1

この例では、colorエステティックマッピングが、ggplotのグローバルプロットオプションからgeom_lineレイヤーに移動されたため、 点には色が適用されなくなりました。 これで、点が線の上に描画されていることがわかります。

ヒント:エステティック属性に、マッピングの代わりに値を設定する

これまでは、データの変数のマッピングとしてエステティック属性(colorなど)を使用する方法を見てきました。たとえば、geom_line(aes(color = continent))を使用すると、ggplotは各大陸に異なる色を与えます。 しかし、すべての線の色を青に変更したい場合はどうすればよいでしょうか? ‘geom_line(aes(color = “blue”))’で動作すると思うかもしれませんが、そうではありません。 特定の変数へのマッピングを作成したくないので、geom_line(color="blue")のようにaes()関数を除いて色の指定をします。

チャレンジ3

先の例の点と線のレイヤーの順序を入れ替えてみましょう。何が起こりますか?

チャレンジ 3の回答例

先の例の点と線のレイヤーの順序を入れ替えてみましょう。何が起こりますか?

ggplot(data = gapminder, aes(x=year, y=lifeExp, by=country)) +
 geom_point() + geom_line(aes(color=continent))

plot of chunk ch3-sol

The lines now get drawn over the points!

変換と統計

ggplot2を使用すると、統計モデルをデータに適用することが容易になります。 デモのために、最初の例に戻ります。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp, color=continent)) +
  geom_point()

plot of chunk lifeExp-vs-gdpPercap-scatter3

現在、1人当たりGDPのいくつかの強い外れ値により、点と点の関係性を見ることが難しくなっています。 scale関数を用いて、x軸上の単位のスケールを変更することができます。 これらは、データの値とエステティックな視覚的値との間のマッピングを制御します。 また、alpha関数を使用して点の透明度を変更することができます。 これは、大量のデータが非常に密集している場合、特に役立ちます。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp)) +
  geom_point(alpha = 0.5) + scale_x_log10()

plot of chunk axis-scale

gdpPercap列の値をプロットに描画する前に、log10関数による変換を適用したので、 10の各倍数は変換されたスケールの1の増加に対応します。 例えば、1人当たりGDPの値1,000はy軸の3、10,000はy軸の4に対応します。 これにより、x軸上のデータの広がりを視覚化することが容易になります。

ヒントのリマインダ:エステティック属性に、マッピングの代わりに値を設定する

geom_point(alpha = 0.5)を使用したことに注目してください。 先のヒントで触れたように、aes()関数以外の設定を使用すると、この値がすべての点で使用されます。 この場合、この値が必要です。しかし、他のエステティック設定と同様に、alphaはデータ内の変数にマッピングすることもできます。 たとえば、geom_point(aes(alpha = continent))を使用して、各大陸に異なる透明度を与えることができます。

geom_smoothという別のレイヤーを追加することで、データに単純な関係を当てはめることができます。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp)) +
  geom_point() + scale_x_log10() + geom_smooth(method="lm")

plot of chunk lm-fit

geom_smoothレイヤーでsizeエステティック属性を設定することによって、 線を太くすることができます。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp)) +
  geom_point() + scale_x_log10() + geom_smooth(method="lm", size=1.5)

plot of chunk lm-fit2

エステティック属性を指定する方法は2つあります。 ここでは、sizeエステティック属性の設定を’geom_smooth’の引数として渡しています。 これまでのレッスンでは、データの変数とその視覚表現の間のマッピングを定義するためにaes関数を使用しました。

チャレンジ 4a

前の例を用いて、点レイヤー上の点の色とサイズを変更して下さい。

ヒント:’aes’関数を使用しないでください。

チャレンジ 4aの回答例

前の例を用いて、点レイヤー上の点の色とサイズを変更して下さい。

ヒント:’aes’関数を使用しないでください。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp)) +
 geom_point(size=3, color="orange") + scale_x_log10() +
 geom_smooth(method="lm", size=1.5)

plot of chunk ch4a-sol

チャレンジ 4b

点を異なる形にし、また大陸毎に色分けと傾向線の描画をするために、 チャレンジ4aの回答を変更して下さい。 ヒント:color引数は、aes関数内で使用することができます。

チャレンジ 4bの回答例

点を異なる形にし、また大陸毎に色分けと傾向線の描画をするために、 チャレンジ4aの回答を変更して下さい。

ヒント:color引数は、aes関数内で使用することができます。

ggplot(data = gapminder, aes(x = gdpPercap, y = lifeExp, color = continent)) +
geom_point(size=3, shape=17) + scale_x_log10() +
geom_smooth(method="lm", size=1.5)

plot of chunk ch4b-sol

複数パネルの図

先の例では、すべての国の平均余命の変化を1つのプロットで視覚化しました。 一方、facetパネルのレイヤーを追加することで、複数のパネルに分割することができます。 名前が“A”または“Z”で始まる国にのみ焦点を当てます。

ヒント

データのサブセットからスタートします。 substr関数を使って文字列の一部を抜き出します。 この場合、gapminder$countryベクトルのstartからstopの位置にある文字が抜き出されます。 演算子%in%では、長いサブセット条件を書き出すのではなく、複数の比較を行うことができます。 (この場合、starts.with %in% c("A", "Z")starts.with == "A" | starts.with == "Z"です。)

starts.with <- substr(gapminder$country, start = 1, stop = 1)
az.countries <- gapminder[starts.with %in% c("A", "Z"), ]
ggplot(data = az.countries, aes(x = year, y = lifeExp, color=continent)) +
  geom_line() + facet_wrap( ~ country)

plot of chunk facet

facet_wrapレイヤーは引数として“formula”をとり、チルダ(~)で表記されます。 これは、gapminderデータセットのcountry列にある各々の一意な値のパネルを描画するようRに指示します。

テキストの変更

分析結果の発表に向けてこの図を整理するにあたり、いくつかのテキスト要素を変更する必要があります。 x軸はあまりにも雑然としており、y軸はデータフレームの列名ではなく、“Life expectancy”と読み替えるべきです。

これを行うには、いくつかのレイヤーを追加する必要があります。 theme レイヤーは、軸テキストと全体のテキストサイズを制御します。 軸、プロットタイトル、および任意の凡例のラベルは、labs関数を使用して設定できます。 凡例のタイトルは、aes関数で使用したものと同じ名前を設定します。 したがって、color凡例のタイトルはcolor = "Continent"を用いて設定され、 fill凡例のタイトルはfill = "任意のタイトル"を使用して設定されます。

ggplot(data = az.countries, aes(x = year, y = lifeExp, color=continent)) +
  geom_line() + facet_wrap( ~ country) +
  labs(
    x = "Year",              # x axis title
    y = "Life expectancy",   # y axis title
    title = "Figure 1",      # main title of figure
    color = "Continent"      # title of legend
  ) +
  theme(axis.text.x=element_blank(), axis.ticks.x=element_blank())

plot of chunk theme

プロットのエクスポート

ggsave()関数を使用すると、ggplotで作成したプロットをエクスポートすることができます。 出版、公開のための高品質グラフィックを作成するために、 適切な引数(widthheight、およびdpi)を調整してプロットの寸法と解像度を指定できます。 上記のように、そのプロットを保存するには、最初にそのプロットを変数lifeExp_plotに割り当て、 ggsaveにそのプロットをpng形式でresultsというディレクトリに保存するよう指示します。 (作業ディレクトリに’results /’フォルダがあることを確認してください。)

lifeExp_plot <- ggplot(data = az.countries, aes(x = year, y = lifeExp, color=continent)) +
  geom_line() + facet_wrap( ~ country) +
  labs(
    x = "Year",              # x axis title
    y = "Life expectancy",   # y axis title
    title = "Figure 1",      # main title of figure
    color = "Continent"      # title of legend
  ) +
  theme(axis.text.x=element_blank(), axis.ticks.x=element_blank())

ggsave(filename = "results/lifeExp.png", plot = lifeExp_plot, width = 12, height = 10, dpi = 300, units = "cm")
Error in grDevices::dev.off(): QuartzBitmap_Output - unable to open file 'results/lifeExp.png'

ggsaveには素晴らしい点が二つあります。 一つ目は、最後のプロットがデフォルトになるので、plot引数を省略すると、ggplotで作成した最後のプロットが自動的に保存されることです。 二つ目は、ファイル名に指定したファイル拡張子(例:.pngまたは.pdf)からプロットを保存するフォーマットを決定しようとします。 必要な場合は、device引数に明示的にフォーマットを指定できます。

これまで学んできたことは、ggplot2でできることの一部です。 RStudioは、利用可能な様々なレイヤーについて、とても便利なチートシートを提供しています。 更なる詳細なドキュメントは、ggplot2のwebサイトで入手できます。 最後に、何を変更すればよいかわからない場合、Google検索を実行してみて下さい。 大抵の場合、Stack Overflow(スタックオーバーフロー)上で適切な質問と回答が、再利用可能なコードと共に見つかります!

チャレンジ5

大陸で塗りつぶされた、1人当たりGDPの密度プロットを作成して下さい。

上級編

  • データの広がりをより良く視覚化するためにx軸を変換して下さい。
  • 1年毎の密度プロットをパネルに追加して下さい。

チャレンジ 5の回答例

大陸で塗りつぶされた、1人当たりGDPの密度プロットを作成して下さい。

上級編

  • データの広がりをより良く視覚化するためにx軸を変換して下さい。
  • 1年毎の密度プロットをパネルに追加して下さい。
ggplot(data = gapminder, aes(x = gdpPercap, fill=continent)) +
 geom_density(alpha=0.6) + facet_wrap( ~ year) + scale_x_log10()

plot of chunk ch5-sol

まとめ

  • プロットを作成するためにggplot2を用います

  • エステティック、ジオメトリ、統計、スケール変換、グループ化など、レイヤー単位でグラフィックスを考えてみましょう。