論理の流刑地

地獄の底を、爆笑しながら闊歩する

【R備忘】ggplot2で不要な図内の余白を消したい時/凡例を一つにまとめたいとき、にどうするか

百回忘れたことに対して百一回目の忘却を防ぐだけのためのメモ
いやーggplotはありがたいパッケージではあるんだけど、毎日使うわけじゃないから細かい設定とかを忘れがち


不要な図内の余白を消す

例によって{panelr}パッケージのWageDataをつかう。
このデータに含まれている変数から、対数変換済賃金(lwage)をY軸に、週当たり労働時間(wks)をX軸にプロットすることを考えよう。
このデータは、労働時間5h以上の労働者を対象としているので、X軸でx < 5の部分はいらない。
ので、scale_x_conutuous() の引数limitsに下限5を設定して一度描画してみる

library( panelr)
data(WageData)
gg_tst1 <- ggplot(data= WageData ,
                  mapping = aes( x = wks , y = lwage)) +
          theme_light(base_family = "Meiryo")+
          scale_x_continuous(  breaks = seq( 5, 55 , by = 5)) +
          geom_point( shape=18 , color = "firebrick4" ) + labs(title="Test1")

できあがったグラフは以下のようになる

定義上値が存在しないはずのx <5 の部分も図に含まれてしまっていて、気持ちが悪い。

こういうときは、引数expandにc(0,0)を指定すると、limitsに指定した上限/下限値で図の表示領域を区切ることができる

gg_tst2 <- ggplot(data= WageData ,
                  mapping = aes( x = wks , y = lwage)) +
          theme_light(base_family = "Meiryo")+
          scale_x_continuous(  breaks = seq( 5, 55 , by = 5), limits = c( 5, 55),
                               expand= c(0,0)) +
          geom_point( shape=18 , color = "firebrick4" ) + labs(title="Test1")

きちんと、想定通りの表示になっている。

凡例をひとつにまとめる

scale_xxx_manual()などを使って、

  • 散布図の各点のshape
  • 折れ線グラフの線の形状(Ex. 実線, 破線, 点線..)
  • 点・線の色

などを各属性ごとに指定していくと、凡例が分裂してしまったりすることがある。

たとえば、以下のように学歴三段階(高/中/低)、性別(男/女)別に賃金の推移を折れ線グラフで確認するとする
このとき、何も考えないで適当にコードを書いてしまうと、以下のように凡例が分裂してしまうことがある。

#教育年数から学歴カテゴリをつくる
WageData <- WageData %>%
  mutate( ed3  = case_when( 
    ed <= 9 ~ 1 , 
    ed %in% 10:12 ~ 2,
    ed > 12 ~ 3), 
    Sex = if_else( fem == 1 , "Female", "Male")) 

#学歴× 性別の6グループでの平均賃金を求める
dfWage <- WageData %>% group_by(
            Sex , ed3) %>%
        summarize( N = n() ,
                   lwageM = mean( lwage , na.rm=T)) %>%
        as.data.frame()


gg_tst3 <- ggplot( data = dfWage,
                   mapping= aes( x = ed3 ,  group = Sex,
                                 y = lwageM, color = Sex ,
                                 linetype= Sex )) +
            theme_light( base_family = "Meiryo") +
            scale_x_continuous(breaks=1:3 ) + 
            geom_line( size = 0.9) + 
            scale_color_manual( breaks= c("Female", "Male"),
                                values = c("firebrick4", "darkblue"), 
                                name = "性別") +
            scale_linetype_manual( breaks = c( "Female","Male"),
                                values = c("dashed", "solid")
                                )

こういうときに、焦ってると何を修正すればいいんだっけ?ってなる。
結論からいうと、以下のふたつが必要である

  1. 同じ変数をマッピングでのそれぞれの属性(具体的には、mapping=aes(color = XXX , linetype=XXX)のとこ)に指定しているのであれば、scale_xxx_manual側で以下属性に指定する値が揃うようにする
    • name(凡例タイトル)
    • labels(凡例における各値のラベル)
    • breaks(値を指定するための水準)
  2. もしcolor=XXXと、linteype=XXXに指定している変数が違うのであれば、組み合わせ水準をinteraction()で作成してcolorとlinetype双方で指定する

colorの指定とlinetypeの指定に使っている変数が異なるときは、
interaction(sex , age)のように二要因の組み合わせ水準をmappingに指定してから、
各値をscale_xxx_manual()のvaluesで指定すればいい(以下URL参照)

※参考
stackoverflow.com

修正すると、以下のように凡例がひとつにまとまる

gg_tst3_2 <- ggplot( data = dfWage,
                   mapping= aes( x = ed3 ,  group = Sex,
                                 y = lwageM, color = Sex ,
                                 linetype= Sex )) +
            theme_light( base_family = "Meiryo") +
            scale_x_continuous(breaks=1:3 ) + 
            geom_line( size = 0.9) + 
            scale_color_manual( breaks= c("Female", "Male"),
                                values = c("firebrick4", "darkblue"), 
                                name = "性別",
                                labels = c("女","男")) +
            scale_linetype_manual( breaks = c( "Female","Male"),
                                values = c("dashed", "solid"),
                                name = "性別",
                                labels = c("女","男")
                                )


求める出力となっている


www.youtube.com


Enjoy!