1. グラフ作成の流れ


◯◯◯ 使用するライブラリ


ggpplot2ライブラリ(グラフ描画パッケージ)およびgcookbookライブラリ(種々のデータフレーム)を使えるようにします

install.packages("ggplot2")
install.packages("gcookbook")
install.packages("patchwork")
library(ggplot2)
library(gcookbook)
library(patchwork)

gcookbookをincludeすることにより、例えば以下のようなデータフレーム(性別、年齢、身長体重のサンプル)が使えるようになります。

# 最初の6行を見る
head(heightweight)
##   sex ageYear ageMonth heightIn weightLb
## 1   f   11.92      143     56.3     85.0
## 2   f   12.92      155     62.3    105.0
## 3   f   12.75      153     63.3    108.0
## 4   f   13.42      161     59.0     92.0
## 5   f   15.92      191     62.5    112.5
## 6   f   14.25      171     62.5    112.0
# データフレームの構造
str(heightweight)
## 'data.frame':  236 obs. of  5 variables:
##  $ sex     : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 1 1 1 1 ...
##  $ ageYear : num  11.9 12.9 12.8 13.4 15.9 ...
##  $ ageMonth: int  143 155 153 161 191 171 185 142 160 140 ...
##  $ heightIn: num  56.3 62.3 63.3 59 62.5 62.5 59 56.5 62 53.8 ...
##  $ weightLb: num  85 105 108 92 112 ...
# データフレームの説明は以下を実行することで
# Helpパネルに表示されます。
?heightweight
help("heightweight", package = "gcookbook")

それではいよいよグラフを作っていきましょう。


(1) エステティックマッピング


エステティックマッピングとは、グラフを描く際に「どの変数をどの視覚的属性に対応させるか」を指定する操作です。これにより、データの値が位置や色などの形で自動的に反映され、情報が視覚的に表現されます。

ここでは、x軸に年齢、y軸に身長、fill属性に性別を割り振ります(この時点では何のグラフも出力されません)。

gp = ggplot(heightweight,aes(x=ageYear,y=heightIn,fill=sex));

(2)散布図としてグラフ化する


ggplot2では、描画するグラフの種類に応じて、geom_で始まる関数を使います。これらは「どのような形でデータを表現するか」を指定するもので、点・線・棒・箱ひげなど、視覚的な表現方法を決める役割を持ちます。どのgeom_xxxを使うかによって、同じデータでも異なる見方を提示することができます。

この講義では、以下のグラフについて学んでいきます。

以下は、散布図を作成する例です。 返り値を実行すると、指定した散布図が出力されます。

gp1 = gp + geom_point(shape=21,size=3)
gp1


(3)軸の設定


軸の設定を行います。軸が連続値か離散値かで扱いが変わります。 以下は、連続値の例です。詳しくは 8.軸の設定 から確認してください。

gp2 = gp1 + scale_x_continuous(
  name="Age", limits=c(10,20),breaks=c(10,15,20))
gp3 = gp1 + scale_y_continuous(
  name="Height (inch)",limits=c(40,80),breaks=10*(4:8))
# ggtitleで必要に応じてタイトルをつけますが、
# 以下では基本的に省略します。
gp2 = gp2 + ggtitle("gp2") 
gp3 = gp3 + ggtitle("gp3") 

# gp1とgp2を並べて表示(patchwork)
gp2 | gp3


(4)凡例の設定


凡例(条件ごとの差異)の色分けなどの設定を行います。 各々のグラフの解説ではデフォルトの凡例を使用します。 詳しくは 9.凡例の設定 から確認してください。

gp4 = gp3 + scale_fill_discrete(
  name = "Gender", labels=c("Female","Male")); 
gp5 = gp3 + scale_fill_grey(
  name = "Gender", labels=c("Female","Male"),start=0.2, end=0.8); 
gp6 = gp3 + scale_fill_brewer(
  name = "Gender", labels=c("Female","Male"),palette="Set2"); 
#3つのグラフをグリッド状に並べる(patchwork)
(gp4 | gp5) / gp6 


(5)全体の体裁を整える


最後に、theme_xxx()関数によって、ggplot2で描かれたグラフの全体的なデザインやレイアウト(背景・枠線・文字・凡例の位置など)を一括して整えます。グラフの内容を変えずに、見た目や雰囲気を統一したり、発表・印刷・論文などの用途に合わせてスタイルを切り替えることができます。

本講義では、HTML上の出力を前提としているため、ほとんど使うことはありませんが、 ここでは代表的な例のみを示しておきます。

gp7 = gp4 + theme_gray(base_size = 14) +
  theme(
    axis.title = element_text(size = 16),
    axis.text  = element_text(size = 12),
    legend.title = element_text(size = 15),
    legend.text  = element_text(size = 12)
  )
gp8 = gp4 + theme_classic(base_size = 14) +
  theme(
    axis.title = element_text(size = 16),
    axis.text  = element_text(size = 12),
    legend.title = element_text(size = 15),
    legend.text  = element_text(size = 12)
  )

gp9 = gp4 + theme_minimal(base_size = 14) +
  theme(
    axis.title = element_text(size = 16),
    axis.text  = element_text(size = 12),
    legend.title = element_text(size = 15),
    legend.text  = element_text(size = 12)
  )
(gp7 | gp8) / gp9 


(補足)patchworkの使い方


patchwork パッケージを使うと、複数の ggplot を簡単に並べられます。

  • 横に並べる: p1 | p2
  • 縦に並べる: p1 / p2
  • グリッド(2×2):
    • (p1 | p2) / (p3 | p4) (p1p2が横並び、、)
    • (p1 / p2) | (p3 / p4) (p1p2が縦並び、、)
  • 変則的な配置:
    • p1 | p2 / p3 (上に2つ、下に1つ)
    • (p1 / p2) | p3(左に縦2つ、右に1つ)
    • p1 / (p2 | p3)(上1つ、下に横2つ)
  • 比率を指定: + plot_layout(widths = c(1, 2), heights = c(1, 1))
      → それぞれの列や行の幅・高さの比率を設定できる。
      例:widths = c(1, 2) は「右側の列を左の2倍の幅」にする。   

2. 棒グラフ1:geom_col


◯◯◯ データフレームの準備


準備としてgcookbookを読み込みます。

# gcookbookのライブラリを使います
#install.packages("gcookbook")
library(gcookbook)

ここでは、gcookbookの中で提供される、6x2のデータセットBOD(水中の有機物が微生物によって分解されるときに消費される酸素量の時間経過)を使用します。

BOD; dim(BOD)
##   Time demand
## 1    1    8.3
## 2    2   10.3
## 3    3   19.0
## 4    4   16.0
## 5    5   15.6
## 6    7   19.8
## [1] 6 2
# 基本レイヤを作成
## この時点では何も出力されません
gp = ggplot(BOD,aes(x=Time,y=demand))

# デフォルトの棒グラフ(塗りは黒、幅は0.9)
gp1 = gp + geom_col() 
# 棒グラフの幅を最大幅の半分とする(デフォルトは0.9)
gp2 = gp + geom_col(width=0.5)
# 棒グラフの塗りつぶしを白、枠線を黒とし、枠線のサイズを0.2とする。
gp3 = gp + geom_col(fill="white",colour="black", size=0.2)
gp1 / gp2 | gp3 


◯◯◯ 属性の要素ごとに分ける方法


キャベツの 栽培条件と収穫量の関係に関するデータフレームを扱います。

library(gcookbook)
cabbage_exp; dim(cabbage_exp)
##   Cultivar Date Weight        sd  n         se
## 1      c39  d16   3.18 0.9566144 10 0.30250803
## 2      c39  d20   2.80 0.2788867 10 0.08819171
## 3      c39  d21   2.74 0.9834181 10 0.31098410
## 4      c52  d16   2.26 0.4452215 10 0.14079141
## 5      c52  d20   3.11 0.7908505 10 0.25008887
## 6      c52  d21   1.47 0.2110819 10 0.06674995
## [1] 6 6
# CultivarとDateは「Factor」(ラベル付きのinteger)
# 数字でラベル付けされた「文字列」と考えてください
typeof(cabbage_exp$Cultivar)
## [1] "integer"
#[1] "integer"
class(cabbage_exp$Cultivar)
## [1] "factor"
#[1] "factor"
# 順序は以下で確認(Levelsの並びに注目)
cabbage_exp$Cultivar
## [1] c39 c39 c39 c52 c52 c52
## Levels: c39 c52
cabbage_exp$Date
## [1] d16 d20 d21 d16 d20 d21
## Levels: d16 d20 d21
# 基本レイヤを作成
## x軸をData、y軸をWeight、塗りをCultivarにマッピング
gp = ggplot(cabbage_exp,aes(x=Date,y=Weight,fill=Cultivar))

# デフォルトはfillを積み上げる(棒グラフ)
## 積み上げ順はfactorの順序(上からC39,C52)
gp1 = gp + geom_col()

# 引数で「積み上げ」を明示的に指定(factor順序:上から下へ...)
gp2 = gp + geom_col(position = position_stack())

# 積み上げ順序の反転(factor順序:下から上へ)
## 上からC52,C39
gp3 = gp + geom_col(position = position_stack(reverse = TRUE))

# 100%積み上げ棒グラフとする
gp4 = gp + geom_col(position = "fill")
# gp1〜gp4を2x2のグリッド状に配置
(gp1 | gp2) / (gp3 | gp4)


◯◯◯ 水平方向に並べる(棒グラフ)


gp = ggplot(cabbage_exp,aes(x=Date,y=Weight,fill=Cultivar))
# デフォルトはfill属性同士はぴたりと張り付く
gp1 = gp + geom_col(position = position_dodge())
# 幅を0.7とし、隙間を0.1だけ空ける。
## この場合、「幅+隙間」をposition_dodgeの引数に与える
gp2 = gp + geom_col(position = position_dodge(0.8),width=0.7)
#隙間を狭める 
gp3 = gp2 + geom_col(position = position_dodge(0.72),width=0.7)

# 判例の色とテーマを整形
gp4 = gp3 + scale_fill_brewer(palette="Set2")
# 4つのグラフを縦に並べます。
gp1 / gp2 | gp3 / gp4 

# fillではなくinteractionを使っても同じことができます
gp = ggplot(cabbage_exp,
            aes(x=interaction(Date,Cultivar),
                y=Weight,fill=Cultivar))

# デフォルトの棒グラフにする
gp = gp + geom_col()
gp1 = gp + scale_fill_brewer(palette = "Set2")


# メモリの表記を変更する
gp2 = gp1 + labs(x = "Date-Cultivar") +
  scale_x_discrete(
  breaks = c("d16.c39","d20.c39","d21.c39",
         "d16.c52","d20.c52","d21.c52"), 
  labels = c("d16-c39","d20-c39","d21-c39",
         "d16-c52","d20-c52","d21-c52"))
gp1 | gp2


◯◯◯ エラーバーの作成(すでに標準誤差が計算されている場合)


library(gcookbook)

# cabbage_expより、Cultivarがc39のものだけ取り出す
cabbage_exp0 = cabbage_exp %>%
  filter(Cultivar=="c39")
print(cabbage_exp0)
##   Cultivar Date Weight        sd  n         se
## 1      c39  d16   3.18 0.9566144 10 0.30250803
## 2      c39  d20   2.80 0.2788867 10 0.08819171
## 3      c39  d21   2.74 0.9834181 10 0.31098410
gp = ggplot(cabbage_exp0,aes(x=Date,y=Weight))

# 塗りを白に、枠線を黒に
gp1 = gp + geom_col(fill="white",colour="black")
# エラーバーの作成(widthはエラーバーの横幅)
gp1 = gp1 + geom_errorbar(aes(ymin=Weight-se,ymax=Weight+se),width=.2)

# Cultivarで色分けする例
gp = ggplot(cabbage_exp,aes(x=Date,y=Weight, fill=Cultivar))

# 横ならびタイプ(dodge)でエラーバーを追加する時
## 棒グラフのデフォルトのずらし幅(0.9)に合わせる。
gp2 = gp + geom_col(colour="black", position = position_dodge()) + 
  geom_errorbar(aes(ymin=Weight-se,ymax=Weight+se),
                position=position_dodge(0.9), width=.2)
gp1 | gp2

3. 棒グラフ2:geom_bar


◯◯◯ データフレームの準備


以下では、データフレームとしてmtcarsを使います。
mtcarsは、1973-74 年モデルのアメリカ車 32 台を対象に、燃費 (mpg:Miles/(US) gallon)、シリンダー数 (cyl)、排気量 (disp:cu.in.)、馬力 (hp)、後軸比 (drat)、車重 (wt:1000 lbs)、1/4マイル走行時間 (qsec)、エンジン形式 (vs:0=V型/1=直列)、変速機形式 (am:0=自動/1=手動)、前進ギア数 (gear)、キャブレター数 (carb) を測定したデータフレームです。

library(gcookbook)
head(mtcars); dim(mtcars) # 32行に対して11の変数
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
## [1] 32 11
# 列名cylのデータを確認(cylはシリンダー数)
mtcars$cyl
##  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
# 出現頻度を数え上げる(2つの方法:countは要dplyr)
table(mtcars$cyl); count(mtcars, cyl) 
## 
##  4  6  8 
## 11  7 14
##   cyl  n
## 1   4 11
## 2   6  7
## 3   8 14
# mtcars$cylはdouble型ですが、
# factorに変換すると、数字が小さな順(4,6,8)に登録されることを覚えておいてください。
as.factor(mtcars$cyl)
##  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
## Levels: 4 6 8

◯◯◯ 同じカテゴリのものを数え上げる


# 列名cylをカテゴリカル変数(順番は小さな4,6,8)に変更し、
# 各要素の個数を数え上げて棒グラフとして表示
gp1 = ggplot(mtcars,aes(x=factor(cyl))) + geom_bar()
# factorにしない場合、X軸のラベルに5と7も表示されることに注意
gp2 = ggplot(mtcars,aes(x=cyl)) + geom_bar()
gp1 = gp1 + ggtitle("gp1 (x=factor(cyl))")
gp2 = gp1 + ggtitle("gp2 (x=cyl)")
gp1 | gp2

以下のgeom_textにおける..count..stat="count" によって自動計算された「x軸カテゴリごとのデータ数」であり、 何を数えるかは aes(x=...) で指定した変数によって決まります。

# 数え上げた個数を棒グラフ上に表示(vjustで上端からの高さを調整)
gp3 = ggplot(mtcars,aes(x=factor(cyl))) + geom_bar()
gp3 = gp3 + geom_text(aes(label=..count..),stat="count",
                      vjust=1.5,colour="white", size=10)

gp4 = ggplot(mtcars,aes(x=factor(cyl))) + geom_bar()
gp4 = gp4 + geom_text(aes(label=..count..),stat="count",
            vjust=-0.5,colour="brown", size=10)
gp4 = gp4 + scale_y_continuous(limits = c(0, 20)) #Y軸の範囲を広げます(見切れないため)
gp3 | gp4 

[属性の要素ごとに分ける方法(interaction)]

# 列名gearのデータを確認(ギアの数)
mtcars$gear
##  [1] 4 4 4 3 3 3 3 4 4 4 4 3 3 3 3 3 3 4 4 4 3 3 3 3 3 4 5 5 5 5 5 4
# $cylと$gearの組み合わせ(3つの方法)
## (シリンダー数 x ギア数のクロス集計)

## 方法1(返り値は配列)
table(mtcars$cyl,mtcars$gear); 
##    
##      3  4  5
##   4  1  8  2
##   6  2  4  1
##   8 12  0  2
## 方法2(要dplyr
library(dplyr)
count(mtcars, cyl,gear)
##   cyl gear  n
## 1   4    3  1
## 2   4    4  8
## 3   4    5  2
## 4   6    3  2
## 5   6    4  4
## 6   6    5  1
## 7   8    3 12
## 8   8    5  2
## 方法3(要dplyr:LEC03の復習)
mtcars %>% 
  group_by(cyl,gear) %>% 
  summarise(n = n())
## # A tibble: 8 × 3
## # Groups:   cyl [3]
##     cyl  gear     n
##   <dbl> <dbl> <int>
## 1     4     3     1
## 2     4     4     8
## 3     4     5     2
## 4     6     3     2
## 5     6     4     4
## 6     6     5     1
## 7     8     3    12
## 8     8     5     2

この組み合わせをグラフとして可視化していきます。

# 変数cylと変数gearの組み合わせについて、gearで色分け
gp1 = ggplot(mtcars,aes(x=interaction(cyl,gear),fill=factor(gear))) + geom_bar()
# 変数cylで色分け
gp2 = ggplot(mtcars,aes(x=interaction(cyl,gear),fill=factor(cyl))) + geom_bar()
gp1 | gp2

# fillにマッピングされた変数(数値)をファクタにしない場合、
# 連続値として扱われ、カラーバーで色付けされることに注意
gp3 = ggplot(mtcars,aes(x=interaction(cyl,gear),fill=gear)) + geom_bar()
gp4 = ggplot(mtcars,aes(x=interaction(cyl,gear),fill=cyl)) + geom_bar()
# グラフを縦並びに配置
gp3 | gp4

[interactionを使わない方法の例]

## デフォルトは積み上げ
gp1 = ggplot(mtcars,aes(x=cyl,fill=factor(gear))) + geom_bar()
gp2 = ggplot(mtcars,aes(x=gear,fill=factor(cyl))) + geom_bar()
gp1 | gp2

## 引数にposition=position_dodge()で横並びにする
gp3 = ggplot(mtcars,aes(x=cyl,fill=factor(gear))) + 
  geom_bar(position=position_dodge())
gp4 = ggplot(mtcars,aes(x=gear,fill=factor(cyl))) + 
  geom_bar(position=position_dodge())
gp3 / gp4

4. 折れ線グラフ:geom_line


◯◯◯ 折れ線グラフの基本


データフレームとしてBOD(水質調査において有機物分解に使われる酸素量)を迂回ます。

library(gcookbook)
BOD; dim(BOD)
##   Time demand
## 1    1    8.3
## 2    2   10.3
## 3    3   19.0
## 4    4   16.0
## 5    5   15.6
## 6    7   19.8
## [1] 6 2
# 基本レイヤの出力
gp = ggplot(BOD,aes(x=Time,y=demand))

# デフォルトのグラフ
gp1 = gp + geom_line()
# 線の色を深緑にして、線の太さを1.5とする。
gp2 = gp + geom_line(colour = "dark green",size=1.5)
# 線を点線とする。
gp3 = gp + geom_line(linetype="dashed")

# xをファクタにすると、カテゴリカルな系列と解釈され、
# x軸の6が取り除かれます。
## aes(group=1)は、Timeが同じグループに属していることを
## 明示しています。(無いとエラーとなります) 
gp = ggplot(BOD,aes(x=factor(Time),y=demand,group=1))
gp4 = gp + geom_line()
# 4つのグラフをグリッド状に配置
(gp1 / gp2) | (gp3 / gp4)


◯◯◯ 属性の要素ごとに分ける方法


以下で使用するtg は、 ビタミンCの投与方法(supp) と 投与量(dose) に対する 平均的な歯の長さ(length) をまとめたものです。

library(gcookbook)
print(tg); dim(tg)
##   supp dose length
## 1   OJ  0.5  13.23
## 2   OJ  1.0  22.70
## 3   OJ  2.0  26.06
## 4   VC  0.5   7.98
## 5   VC  1.0  16.77
## 6   VC  2.0  26.14
## [1] 6 3
# 基本レイヤの作成
gp = ggplot(tg,aes(x=dose,y=length,colour=supp))

# (gp1) suppの要素(OJ、VC)ごとに、色分けして出力
gp1 = gp + geom_line()
# (gp2) 線の描画をグループ間で左右に0.2だけずらす
gp2 = gp + geom_line(position = position_dodge(0.2))
# (gp3) 同じ位置に点を重ねる
gp3 = gp + geom_line(position = position_dodge(0.2)) + 
  geom_point(position=position_dodge(0.2),shape=21,size=5,fill="white")
# (gp4) suppをlinetypeでマッピング
gp4 = ggplot(tg,aes(x=dose,y=length,linetype=supp)) + geom_line()
(gp1 / gp2) | (gp3 / gp4)


◯◯◯ エラーバーの描画


library(gcookbook)
cabbage_exp
##   Cultivar Date Weight        sd  n         se
## 1      c39  d16   3.18 0.9566144 10 0.30250803
## 2      c39  d20   2.80 0.2788867 10 0.08819171
## 3      c39  d21   2.74 0.9834181 10 0.31098410
## 4      c52  d16   2.26 0.4452215 10 0.14079141
## 5      c52  d20   3.11 0.7908505 10 0.25008887
## 6      c52  d21   1.47 0.2110819 10 0.06674995
# Cultivarの要素に基づき、折れ線グラフを分けて描画
# 折れ線に関して、Cutivarでグループ分けすることを
# 明示的に伝える必要がある(colourをerrorbarでも使っているため)
gp = ggplot(cabbage_exp,
            aes(x=Date,y=Weight,colour=Cultivar,group=Cultivar))
            
# ドッジの設定を変数に保存
## position_dodge(width) の「width × 0.5」が、2色(2系列)の間の中心距離になります。
pd1 = position_dodge(0.3)
pd2 = position_dodge(1.0)

# エラーバーの描画
gp1 = gp + geom_errorbar(
  aes(ymin=Weight-se,ymax=Weight+se),
  width=.2,size=0.25,colour="black",position=pd1) +
  geom_line(position=pd1) + 
  geom_point(position=pd1,size=5)
  
gp2 = gp + geom_errorbar(
  aes(ymin=Weight-se,ymax=Weight+se),
  width=.2,size=0.25,colour="black",position=pd2) +
  geom_line(position=pd2) + 
  geom_point(position=pd2,size=5)
gp1 | gp2

5. 散布図:geom_point


◯◯◯ 散布図の基本


以下では、思春期の男女の身長と体重の関係を示すデータセットであるheightweightを使います。個々の参加者について、性別(sex)・年齢(ageYear)・身長(heightIn)・体重(weightLb)などが記録されています。

library(gcookbook)

# heightweightの最初の6行、および次元
head(heightweight); dim(heightweight)
##   sex ageYear ageMonth heightIn weightLb
## 1   f   11.92      143     56.3     85.0
## 2   f   12.92      155     62.3    105.0
## 3   f   12.75      153     63.3    108.0
## 4   f   13.42      161     59.0     92.0
## 5   f   15.92      191     62.5    112.5
## 6   f   14.25      171     62.5    112.0
## [1] 236   5
# 基本レイヤ
gp = ggplot(heightweight,aes(x=ageYear,y=heightIn)) 

# デフォルトの散布図を出力
gp1 = gp + geom_point()
# 正方形の点(22)、サイズを3、塗りつぶしの色を白に
gp2 = gp + geom_point(shape=22, size = 3, fill = "white")
# 円状の点(21)、サイズを2、塗りつぶしをorange、枠線を黒、、
gp3 = gp + geom_point(shape=21, size = 2, colour="black", fill = "orange")
gp1 | gp2 / gp3


◯◯◯ グループ分け


同様にheightweightを使っていきます。

library(gcookbook)
head(heightweight)
##   sex ageYear ageMonth heightIn weightLb
## 1   f   11.92      143     56.3     85.0
## 2   f   12.92      155     62.3    105.0
## 3   f   12.75      153     63.3    108.0
## 4   f   13.42      161     59.0     92.0
## 5   f   15.92      191     62.5    112.5
## 6   f   14.25      171     62.5    112.0
# 性別(sex)で色分け
gp_col = ggplot(heightweight,aes(x=ageYear,y=heightIn,colour=sex)) + geom_point()

# 性別(sex)で形状を変える
gp_shape = ggplot(heightweight,aes(x=ageYear,y=heightIn,shape=sex)) + geom_point()

# 性別(sex)で色も形も変える
gp_colshape = 
  ggplot(heightweight,aes(x=ageYear,y=heightIn,colour=sex,shape=sex)) + geom_point()
gp_col | gp_shape / gp_colshape

6. ヒストグラム:geom_histogram


◯◯◯ ヒストグラムの基本


以下では、アメリカ・イエローストーン国立公園の「オールド・フェイスフル間欠泉」に関するデータであるfaithfulを使います。各噴出について、噴出の継続時間(eruptions)と次の噴出までの待ち時間(waiting)が記録されています。

library(gcookbook)
head(faithful); dim(faithful)
##   eruptions waiting
## 1     3.600      79
## 2     1.800      54
## 3     3.333      74
## 4     2.283      62
## 5     4.533      85
## 6     2.883      55
## [1] 272   2
# 基本レイヤ
gp = ggplot(faithful,aes(x=waiting))

# デフォルトのヒストグラム
gp1 = gp + geom_histogram()
# ヒストグラムの塗りつぶしの色を白に、枠線の色を黒とする。
gp2 = gp + geom_histogram(fill="white",colour="black")
gp1 | gp2

# ビン幅を8に、ビンの開始を31とする。
# [31~39), [39~47), [47~55), ...(最大はデータによる)
gp3 = gp + geom_histogram(binwidth=8, boundary=31,fill="white",colour="black")
# ビン幅を[31~39), [39~47), [47~55), ...[87~95)とする
gp4 = gp = gp + geom_histogram(breaks = seq(31,95,by=8),fill="white",colour="black")
gp3 | gp4


◯◯◯ グループ分け(facetを使う)


以下で使用するbirthwt は、低出生体重児に関するデータセットです。 ボストンの病院で生まれた子どもについて、出生体重(bwt)を目的変数とし、母親の年齢(age)・体重(lwt)・人種(race)・喫煙の有無(smoke)・妊娠中の健康指導の有無(ht)、既往症(ui)などが記録されています。birthwtデータセットはMASSパッケージに含まれています。

library(MASS)
head(birthwt); dim(birthwt)
##    low age lwt race smoke ptl ht ui ftv  bwt
## 85   0  19 182    2     0   0  0  1   0 2523
## 86   0  33 155    3     0   0  0  0   3 2551
## 87   0  20 105    1     1   0  0  0   1 2557
## 88   0  21 108    1     1   0  0  1   2 2594
## 89   0  18 107    1     1   0  0  1   0 2600
## 91   0  21 124    3     0   0  0  0   0 2622
## [1] 189  10

smokeとbwtの内容は以下の通りです。

  • smoke=0:喫煙なし
  • smoke=1:喫煙あり
  • bwt:出生児体重
# 喫煙の有無ごとにヒストグラムを分けて描画
gp = ggplot(birthwt,aes(x=bwt,fill=factor(smoke)))
## デフォルトでは積み上げで表示
gp1 = gp + geom_histogram()
## 横並びではよくわからない
gp2 = gp + geom_histogram(position=position_dodge())
## 重ねて表示(半透明とする)
gp3 = gp + geom_histogram(position=position_identity(),alpha=0.6)
gp1 | gp2 / gp3

ファセット(facet_grid)を使うと、 グループごとに異なるグラフで描画をしてくれます。
facet_grid関数の引数に、グループ分けしたい変数を指定するには:

  • 書式:facet_grid(行の変数 ~ 列の変数)
  • 行や列を省略したい場合は、.(ドット)を使う
gp = ggplot(birthwt,aes(x=bwt))

# 喫煙の有無(smoke)でグループ分け
gp1 = gp + geom_histogram(fill="white",colour="black") +
  facet_grid(smoke ~ .) 
# 人種(race)でグループ分け
gp2 = gp + geom_histogram(fill="white",colour="black") +
  facet_grid(race ~ .)
gp1 | gp2

# 行×列で分割(race × smoke)
gp3 = gp + geom_histogram(fill="white",colour="black") +
  facet_grid(race ~ smoke)

gp3 + ggtitle("gp3") #タイトルをつけて描画

facetについては、「ファセット(facet)の利用」でも追加の解説を行っています。

7. ボックスプロット(箱ひげ図):geom_boxplot


◯◯◯ 箱ひげ図の基本


同様にMASSパッケージのbirthwt(出生児体重)を使用します。

library(MASS)
head(birthwt); dim(birthwt)
##    low age lwt race smoke ptl ht ui ftv  bwt
## 85   0  19 182    2     0   0  0  1   0 2523
## 86   0  33 155    3     0   0  0  0   3 2551
## 87   0  20 105    1     1   0  0  0   1 2557
## 88   0  21 108    1     1   0  0  1   2 2594
## 89   0  18 107    1     1   0  0  1   0 2600
## 91   0  21 124    3     0   0  0  0   0 2622
## [1] 189  10
# race(人種)は1,2,3のいずれか
library(dplyr)
count(birthwt, race)
##   race  n
## 1    1 96
## 2    2 26
## 3    3 67
# 基本レイヤの作成
## race(人種) をファクタに変換
gp = ggplot(birthwt,aes(x=factor(race),y=bwt))

# デフォルトの箱ひげ図
gp1 = gp + geom_boxplot()
# 外れ値の範囲設定(IQR x 1.5)および、描画の形
gp2 = gp + geom_boxplot(outlier.size=1.5, outlier.shape = 21)
# 外れ値を表示しない
## dotplotを重ね書きするときには表示しないのがよい
gp3 = gp + geom_boxplot(outlier.shape = NA)
gp1 | gp2 | gp3

# birthwtの全ての行を対象に箱ひげ図を作成
## xに任意の値を与える(下の場合1)
gp4 = ggplot(birthwt,aes(x=1,y=bwt)) + geom_boxplot()

## x軸の目盛とラベルを除く
gp5 = ggplot(birthwt,aes(x=1,y=bwt)) + geom_boxplot() +
  scale_x_continuous(breaks=NULL) + 
  theme(axis.title.x = element_blank())
gp4 | gp5  


◯◯◯ n x mの箱ひげ図


ひきつづき、MASSパッケージのbirthwt(出生児体重)を使用します。

library(MASS)
head(birthwt); dim(birthwt)
##    low age lwt race smoke ptl ht ui ftv  bwt
## 85   0  19 182    2     0   0  0  1   0 2523
## 86   0  33 155    3     0   0  0  0   3 2551
## 87   0  20 105    1     1   0  0  0   1 2557
## 88   0  21 108    1     1   0  0  1   2 2594
## 89   0  18 107    1     1   0  0  1   0 2600
## 91   0  21 124    3     0   0  0  0   0 2622
## [1] 189  10

使用する変数の内容は以下の通り

  • smoke(喫煙の有無: 0,1)
  • race(人種:1,2,3)
# smoke x raceは合計6種類
library(dplyr)
count(birthwt, smoke, race)
##   smoke race  n
## 1     0    1 44
## 2     0    2 16
## 3     0    3 55
## 4     1    1 52
## 5     1    2 10
## 6     1    3 12
# 上記の6つのグループそれぞれで箱ひげ図を出力
# smokeで色分けする場合(いずれもファクタに変換する)
gp1 = ggplot(birthwt,aes(x=factor(race),y=bwt,fill=factor(smoke))) + geom_boxplot()
## 凡例ラベルの表記を変更
gp2 = ggplot(birthwt,aes(x=factor(race),y=bwt,fill=factor(smoke))) + geom_boxplot() + 
  scale_fill_discrete(labels=c("NO SMOKE","SMOKE"))

# raceで色分けする場合
gp3 = ggplot(birthwt,aes(x=factor(smoke),y=bwt,fill=factor(race))) + geom_boxplot()
(gp1 | gp2) / gp3


◯◯◯ dotplotを重ねて描画


ひきつづき、MASSパッケージのbirthwt(出生児体重)を使用します。

library(MASS)
head(birthwt); dim(birthwt)
##    low age lwt race smoke ptl ht ui ftv  bwt
## 85   0  19 182    2     0   0  0  1   0 2523
## 86   0  33 155    3     0   0  0  0   3 2551
## 87   0  20 105    1     1   0  0  0   1 2557
## 88   0  21 108    1     1   0  0  1   2 2594
## 89   0  18 107    1     1   0  0  1   0 2600
## 91   0  21 124    3     0   0  0  0   0 2622
## [1] 189  10
# 基本レイヤの作成
gp = ggplot(birthwt,aes(x=factor(race),y=bwt))

# ビンをY軸上に区切って(ビン幅:90)ドットをX軸方向に積み上げる
# デフォルトは棒グラフの中心から右に配列される
gp1 = gp + geom_boxplot() + 
  geom_dotplot(binaxis="y", binwidth=90)

# 中央寄せとして、色を中抜きとする。
gp2 = gp + geom_boxplot() + 
  geom_dotplot(binaxis="y", binwidth=90, stackdir="center", fill=NA)

# 平均値の追加(stat_summaryを使用する)
## fun.y="mean"で、y値の平均値を計算し、geom="point"でその値を点で描画
gp3 = gp + geom_boxplot() + 
  geom_dotplot(binaxis="y", binwidth=90, stackdir="center", fill=NA) + 
  stat_summary(fun.y="mean",geom="point", shape=23,size=5,fill="red")
  
# N x Mの箱ひげ図でdotplotを重ねる
## smoke=0を白に、smoke=1を灰色にマッピング
## aes(group=factor(smoke))で、smokeの値ごとに平均値を計算する

gp4 = ggplot(birthwt,aes(x=factor(race),y=bwt,fill=factor(smoke))) +
  geom_boxplot() +
  scale_fill_manual(values=c("white","gray"), labels=c("NO SMOKE","SMOKE")) +
  geom_dotplot(binaxis="y",binwidth=60,stackdir="center",
               position = position_dodge(0.75)) +
  stat_summary(aes(group=factor(smoke)),
    fun.y="mean",geom="point",shape=23,size=3,
    fill="orange",colour="black",
    position = position_dodge(0.75)
    ) 
(gp1 / gp2) | (gp3 / gp4)

8. 軸の設定


◯◯◯ 使用するデータフレーム


library(gcookbook)
head(heightweight);dim(heightweight);
##   sex ageYear ageMonth heightIn weightLb
## 1   f   11.92      143     56.3     85.0
## 2   f   12.92      155     62.3    105.0
## 3   f   12.75      153     63.3    108.0
## 4   f   13.42      161     59.0     92.0
## 5   f   15.92      191     62.5    112.5
## 6   f   14.25      171     62.5    112.0
## [1] 236   5
# `str`関数を使うことでも、データフレームの構造を確認できます。
str(heightweight)
## 'data.frame':  236 obs. of  5 variables:
##  $ sex     : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 1 1 1 1 ...
##  $ ageYear : num  11.9 12.9 12.8 13.4 15.9 ...
##  $ ageMonth: int  143 155 153 161 191 171 185 142 160 140 ...
##  $ heightIn: num  56.3 62.3 63.3 59 62.5 62.5 59 56.5 62 53.8 ...
##  $ weightLb: num  85 105 108 92 112 ...

heightweight データは、男女のティーンエイジャー(11〜19歳)約200人の身長と体重をまとめたデータセットです。
含まれる主な変数は以下の通りです:

  • sex:性別(“f” = female, “m” = male)
  • ageYear:年齢(年単位)
  • heightIn:身長(インチ)
  • weightLb:体重(ポンド)

◯◯◯ 軸のタイトル


# 散布図を描画(xを年齢、yを身長)
gp = ggplot(heightweight,aes(x=ageYear,y=heightIn))

# (gp1)デフォルトの散布図
## 軸名はデフォルトではデータフレームの列名が使われる。
gp1 = gp + geom_point()

# (gp2)x軸・y軸のタイトルを設定しなおす
gp2 = gp1 + xlab("Age Year") + ylab("Height")
## 別の方法(1)
gp2 = gp1 + labs(x="Age Year", y = "Height")
## 別の方法(2)
## scale_xy_continuousは連続値変数を扱う軸の設定
gp2 = gp1 + scale_x_continuous(name = "Age Year") + 
  scale_y_continuous(name = "Height") 
# (gp3) x軸のタイトルを非表示にする
gp3 = gp1 + xlab(NULL)
gp3 = gp1 + scale_x_continuous(name=NULL) 
# (gp4) x軸の目盛とラベルを除く
gp4 = gp1 + scale_x_continuous(breaks = NULL)
(gp1 / gp2) | (gp3 / gp4) 


◯◯◯ 目盛と範囲の設定(連続値変数)


# 散布図を描画(xを年齢、yを身長)
gp = ggplot(heightweight,aes(x=ageYear,y=heightIn))
gp1 = gp + geom_point()

# x軸の目盛を1刻みとする(範囲では無い)
gp2 = gp1 + scale_x_continuous(breaks = 10:20)
# x軸の範囲を0〜20とする。
gp3 = gp1 + scale_x_continuous(limits=c(10,20))
# x軸の目盛と範囲を同時に変える。
gp4 = gp1 + scale_x_continuous(breaks=seq(10,20,by=2),limits=c(10,20))
(gp1 / gp2) | (gp3 / gp4)

# y軸の目盛と範囲を同時に変える。
gp5 = gp1 + scale_y_continuous(breaks=seq(0,100,by=10),limits=c(0,100))
# xim、ylimを使っても同じ
gp6 = gp1 + xlim(10,20) + ylim(40,80)
gp7 = gp1 + xlim(10,20) + ylim(80,40) # y軸を反転

## y軸の反転(および範囲の設定)|上と同じ
gp7 = gp1 + xlim(10,20) + scale_y_reverse(limits=c(40,80))

# データの内容から軸の範囲を決定
gp8 = gp1 + xlim(min(heightweight$ageYear)-2,max(heightweight$ageYear)+2) + 
            ylim(min(heightweight$heightIn)-5,max(heightweight$heightIn)+5)
(gp5 / gp6) | (gp7 / gp8)

# 横軸が「y=0」を含む様に拡大
gp9 = gp1 + expand_limits(x=0) + ggtitle("gp9")

# 任意に設定した目盛の位置に位置にラベルを打つ
gp10 = gp1 + scale_y_continuous(breaks=c(50,56,60,72),
                        labels=c("Tiny","Short","Medium","Tallish")) +
                        ggtitle("gp10")
gp9 | gp10


◯◯◯ 離散値変数の軸設定(scale_xy_discrete


# 年齢の整数部分だけを取り出し、離散値とし、さらにファクタとする
heightweight = heightweight %>%
  mutate(ageYear.f = factor(floor(ageYear)))
# 各年齢の行数をカウントする
count(heightweight,ageYear.f)
##   ageYear.f  n
## 1        11 30
## 2        12 63
## 3        13 46
## 4        14 44
## 5        15 39
## 6        16 10
## 7        17  4
# 単に年齢(11〜17)の個数を数え上げたグラフ
## 横軸のxをファクタとして扱う。
gp = ggplot(heightweight,aes(x=ageYear.f))
gp1 = gp + geom_bar() # デフォルトのx軸は、11から17までの7つ

# 順番を変える
gp2 = gp1 + scale_x_discrete(limits=c("12","13","14","15","11","16","17"))
# 順番を反転させる
gp3 = gp1 + scale_x_discrete(limits=rev(levels(heightweight$ageYear.f)))
# 一部のみを表示する
gp4 = gp1 + scale_x_discrete(limits=c("12","13","14"))

# 軸のラベルに新しい名前を対応させる
gp5 = gp1 + scale_x_discrete(limits=c("12","14","16"),
                      breaks=c("12","14","16"),
                      labels=c("Twelve","Fourteen","Sixteen"))
# plot_spacer()はブランクスペース
gp1 / gp2 | gp3 / gp4 |  plot_spacer() / gp5


◯◯◯ スケールの変更


# 散布図を描画(xを年齢、yを身長)
gp = ggplot(heightweight,aes(x=ageYear,y=heightIn))
gp1 = gp + geom_point()

# x軸とy軸を反転
gp2 = gp1 + coord_flip()
# x軸とy軸のスケールを同じにする。
gp3 = gp1 + coord_fixed()
## y軸のスケールをx軸の2倍とする。
gp4 = gp1 + coord_fixed(ratio = 1/2)
gp1 / gp2 | gp3 | gp4 

9. 凡例の設定


◯◯◯ 使用するデータフレーム


以下では離散値用にPlantGrowth、連続値用にheightweightを使います。PlantGrowthは、植物の成長量(乾燥重量)を、異なる処理条件(群)で比較した実験データ、heightweightは、男女のティーンエイジャー(11〜19歳)約200人の身長と体重をまとめたデータセットです

# 離散値用のデータフレーム
head(PlantGrowth);dim(PlantGrowth)
##   weight group
## 1   4.17  ctrl
## 2   5.58  ctrl
## 3   5.18  ctrl
## 4   6.11  ctrl
## 5   4.50  ctrl
## 6   4.61  ctrl
## [1] 30  2
# 構造の確認
str(PlantGrowth)
## 'data.frame':  30 obs. of  2 variables:
##  $ weight: num  4.17 5.58 5.18 6.11 4.5 4.61 5.17 4.53 5.33 5.14 ...
##  $ group : Factor w/ 3 levels "ctrl","trt1",..: 1 1 1 1 1 1 1 1 1 1 ...
# grouopは要素数3のファクタ
PlantGrowth$group
##  [1] ctrl ctrl ctrl ctrl ctrl ctrl ctrl ctrl ctrl ctrl trt1 trt1 trt1 trt1 trt1
## [16] trt1 trt1 trt1 trt1 trt1 trt2 trt2 trt2 trt2 trt2 trt2 trt2 trt2 trt2 trt2
## Levels: ctrl trt1 trt2
library(gcookbook)
# 連続値用のデータフレーム
head(heightweight);dim(heightweight)
##   sex ageYear ageMonth heightIn weightLb ageYear.f
## 1   f   11.92      143     56.3     85.0        11
## 2   f   12.92      155     62.3    105.0        12
## 3   f   12.75      153     63.3    108.0        12
## 4   f   13.42      161     59.0     92.0        13
## 5   f   15.92      191     62.5    112.5        15
## 6   f   14.25      171     62.5    112.0        14
## [1] 236   6
# 構造の確認
str(heightweight)
## 'data.frame':  236 obs. of  6 variables:
##  $ sex      : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 1 1 1 1 ...
##  $ ageYear  : num  11.9 12.9 12.8 13.4 15.9 ...
##  $ ageMonth : int  143 155 153 161 191 171 185 142 160 140 ...
##  $ heightIn : num  56.3 62.3 63.3 59 62.5 62.5 59 56.5 62 53.8 ...
##  $ weightLb : num  85 105 108 92 112 ...
##  $ ageYear.f: Factor w/ 7 levels "11","12","13",..: 1 2 2 3 5 4 5 1 3 1 ...

◯◯◯ 凡例の表示◯◯◯


# ボックスプロットの作成(fillは離散値groupにマッピング)
## 凡例は離散表現となる
gp_dc = ggplot(PlantGrowth,aes(x=group,y=weight,fill=group))
gp_dc = gp_dc + geom_boxplot()

# 散布図の作成(fillは連続値ageYearにマッピング)
## fillをプロットに反映させるには、塗りのあるshapeを選ぶ必要あり
## 凡例はカラーバーとなる
gp_con = ggplot(heightweight,aes(x=heightIn,y=weightLb,fill=ageYear))
gp_con = gp_con + geom_point(size=3,shape=21)
gp_dc | gp_con


◯◯◯ 凡例の表示形式(離散値)◯◯◯


# 離散値の凡例のタイトルを変更(デフォルトは軸名)
gp_dc1 = gp_dc + scale_fill_discrete(name="Condition") #同じ
gp_dc1 = gp_dc + labs(fill="Condition") # 省略記法

# 凡例のラベル(デフォルトは要素名)を更新
gp_dc2 = gp_dc + scale_fill_discrete(
  labels=c("Control","Treatment 1","Treatment 2")) + ggtitle("dc2")
  
# 要素数が不足しているところはNAとなる
gp_dc3 = gp_dc + scale_fill_discrete(
  labels=c("Control","Treatment 1"))
  
# 離散値凡例の色をグレースケールで0.5〜1.0の範囲とする。
gp_dc4 = gp_dc + scale_fill_grey(
  start=.5,end = 1,limits=c("ctrl","trt1","trt2"))
gp_dc1 / gp_dc2 | gp_dc3 / gp_dc4


◯◯◯ 凡例の表示形式(連続値)◯◯◯


# 連続値の凡例タイトルの変更
gp_con1 = gp_con + scale_fill_continuous(name="Condition") #同じ
gp_con1 = gp_con + labs(fill="Condition")

# 連続値凡例のカラーバーの目盛と範囲を設定
gp_con2 = gp_con + scale_fill_continuous(
    limits=c(10,20), breaks=seq(10,20,by=5))

# 目盛に対応するラベルを更新
gp_con3 = gp_con + scale_fill_continuous(
    limits=c(10,20), breaks=seq(10,20,by=5),
    labels=c("Ten","Fifteen","Twenty"))
    
## カラーバーの最小値を黒、最大値を白とする
gp_con4 = gp_con + scale_fill_gradient(
  low="black", high="white", 
  limits=c(10,20),breaks=seq(10,20,by=5))
  
## カラーバーの代わりに離散的な凡例を用いる。
gp_con5 = gp_con + scale_fill_gradient(
  low="white", high="black", 
  limits=c(12,18),breaks=seq(12,18,by=3), 
  guide = guide_legend())
(gp_con1 | gp_con2) / (gp_con3 | gp_con4) / (gp_con5 | plot_spacer())


◯◯◯ 凡例の非表示◯◯◯


# fill凡例を非表示
gp_dc5 = gp_dc + scale_fill_discrete(guide=FALSE)
gp_con6 = gp_con + scale_fill_continuous(guide=FALSE)

# 全ての凡例を一気に非表示
gp_dc5 = gp_dc + theme(legend.position="none") 
gp_con6 = gp_con + theme(legend.position="none")
gp_dc5 | gp_con6


◯◯◯ 凡例の位置を変更


# 上部に表示
gp_dc6 = gp_dc + theme(legend.position="top")

# 座標で指定:左下が(0,0), 右上が(1,1)
gp_dc7 = gp_dc + theme(legend.position=c(0.8,0.2))

# 凡例を4隅に合わせる
gp_dc8 = gp_dc + theme(legend.position=c(0,1),
              legend.justification=c(0,1))
gp_dc9 = gp_dc + theme(legend.position=c(0,0),
              legend.justification=c(0,0))
(gp_dc6 | gp_dc7) / (gp_dc8 | gp_dc9)


◯◯◯ その他


# 凡例の枠に境界線をつける
gp_dc10 = gp_dc + theme(legend.background = 
                element_rect(fill="white",colour="black")) + ggtitle("dc10")

# 凡例ラベルの体裁を一気に変更
gp_dc11 = gp_dc  + theme(legend.text=element_text(
    face="italic",family="Times",colour="red",size=14)) + ggtitle("dc11")

gp_con7 = gp_con  + theme(legend.text=element_text(
  face="italic",family="Times",colour="brown",size=12)) + ggtitle("con7")
gp_dc10 | gp_dc11 | gp_con7

10. 色の設定

以下ではheightweightを使います。heightweightは、男女のティーンエイジャー(11〜19歳)約200人の身長と体重をまとめたデータセットです

library(gcookbook)
# 連続値用のデータフレーム
head(heightweight);dim(heightweight)
##   sex ageYear ageMonth heightIn weightLb ageYear.f
## 1   f   11.92      143     56.3     85.0        11
## 2   f   12.92      155     62.3    105.0        12
## 3   f   12.75      153     63.3    108.0        12
## 4   f   13.42      161     59.0     92.0        13
## 5   f   15.92      191     62.5    112.5        15
## 6   f   14.25      171     62.5    112.0        14
## [1] 236   6
# 構造の確認
str(heightweight)
## 'data.frame':  236 obs. of  6 variables:
##  $ sex      : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 1 1 1 1 ...
##  $ ageYear  : num  11.9 12.9 12.8 13.4 15.9 ...
##  $ ageMonth : int  143 155 153 161 191 171 185 142 160 140 ...
##  $ heightIn : num  56.3 62.3 63.3 59 62.5 62.5 59 56.5 62 53.8 ...
##  $ weightLb : num  85 105 108 92 112 ...
##  $ ageYear.f: Factor w/ 7 levels "11","12","13",..: 1 2 2 3 5 4 5 1 3 1 ...
# ageYearの少数部分を切り捨てたものをageYear.iとし, 
# ageYear.iをファクタ化したものをageYear.fとする。
heightweight = heightweight %>% 
  mutate(
    ageYear.i = floor(ageYear), #整数化
    ageYear.f = factor(ageYear.i) #因子化
  )
# ファクタ化されていることを確認  
heightweight$ageYear.f
##   [1] 11 12 12 13 15 14 15 11 13 11 11 14 13 12 11 12 15 12 12 15 11 11 13 14 15
##  [26] 13 14 15 17 12 14 13 12 11 15 16 14 14 15 15 14 13 14 14 12 15 11 12 12 14
##  [51] 14 16 12 12 12 12 12 13 15 11 15 15 12 12 12 13 12 12 12 15 15 11 12 15 11
##  [76] 14 13 13 12 12 14 14 14 15 15 11 14 15 15 15 11 13 13 12 12 12 13 11 12 17
## [101] 14 13 15 12 16 11 13 15 14 14 15 13 13 12 12 12 11 15 15 12 12 13 13 14 12
## [126] 11 12 13 12 17 14 14 11 15 15 12 15 11 12 12 12 13 14 16 13 13 15 11 14 14
## [151] 14 14 14 14 13 12 13 12 12 12 15 14 14 12 16 13 14 11 13 13 13 15 13 12 14
## [176] 14 12 11 15 16 11 15 15 16 12 14 13 12 11 13 13 15 14 12 13 14 14 14 13 12
## [201] 12 15 13 14 13 11 14 11 12 11 13 12 17 13 12 16 16 12 12 11 15 13 12 16 13
## [226] 13 14 12 12 14 11 13 15 13 13 12
## Levels: 11 12 13 14 15 16 17

◯◯◯ 塗りつぶしの設定

# デフォルトのboxplot
## fillを指定していない場合、白色が塗られる。
gp = ggplot(heightweight,aes(x=ageYear.f,y=heightIn))
gp1 = gp + geom_boxplot()
# 一律に色を塗る
gp2 = gp + geom_boxplot(colour="black",fill="purple")
gp1 | gp2

# エステティックマッピングでfillに軸名を対応させると
# ファクトの要素ごとに異なる色の配色となる
gp3 = ggplot(heightweight,aes(x=ageYear.f,y=heightIn,fill=ageYear.f)) + 
        geom_boxplot()

# デフォルトの配色パレット
## 色相で等距離にあるもの
gp4 = gp3 + scale_fill_discrete() 
gp4 = gp3 + scale_fill_hue() #上に同じ
# グレースケール
gp5 = gp3 + scale_fill_grey()
## 始まりと終わりのグレースケールの値を指定
gp6 = gp3 + scale_fill_grey(start=1.0,end=0.5)
(gp3 | gp4) / (gp5 | gp6)

gp = ggplot(heightweight,aes(x=ageYear.f,y=heightIn,fill=ageYear.f)) + 
      geom_boxplot()

# ColorBrewerパレット(デフォルトで利用可能)
gp_brewer = gp + scale_fill_brewer() + ggtitle("brewer")

# viridisパレット
# install.packages("viridis")
library(viridis)
gp_viridis = gp + scale_fill_viridis_d() + ggtitle("viridis")

# そのほかによく使われているものとして、
# Nature Publishing Groupのパレットががあります。

# ggsciのライブラリを使用します。(事前に要install)
# install.packages("ggsci")
library(ggsci)
gp_npg = gp + scale_fill_npg() + ggtitle("npg")
gp_viridis | gp_brewer | gp_npg

◯◯◯ ColorBrewer

#ColorBrewerで使用できるパレットを調べる
library(RColorBrewer)
display.brewer.all()

gp = ggplot(heightweight,aes(x=ageYear.f,y=heightIn,fill=ageYear.f)) + 
      geom_boxplot()
## 引数でパレットを指定
gp1 = gp + scale_fill_brewer(palette = "Oranges")
gp2 = gp + scale_fill_brewer(palette = "PiYG") 
gp3 = gp + scale_fill_brewer(palette = "Paired")
gp4 = gp + scale_fill_brewer(palette = "Set2")
(gp1 | gp2) / (gp3 | gp4)

◯◯◯ 手動による色設定

gp = ggplot(heightweight,aes(x=ageYear.f,y=heightIn,fill=ageYear.f)) + 
      geom_boxplot()
      
# 手動で色指定(valuesで要素の数だけ指定します)
gp1 = gp + scale_fill_manual(
  values=c("purple","pink","orange","black","white","blue","gray")
  ) + ggtitle("gp1")
gp2 = gp + scale_x_discrete(
  limits=c("12","16"),labels=c("Twelve","Sixteen")) + 
  scale_fill_manual(values=c("#CC6666","#7777DD")
  ) + ggtitle("gp2")
gp1 | gp2

11. ファセット(facet)の利用

facet(ファセット)は、変数の値ごとに自動的にグラフを分割して表示する仕組みです。 単に複数のグラフを手で並べるのではなく、データ内のカテゴリ(条件)に応じて自動的に小分けされたサブグラフを作ってくれるのが最大の利点です。

ここでも、データとしてheightweightを使います。heightweightは、男女のティーンエイジャー(11〜19歳)約200人の身長と体重をまとめたデータセットです

# 使用するデータフレーム
library(gcookbook) 
# heightweightを初期化
## data() 関数は、R本体やパッケージに含まれるサンプルデータを作業スペースに読み込む関数です。すでに同じ名前のデータが存在していても、元の状態(初期状態)に戻すように上書きして読み込み直すことができます。このため、実質的に「データの初期化」としても使えます。
data(heightweight)  

head(heightweight); dim(heightweight)
##   sex ageYear ageMonth heightIn weightLb
## 1   f   11.92      143     56.3     85.0
## 2   f   12.92      155     62.3    105.0
## 3   f   12.75      153     63.3    108.0
## 4   f   13.42      161     59.0     92.0
## 5   f   15.92      191     62.5    112.5
## 6   f   14.25      171     62.5    112.0
## [1] 236   5
str(heightweight)
## 'data.frame':  236 obs. of  5 variables:
##  $ sex     : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 1 1 1 1 ...
##  $ ageYear : num  11.9 12.9 12.8 13.4 15.9 ...
##  $ ageMonth: int  143 155 153 161 191 171 185 142 160 140 ...
##  $ heightIn: num  56.3 62.3 63.3 59 62.5 62.5 59 56.5 62 53.8 ...
##  $ weightLb: num  85 105 108 92 112 ...
heightweight = heightweight %>% 
  mutate(
    ageYear.i = floor(ageYear), #整数化
    ageYear.f = factor(ageYear.i) #因子化
    )

# 結果を確認
heightweight$ageYear.f
##   [1] 11 12 12 13 15 14 15 11 13 11 11 14 13 12 11 12 15 12 12 15 11 11 13 14 15
##  [26] 13 14 15 17 12 14 13 12 11 15 16 14 14 15 15 14 13 14 14 12 15 11 12 12 14
##  [51] 14 16 12 12 12 12 12 13 15 11 15 15 12 12 12 13 12 12 12 15 15 11 12 15 11
##  [76] 14 13 13 12 12 14 14 14 15 15 11 14 15 15 15 11 13 13 12 12 12 13 11 12 17
## [101] 14 13 15 12 16 11 13 15 14 14 15 13 13 12 12 12 11 15 15 12 12 13 13 14 12
## [126] 11 12 13 12 17 14 14 11 15 15 12 15 11 12 12 12 13 14 16 13 13 15 11 14 14
## [151] 14 14 14 14 13 12 13 12 12 12 15 14 14 12 16 13 14 11 13 13 13 15 13 12 14
## [176] 14 12 11 15 16 11 15 15 16 12 14 13 12 11 13 13 15 14 12 13 14 14 14 13 12
## [201] 12 15 13 14 13 11 14 11 12 11 13 12 17 13 12 16 16 12 12 11 15 13 12 16 13
## [226] 13 14 12 12 14 11 13 15 13 13 12
## Levels: 11 12 13 14 15 16 17

まずは「一つのグラフの中で」fillで色分けをする方法から確認していきます

# 身長(x=heightIn)と体調(y=weightLb)の相関図をプロット
gp1 = ggplot(heightweight,aes(x=heightIn,y=weightLb))
gp1 = gp1 + geom_point(size=3, shape=21)

# 年齢で色分けする
gp2 = ggplot(heightweight,aes(x=heightIn,y=weightLb,fill=ageYear.f))
gp2 = gp2 + geom_point(size=3, shape=21)
gp2 = gp2 + scale_fill_discrete()

# 性別で色分けする
gp3 = ggplot(heightweight,aes(x=heightIn,y=weightLb,fill=sex))
gp3 = gp3 + geom_point(size=3, shape=21)
gp3 = gp3 + scale_fill_discrete()
(gp1 | gp2) / gp3

同じことを、複数のグラフで振りわける方法でやりましょう。 以下では、要素ごとに異なるグラフを作成するためにファセットを利用していきます。

## 基本プロットの作成
gp = ggplot(heightweight,aes(x=heightIn,y=weightLb))
gp = gp + geom_point(size=3, shape=21, fill="black")

## 垂直方向に分割
gp_a = gp + facet_grid(ageYear.f ~ .)
gp_b = gp + facet_grid(sex ~ .)
gp_a | gp_b

## 水平方向に分割
gp_c = gp + facet_grid(. ~ ageYear.f)
gp_d = gp + facet_grid(. ~ sex)
gp_c / gp_d

## なるべく同じ行数列数で配置
gp_e = gp + facet_wrap( ~ ageYear.f)
## 行数を指定
gp_f = gp + facet_wrap( ~ ageYear.f, nrow=4)
## 列数を指定(ここでは出力しません)
# gp_g = gp + facet_wrap( ~ ageYear.f, ncol=4)
gp_e / gp_f

## xとyをフリースケールにする
##(軸の範囲が可変となります)
gp_h = gp + facet_wrap( ~ ageYear.f, scales = "free") 

## yのみをフリースケールにする(ここでは出力しません)
# gp_i = gp + facet_wrap( ~ ageYear.f, scales = "free_y")

gp_h + ggtitle('gp_h | scales="free"')


◯◯◯ ファセットラベルのテキストを変更する


まず、heightweightの性別属性を確認します。

heightweight$sex
##   [1] f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
##  [38] f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
##  [75] f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
## [112] m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m
## [149] m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m
## [186] m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m
## [223] m m m m m m m m m m m m m m
## Levels: f m

このfmをfemaleとmaleに変更する方法を考えます。
凡例ラベルと異なり、 ファセットラベルを変更するには、 大元のデータフレームのデータを変更しなければならないようです。
dplyrライブラリのrecode関数を使うと、 文字列を異なる文字列に一括に変換してくれます。

# install.packages(dplyr)
library(dplyr)

data(heightweight) #初期化

heightweight = heightweight %>% 
  mutate(
    ageYear.i = floor(ageYear), #整数化
    ageYear.f = factor(ageYear.i) #因子化
    )
    
heightweight = heightweight %>% 
  mutate(gender = factor(sex),
         gender = recode(gender, "f"="Female","m"="Male")
  )
# (パイプを使うと以下のように書けます)  
# heightweight$gender = recode(factor(heightweight$sex), "f"="Female","m"="Male")  
## 次のように変わりました. 
###[BEFORE]
head(heightweight$sex,10)
##  [1] f f f f f f f f f f
## Levels: f m
###[AFTER]
head(heightweight$gender,10)
##  [1] Female Female Female Female Female Female Female Female Female Female
## Levels: Female Male

これでファセットラベルが「Female」「Male」となりました

gp = ggplot(heightweight,aes(x=heightIn,y=weightLb,fill=ageYear.f))
gp = gp + geom_point(size=3, shape=21)
gp1 = gp + facet_grid(. ~ gender)

# ファセットラベルのサイズを変える
gp2 = gp + facet_grid(. ~ gender) + 
  theme(strip.text = element_text(size=40))

# ファセットラベルの背景も変える
gp3 = gp + facet_grid(. ~ gender) + 
  theme(strip.text = element_text(face="bold",size=rel(2)),
        strip.background = 
          element_rect(fill="lightblue",colour="black",size=1))
gp1 / gp2 / gp3


◯◯◯ ファセットごとに異なる色を与える


## fillを使いますが、判例とファセットで表記が重なるため, 
## 凡例を消去します. 
gp = ggplot(heightweight,aes(x=heightIn,y=weightLb,fill=gender))
gp = gp + geom_point(size=3, shape=21)
gp1 = gp + scale_fill_discrete(guide=FALSE)
gp2 = gp + facet_grid(. ~ gender) + 
  theme(strip.text = element_text(size=20))
gp1 / gp2