3-2 統一的な記法によるグラフ描写(ggplot2パッケージ)
# ダイヤモンドの価格・カラット数・色の関係を散布図として可視化
# ライブラリ読み込み
library(ggplot2 )
# 可視化
ggplot(diamonds ) + # 可視化したいデータフレームの指定
aes( # 列名をx軸、y軸、色に割り当て。引用符は使わない
x = carat ,
y = price ,
color = color
) +
geom_point() # 散布図として可視化
グラフに使うデータフレームの指定(ggplot
関数)
データフレームの列を軸や点の色に指定(aes
関数)
# ダイアモンドのカラット数と価格の関係の散布図を
# 1カラット以上か否かで塗り分ける
ggplot(diamonds ) +
aes(x = carat , y = price , color = carat > = 1 ) +
geom_point()
# 審美的属性の指定方法3パターン(結果省略)
# 1. mapping変数をレイヤとして利用
ggplot(diamonds ) +
aes(x = carat , y = price ) +
geom_point()
# 2. mapping変数をggplot関数のmapping引数に指定
ggplot(diamonds , mapping = aes(x = carat , y = price )) +
geom_point()
# 3. mapping変数をgeom_point関数のmapping引数に指定
ggplot(diamonds ) +
geom_point(mapping = aes(x = carat , y = price ))
# geom関数群によるグラフ全体の審美的属性のオーバーライド
# (結果省略)
ggplot(diamonds ) +
aes(x = carat , y = table ) +
geom_point(aes(y = price )) # x = carat, y = priceに相当
# 同日に同種の餌を与えられた雛の体重の中央値を集計
library(magrittr )
chick_weight <- ChickWeight %> %
dplyr :: group_by(Diet , Time ) %> %
dplyr :: summarize(Weight = median(weight ), .groups = " drop" )
# 体重の中央値の推移を餌ごとに可視化する
ggplot(chick_weight ) +
aes(x = Time , y = Weight , shape = Diet ) +
geom_line() +
geom_point(size = 4 )
# 散布図の点をviridisで色付け
ggplot(mtcars ) +
aes(wt , mpg , color = cyl ) +
geom_point(size = 3 ) +
scale_color_viridis_c()
# 外れ値を含むデータの作成
d <- data.frame (
condition = " good" ,
x = runif(100 , 0 , 10 )
) %> %
dplyr :: mutate(y = rnorm(dplyr :: n(), x )) %> %
tibble :: add_row(x = 8 , y = 1 , condition = " bad" )
# 外れ値を含む散布図の作成
g <- ggplot(d ) +
aes(x , y , shape = condition ) +
geom_point()
# (a) 点の形をパッケージにまかせて表示
g
# (b) 点の形はデータが正常なら●で、外れ値なら×にする
g + scale_shape_manual(
values = c(good = " circle" , bad = " cross" )
)
# condition列を凡例に利用したとき、
# goodがbadより順序が上にくるように変数dに前処理を加える
d <- d %> %
dplyr :: mutate(
condition = forcats :: fct_relevel(condition , " good" , " bad" )
)
g <- ggplot(d ) +
aes(x , y , shape = condition ) +
geom_point()
# (a) 散布図の点の枠線と塗り潰しがうまく反映されない例
ggplot(mtcars ) +
aes(wt , mpg , fill = cyl ) +
geom_point(color = " black" , size = 3 )
# (b) 散布図の点の枠線と塗り潰しがうまく反映される例
ggplot(mtcars ) +
aes(wt , mpg , fill = cyl ) +
geom_point(
color = " black" ,
size = 3 ,
shape = " circle filled"
)
# 散布図で塗り潰し可能な形を複数利用する例
ggplot(mtcars ) +
aes(
wt , mpg , fill = cyl ,
shape = as.factor(am ) # shape審美的属性に数値は使えない
) +
geom_point(color = " black" , size = 3 ) +
scale_shape_manual(
name = " am" , # 凡例のタイトルを「as.factor(am)」から変更
values = c( # am列の各値(0または1)に割り当てたい形を指定
" 1" = " circle filled" ,
" 0" = " triangle filled"
)
)
3-4 軸の調整(scale
関数群とcoord
関数群)
# ヒストグラムの作成
g <- ggplot(diamonds ) +
aes(carat ) +
geom_rug() +
geom_histogram()
# (a) 通常の軸のグラフ
g
# (b) y軸が対数スケールのグラフ
g + scale_y_log10()
# 車重と燃費の関係を散布図と回帰曲線で比較する
g <- ggplot(mtcars ) +
aes(wt , mpg ) +
geom_point() +
geom_smooth(se = FALSE ) # 回帰曲線。信頼区間は非表示
# (a) 全領域を表示
g
# (b) 指定範囲のみ表示
g + coord_cartesian(xlim = c(3 , 4 ))
# (c) 指定範囲外を欠損値に変換
# 欠損の発生と回帰直線の再計算が起きている旨の警告が発生
g + xlim(3 , 4 ) # scale_x_continuous(xlim = c(3, 4)) と同じ
# 車の重量と燃費の比較
g <- ggplot(mtcars ) +
aes(x = wt ,
y = mpg ,
shape = ifelse(am == 1 , " AT車" , " MT車" )) +
geom_point(size = 3 )
# (a) ラベルの調整なし
g
# (b) ラベルの調整あり
g + labs(
# 審美的属性ごとのラベル変更
x = " 車重(1000lbs)" ,
y = " 燃費(miles/(US) gallon)" ,
shape = NULL ,
# その他のラベル変更
title = " 車の重量と燃費の関係"
)
3-7 テーマを変えフォントを指定する(theme関数群)
# ミニマルなテーマでフォントにIPAexGothicを使う
ggplot(mtcars ) +
aes(wt , mpg ) +
geom_point() +
theme_minimal(base_family = " IPAexGothic" )
# グラフのテーマをggThemeAssistパッケージを使って調整する
g <- ggplot(mtcars ) + aes(wt , mpg ) + geom_point()
ggThemeAssist :: ggThemeAssistGadget(g )
# デフォルトフォントをIPAexゴシックに変更する
theme_set(theme_gray(base_family = " IPAexGothic" ))
library(magrittr )
systemfonts :: system_fonts()$ family %> %
unique %> %
stringr :: str_subset(" IPA" )
# ggplotオブジェクトを変数に保存
g <- ggplot(mtcars ) +
aes(wt , mpg ) +
geom_point()
# ggplotオブジェクトを5cm四方の画像に保存
ggsave(
filename = " mtcars.png" ,
plot = g ,
width = 5 ,
height = 5 ,
units = " cm"
)
ggsave(" example.png" , g , device = ragg :: agg_png )
# 車の重量と燃費の比較
# 前処理: 行名をmodel列に変換する
motor_cars <- tibble :: rownames_to_column(mtcars , " model" )
# 散布図の作成
g <- ggplot(motor_cars ) +
aes(wt , mpg , label = model ) +
geom_point()
# (a) 散布図上のすべての点に車種名をラベリングする
g + ggrepel :: geom_text_repel()
# (b) 散布図上の燃費が良い車種をラベリングする
g + ggrepel :: geom_text_repel(
data = function (x ) dplyr :: slice_max(x , mpg , n = 5 )
)
# 2 * x ^ 2 + x + 1
# # 関数を定義せずx = 3とx = 5の場合を計算
f_x3 <- 2 * 3 ^ 2 + 3 + 1
f_x5 <- 2 * 5 ^ 2 + 5 + 1
# 2 * x ^ 2 + x + 1
# # 関数を定義してx = 3とx = 5の場合を計算
quadratic <- function (x ) {
2 * x ^ 2 + x + 1
}
f_x3 <- quadratic(x = 3 )
f_x5 <- quadratic(5 ) # 実行時の引数名は省略可能
# mtcarsの任意の列を選んで箱ひげ図にする関数(失敗例)
boxplot_mtcars_ng <- function (x ) {
ggplot(mtcars ) +
aes(x ) +
geom_boxplot()
}
boxplot_mtcars_ng(wt )
# mtcarsの任意の列を選んで箱ひげ図にする関数(成功例1)
# # aes関数と同様に引用符を使わず列を選択
boxplot_mtcars_ok1 <- function (x ) {
ggplot(mtcars ) +
aes({{ x }}) + # aes(x) を aes({{ x }}) に修正
geom_boxplot()
}
# # 箱ひげ図の表示
boxplot_mtcars_ok1(wt )
# mtcarsの任意の列を選んで箱ひげ図にする関数(成功例2)
# # 文字列で列を選択
boxplot_mtcars_ok2 <- function (x ) {
ggplot(mtcars ) +
aes(.data [[x ]]) + # aes(x) を aes(.data[[x]]) に修正
geom_boxplot()
}
# # 箱ひげ図の表示
# # 結果は `boxplot_mtcars_ok1(wt)` と同じなので省略
boxplot_mtcars_ok2(" wt" )
# mtcarsの複数の列に対し箱ひげ図をプロット(結果省略)
for (x in c(" wt" , " mpg" )) {
print(
boxplot_mtcars_ok2(x )
# または boxplot_mtcars_ok1(.data[[x]])
)
}
g <- ggplot(ChickWeight ) +
aes(Time , weight , color = Diet , group = Chick ) +
geom_line() +
geom_point()
# (a) gghighlightパッケージ未使用時
g
# (b) gghighlightパッケージにより餌2を強調
g + gghighlight :: gghighlight(Diet == 2 )
# gghighlightパッケージによる出力の見た目を変える
g +
gghighlight :: gghighlight(
Diet == 2 ,
unhighlighted_params = list (color = " white" ),
use_direct_label = FALSE ,
keep_scales = TRUE
)
# 車の重量と燃費の比較
# gghighlight関数を用いて燃費の良い車種を強調
# 前処理: 行名をmodel列に変換する
motor_cars <- tibble :: rownames_to_column(mtcars , " model" )
# ベースとなる散布図の作成
g <- ggplot(motor_cars ) +
aes(wt , mpg ) +
geom_point()
# (a) 燃費が上位の車種を強調
g +
gghighlight :: gghighlight(
rank(- mpg , ties.method = " min" ) < = 5
)
# (b) 燃費が上位の車種にラベルを付け、他を濃い灰色にする
g +
gghighlight :: gghighlight(
rank(- mpg , ties.method = " min" ) < = 5 ,
label_key = model , # 強調対象にラベルを付ける
unhighlighted_params = list (
color = " gray50" ) # 強調対象外を濃い灰色にする
)
# gghighlightを用いないデータの強調(コードのみ)
ggplot(motor_cars ) +
aes(wt , mpg ) +
geom_point(color = " gray80" ) +
geom_point(
color = " black" ,
data = function (x ) dplyr :: slice_max(x , mpg , n = 5 )
)
変数間の関係を把握するために散布図を並べる(facet_wrap
関数)
# ダイヤモンドの色合いごとに、カラット数と価格を比較
ggplot(diamonds ) +
aes(carat , price ) +
geom_point() +
facet_wrap(
vars(color ), # 分割する基準となる変数を指定
nrow = 1 , # 分割する行数を指定(省略可)
ncol = 7 # 分割する列数を指定(省略可)
)
# データの変形
# price列以外のnumeric型の列の値をx_value列にまとめ、
# x_value列のどの値がどの列由来かx_title列に記録する
diamonds_price_vs_others <- diamonds %> %
tidyr :: pivot_longer(
where(is.numeric ) & ! price ,
names_to = " x_title" ,
values_to = " x_value"
)
# 結果の確認
str(diamonds_price_vs_others )
# ダイヤモンドの価格と価格以外の数値の関係を
# 複数の散布図にプロットして並べる
ggplot(diamonds_price_vs_others ) +
aes(x_value , price , color = color ) +
geom_point() +
facet_wrap(
vars(x_title ),
scales = " free_x" # x軸の範囲を固定しない
)
関連するグラフを1枚にまとめる(patchworkパッケージ)
# 3つのグラフをpatchworkパッケージを使って並べた例
library(patchwork )
g <- ggplot(diamonds ) + aes(price ) + geom_density()
g | (g / g )
# 散布図にy軸の周辺分布を追加する
library(patchwork )
# 並べたいグラフに共通のレイヤ
gg_base <- ggplot(diamonds ) +
coord_cartesian(ylim = range(diamonds $ price ))
# 散布図の作成
gg_scatter_carat_vs_price <- gg_base +
aes(carat , price , color = color ) +
geom_point(show.legend = FALSE )
# 周辺分布(ヒストグラム)の作成
gg_hist_price <- gg_base +
aes(y = price , fill = color ) +
geom_histogram(bins = 30 )
gg_scatter_carat_vs_price | gg_hist_price
# グラフのサイズ比を指定する
patchwork :: wrap_plots(
list ( # 並べたいグラフのリスト
gg_scatter_carat_vs_price ,
gg_hist_price
),
ncol = 2 , # 2列に並べる。余りは改行
widths = c(3 , 1 ) # 1列目と2列目の幅の比を3:1にする
) +
patchwork :: plot_annotation(
title = " ダイヤモンドの価格とカラット数の関係" ,
tag_levels = " a" , # a, b,...とタグ付け
tag_prefix = " (" , tag_suffix = " )" # タグを括弧で囲う
)
相関を見るために散布図に色を付ける(patchworkパッケージ)
# 表示色にマッピングする列を変更しながら
# diamondsデータセットのカラット数と価格を比較
# 散布図を描写する関数
scatter_diamonds <- function (color = " cut" ) {
ggplot(diamonds ) +
aes(
carat , price ,
color = .data [[color ]] # 後述
) +
geom_point()
}
# diamondsデータセットの中からfactor型の列名を抽出し、
# それぞれを散布図の色に割り当てたグラフを作成し、
# patchworkパッケージで1枚にまとめる
diamonds %> %
select(where(is.factor )) %> % # factor型の列を選択
names %> % # 選択中の列名を抽出
purrr :: map(scatter_diamonds ) %> % # さまざまな列を表示色にマッピング
# 出力はグラフのリスト
patchwork :: wrap_plots(ncol = 1 ) # リストを1枚のグラフにまとめる
コラム:facet_wrap
関数で分割したグラフの書式を整理
# stripをx軸タイトルに変更する
ggplot(diamonds_price_vs_others ) +
aes(x_value , price , color = color ) +
geom_point() +
lemon :: facet_rep_wrap( # (A)
vars(x_title ),
scales = " free_x" ,
repeat .tick.labels = TRUE , # (A.1)
strip.position = " bottom" # (B)
) +
theme_classic() +
theme( # (C)
strip.placement = " outside" , # (C.1)
strip.background = element_blank(), # (C.2)
strip.text = element_text(size = rel(1.1 )), # (C.3)
axis.title.x = element_blank() # (C.4)
)
# 対話的に操作可能なグラフの作成
gg_diamonds <- ggplot(diamonds ) +
aes(x = carat , y = price , color = color ) +
geom_point()
plotly :: ggplotly(gg_diamonds )
# マウス操作で見てきたグラフをggplot2パッケージで再現
# # carat列が0.2から1、price列が0から5000の範囲を拡大
gg_diamonds +
coord_cartesian(xlim = c(0.2 , 1 ), ylim = c(0 , 5000 ))
# # color列がJな列を強調表示
gg_diamonds +
gghighlight :: gghighlight(color == " J" )