Edited at

ggplot2で100%積み重ね棒グラフの真ん中に値を表示させたい


はじめに

Rのggplot2で棒グラフを作成する際数字を入れたい場面があります。

やり方をいつも忘れてしまうので、いつもkaztanさんの記事やR Graphics Cookbook, 2nd editionを参考にさせて頂いています。ただこの方法はposition = "stack"の積み上げ棒グラフで、縦軸はカウントデータになっています。

position = "fill"の100%積み上げ棒グラフでも数値を真ん中に配置する方法を調べようとしたのですが、google検索の上位表示に出てきませんでした。

今回は備忘録のために自分が行った方法を紹介します。


ライブラリの読み込み

#tidyverseパッケージを使ったことがなければインストールします

if(!require(tidyverse)) install.packages("tidyverse", repos = "http://cran.us.r-project.org")

#既にtidyverseパッケージをインストールしている方はライブラリで読み込みます
library(tidyverse)

今回はggplot2を使うためにtidyverseパッケージを使います。


データの作成

#データ作成

set.seed(2019)
sex <- sample(c("male", "female"), size = 200, replace = TRUE)
category <- sample(c("A","B","C","D"), size = 200, prob = c(0.2, 0.3, 0.4, 0.1), replace = TRUE)
dat <- data.frame(sex, category)
rm(sex, category)
summary(dat)

#結果

sex category
female: 91 A:33
male :109 B:63
C:90
D:14

#積み上げ棒グラフ(position = "fill")

dat %>%
group_by(sex, category) %>%
summarize(count = n()) %>%
arrange(sex, desc(category)) %>%
mutate(label_y = (cumsum(count) - 0.5 * count) / sum(count)) %>%
ggplot2::ggplot(aes(x = sex))+
geom_bar(aes(y = count, fill = category), stat = "identity", position = "fill")+
geom_text(aes(label = count, y = label_y))+
scale_y_continuous(labels = scales::percent)

group_bysummarize関数で集計した後グラフを作成しています。

棒グラフを作るのはgeom_bar、数値はgeom_textを用いています。


ポイント1

geom_bar関数で作る棒グラフはカテゴリーの順番毎に上から並びます。

cumsum関数で累積和を求めるのですが、そのまま行うと累積和の順番が逆になります。

そのためarrange(sex, desc(category))で逆順にしています。

#arrangeを使わなかった場合

dat %>%
group_by(sex, category) %>%
summarize(count = n()) %>%
mutate(label_y = (cumsum(count) - 0.5 * count) / sum(count))
>
sex category count label_y
<fct> <fct> <int> <dbl>
1 female A 16 0.0879
2 female B 31 0.346
3 female C 36 0.714
4 female D 8 0.956
5 male A 17 0.0780
6 male B 32 0.303
7 male C 54 0.697
8 male D 6 0.972

#arrangeを使った場合

dat %>%
group_by(sex, category) %>%
summarize(count = n()) %>%
arrange(sex, desc(category)) %>%
mutate(label_y = (cumsum(count) - 0.5 * count) / sum(count))
>
sex category count label_y
<fct> <fct> <int> <dbl>
1 female D 8 0.0440
2 female C 36 0.286
3 female B 31 0.654
4 female A 16 0.912
5 male D 6 0.0275
6 male C 54 0.303
7 male B 32 0.697
8 male A 17 0.922


ポイント2

通常の積み上げ棒グラフであればmutate(label_y = cumsum(count) - 0.5 * count)で高さを求めます。

100%積み上げ棒グラフの場合は、上で求めた値をsum(count)で割ることで割合になります。


まとめ

色々書いたのですが、結果通常の積み上げ棒グラフで行う方法に対しsum()で割ればよいという話でした。


参考

ggplot2で積み重ね棒グラフに値を表示させたい

R Graphics Cookbook, 2nd edition