読者です 読者をやめる 読者になる 読者になる

Mukku John Blog

取り組んでいること を つらつら と

ggplot2パッケージを使って、棒グラフを作成してみる-3

Rグラフィックスクックブック 棒グラフ

R グラフィックス クックブック 6回目

ggplot2パッケージを利用して、棒グラフを作成していきます。
この2つを対象にします。

  • 棒グラフにラベルを追加する
  • (Cleveland)ドットプロット

棒グラフにラベルを追加する

利用するデータ

このキャベツデータを使います。

> head(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
ラベル付きの棒グラフ

まずマッピングとグラフの種類を指定します。

#x軸に日付と品種、y軸に重さを指定する
cabbageMap <- ggplot(cabbage_exp,aes(x=interaction(Date,Cultivar),y=Weight))
#幾何オブジェクトに、棒グラフを指定する
chartType <- geom_bar(stat="identity")

そしてラベルを指定します。

#色が白で、位置が1.5
chartLabel <- geom_text(aes(label = Weight), vjust=1.5,colour = "white")

描画します。

> cabbageMap + chartType + chartLabel

f:id:MukkuJohn:20160821110356p:plain

ラベルの位置

ラベルの位置は、vjustで指定します。
vjustの基本位置は、棒の上端が基本位置になります。

#vjust=0が棒の上端を指す。正の値が棒の下/負の値が棒の上を指す
geom_text(aes(label = Weight), vjust=1.5,colour = "white")

ラベルを棒の上に変更します。

#ラベル位置を棒の上部に設定し、ラベルテキストの色を黒に
> chartLabelOver <- geom_text(aes(label = Weight), vjust=-0.2,colour = "black")
#グラフを描画する
> cabbageMap + chartType + chartLabelOver

f:id:MukkuJohn:20160821110859p:plain
y軸はマッピングされた値で設定されるので、棒の高さによっては、
ラベルが見切れてしまう事に注意が必要です。

ラベルを見切れない位置に設定する

このラベルを見切れないための対策は2つです。

  • y軸を伸ばす
  • 棒のある一定の上側に配置する

上記の2種を比較しやすくするために、
コードの重複部分を、1つのオブジェクトに格納します。

cabbageBarChart <- cabbageMap + chartType
  • y軸を伸ばす方法

y軸を、重さ値の1.05倍まで表示して、ラベル位置を上端から0.2上に位置させます。

cabbageBarChart + 
  geom_text(aes(label = Weight), vjust = -0.2) +
  ylim(0, max(cabbage_exp$Weight) * 1.05)

f:id:MukkuJohn:20160821112212p:plain

  • 棒のある一定の上側に配置する

ラベル位置を重さ値の0.1多い位置に位置させます。

cabbageBarChart +
  geom_text(aes(label = Weight, y = Weight + 0.1))

f:id:MukkuJohn:20160821112307p:plain

どちらも同じに見えるかもしれませんが、
後者の棒のある一定の上側に配置するはあまりお勧めできません。
というのも、Weightの値によって、+ 0.1の部分を変更しないといけないためです。

ラベル付きのグループ化された棒グラフ

グループ化された棒グラフにラベルを付ける際には、下記2つに注意します。

  • ラベルのずらしを指定する
  • ラベルのフォントサイズを指定する

デフォルトのグループ化された棒グラフを作成します。

#マッピングと幾何オブジェクトを指定する
cabbageGroupedBarChart <-
  ggplot(cabbage_exp, aes(x = Date, y=Weight, fill=Cultivar)) +
  geom_bar(stat = "identity", position = "dodge")
#グラフを描画する
cabbageGroupedBarChart

f:id:MukkuJohn:20160821114401p:plain

  • ラベルを指定する

ずらしや、フォントサイズの指定をせずにラベルを表示させます。

cabbageGroupedBarChart +
  geom_text(aes(label = Weight), vjust = 1.5, colour = "white")

f:id:MukkuJohn:20160821114616p:plain
ラベルが、グループ化されたx軸の真ん中に来ています。
これでは何だか分からないので、ラベルのずらしを検討します。

  • ラベルのずらしを指定する

ラベルをずらす前に、グループ化された棒グラフの成り立ちを考えます。
幾何オブジェクト部分

#上記コードで、幾何オブジェクトを表す部分
geom_bar(stat = "identity", position = "dodge")

この幾何オブジェクトの指定は、position="dodge"としているので、
幾何オブジェクト自体が、「ずらし」で成り立っていることが分かります。
つまり、ラベルも「ずらし」で指定すれば、棒に重ねて表示できます。

そして、この「ずらし」のデフォルト値ですが、0.9です。

#このコードは、position = "dodge"と同じ
geom_bar(stat = "identity", position = position_dodge(0.9))

上記を踏まえ、ラベルのずらしを指定したグラフがこちらです。

cabbageGroupedBarChart +
  geom_text(aes(label = Weight), vjust = 1.5, colour = "white", position = position_dodge(0.9))  

f:id:MukkuJohn:20160821122754p:plain

  • ラベルのフォントサイズを指定する

棒が多くなりにつれ、棒の幅が狭くなっていきます。
(これは極端な例です。そもそも見えないので、可視化の目的を達成してないです。)
f:id:MukkuJohn:20160813202614p:plain

そのため、棒の幅に合わせて、ラベルのフォントサイズを指定する必要があります。
フォントサイズは、sizeで指定します。(デフォルトは5です。)

cabbageGroupedBarChart +
  geom_text(aes(label = Weight), vjust = 1.5, colour = "white", 
            position = position_dodge(0.9),
            size = 10)

f:id:MukkuJohn:20160821123327p:plain

ラベル付きの積み上げ棒グラフ

積み上げのグループ毎に、累積和を算出する必要があります。

下のグラフは、x軸は日付で、グループ化は品種で、y軸に重さが図示しています。
下記を例にとると、日付d16でグループ化されている品種c39・c52毎の、重さ累積和が必要です。

cabbageGroupedMap <- ggplot(ce,aes(x=Date,y=Weight,fill=Cultivar))
cabbageGroupedMap + geom_bar(stat="identity")

f:id:MukkuJohn:20160821124219p:plain

上記のような、○○毎に△△の値を集計するためには、
この記事でも使用したplyrパッケージを利用します。
mukkujohn.hatenablog.com

library(plyr)
ce <- ddply(cabbage_exp,"Date",transform,label_y=cumsum(Weight))
> ce
  Cultivar Date Weight        sd  n         se label_y
1      c39  d16   3.18 0.9566144 10 0.30250803    3.18
2      c52  d16   2.26 0.4452215 10 0.14079141    5.44
3      c39  d20   2.80 0.2788867 10 0.08819171    2.80
4      c52  d20   3.11 0.7908505 10 0.25008887    5.91
5      c39  d21   2.74 0.9834181 10 0.31098410    2.74
6      c52  d21   1.47 0.2110819 10 0.06674995    4.21

label_y列が、Dateで区切り、Cultivarの累積和になります。

ラベル無しでグラフを表示します。

cabbageBuildupBarChart <- ggplot(ce,aes(x=Date,y=Weight,fill=Cultivar)) +
  geom_bar(stat="identity")
cabbageBuildupBarChart

f:id:MukkuJohn:20160821124908p:plain

ラベルを付与して表示します。

cabbageBuildupBarChart +
  geom_text(aes(y = label_y, label = Weight), vjust = 1.5,colour = "white", size = 7)

f:id:MukkuJohn:20160821125146p:plain
aesのy引数に、事前に算出した累積和を指定しています。

このy引数を指定して、位置を分からせてあげないとこんなグラフになります。
f:id:MukkuJohn:20160821125435p:plain
ラベルを表示するy位置に、fill値に指定されたCultivar毎のweight値を使っています。

表示するy位置を変更すれば、ラベルを棒の上下真ん中に配置することができます。

ce <- ddply(ce,"Date",transform,label_y=cumsum(Weight)-0.5*Weight)

f:id:MukkuJohn:20160821130210p:plain

あとは、人の好みで、お好きなように外観をいじります。

cabbageBuildupBarChart +
  geom_text(aes(y=label_y, label=paste(format(Weight, nsmall = 2),"kg")), size=5, colour="black") +
  guides(fill=guide_legend(reverse = TRUE)) +
  scale_fill_brewer(palette = "Pastel1")

f:id:MukkuJohn:20160821130457p:plain

(Cleveland)ドットプロット

この様なグラフが、ドットプロットと言います。
f:id:MukkuJohn:20160821131545p:plain

なぜ棒グラフと、同じカテゴリで扱っているのかといいますと、
この棒グラフ代替と言えるからっぽいです。*1
f:id:MukkuJohn:20160821131740p:plain
確かに、塗りつぶす必要性が感じられないですね。

利用するデータ

2001年のメジャーリーグの選手データです。
ここから25人に限り、name・lg・avg列を使用します。

library(gcookbook)
tophit <- tophitters2001[1:25,c("name","lg","avg")]
head(tophit)
            name lg    avg
1   Larry Walker NL 0.3501
2  Ichiro Suzuki AL 0.3497
3   Jason Giambi AL 0.3423
4 Roberto Alomar AL 0.3357
5    Todd Helton NL 0.3356
6    Moises Alou NL 0.3314
並び替えと見た目の調整

上述のグラフは,y軸の下からnameのアルファベット順になっています。
着目している値は、avgですので、avg順に並び替えます。

ggplot(tophit,aes(x=avg, y=reorder(name, avg))) + geom_point()

f:id:MukkuJohn:20160821132932p:plain

ドットを大きくして、背景・目盛り線を変更します。

ggplot(tophit,aes(x=avg, y=reorder(name, avg))) + 
#ドットサイズを指定する
  geom_point(size = 3) +
#背景を変更する
  theme_bw() +
#目盛り線を変更する
  theme(panel.grid.major.x = element_blank(),
        panel.grid.minor.y = element_blank(),
        panel.grid.major.y = element_line(colour = "grey60",linetype = "dashed"))

f:id:MukkuJohn:20160821133917p:plain

x軸とy軸を入れ替える

x軸とy軸は、マッピングの指定部分で入れ替えるだけです。
x軸の名前が横に表示されると重なって見えないため、角度をつけています。

#x軸とy軸にバインドしている値を入れ替える
ggplot(tophit,aes(x=reorder(name, avg), y=avg)) + 
  geom_point(size = 3) +
  theme_bw() +
#x軸のテキストを60°つけて表示する
  theme(axis.text.x = element_text(angle = 60, hjust = 1),
        panel.grid.major.x = element_blank(),
        panel.grid.minor.y = element_blank(),
        panel.grid.major.y = element_line(colour = "grey60",linetype = "dashed"))

f:id:MukkuJohn:20160821134334p:plain

グループ化する

所属しているリーグ毎にグループ化したいと思います。
グループ化するためには、ファクタを使います。

まず、リーグ毎に、avg順に名前を並び替えます。

nameOrder <- tophit$name[order(tophit$lg,tophit$avg)] 

次に、マッピングされるデータを、順序のレベルを持つファクタに変更します。

tophit$name <- factor(tophit$name,levels = nameOrder)

そのデータを利用して、ドットプロットを描画します。

ggplot(tophit, aes(x = avg, y = name)) + 
  geom_point(size = 3, aes(colour = lg)) +
  theme_bw() +
  theme(panel.grid.major.y = element_blank())

f:id:MukkuJohn:20160821140926p:plain

ドットプロットの見た目の変更

凡例をグラフ内に押し込めます。

ggplot(tophit, aes(x = avg, y = name)) + 
  geom_point(size = 3, aes(colour = lg)) +
  theme_bw() +
  theme(panel.grid.major.y = element_blank(),
        legend.position = c(1, 0.55), #凡例の位置を指定する
        legend.justification = c(1, 0.55))

f:id:MukkuJohn:20160821141146p:plain

それぞれの点にy軸から線を描画してみます。

ggplot(tophit, aes(x = avg, y = name)) + 
  geom_point(size = 3, aes(colour = lg)) +
  geom_segment(aes(yend = name), xend = 0, colour = "black") + 
  theme_bw() +
  theme(panel.grid.major.y = element_blank(),
        legend.position = c(1, 0.55),
        legend.justification = c(1, 0.55))

f:id:MukkuJohn:20160821141351p:plain

パレットを変更します。

ggplot(tophit, aes(x = avg, y = name)) + 
  geom_segment(aes(yend = name), xend = 0, colour = "black") +
  geom_point(size = 3, aes(colour = lg)) +
  scale_colour_brewer(palette = "Set1", limits = c("NL","AL")) +
  theme_bw() +
  theme(panel.grid.major.y = element_blank(), 
        legend.position = c(1, 0.55),
        legend.justification = c(1, 0.55))

f:id:MukkuJohn:20160821141752p:plain

グループ化について、ファセットを使う手段もあります。

ggplot(tophit, aes(x = avg, y = name)) + 
  geom_segment(aes(yend = name), xend = 0, colour = "black") +
  geom_point(size = 3, aes(colour = lg)) +
#凡例表示をやめる
  scale_colour_brewer(palette = "Set1", limits = c("NL","AL"), guide = FALSE) +
  theme_bw() +
  theme(panel.grid.major.y = element_blank()) +
#ファセットグリッドを表示する
  facet_grid(lg ~., scales = "free_y", space = "free_y")

f:id:MukkuJohn:20160821142114p:plain


棒グラフの描画について、3回にかけて触れてきました。
次回からは、折れ線グラフを作成していきたいと思います。