マクドナルドの損益計算書を取得します
2020年12月期(連結)の営業利益が312億9000万円と、9年ぶりに最高益を記録したマクドナルドの損益計算書(PL)のウォーターフォール図を作ってみました。
**「ggplot2」が装備する、矩形描画のための「geom_rect」**を使います。
※プログラム言語初心者レベルなので、冗長性のあるコードになっているかもしれません。ご容赦ください。
ウォーターフォール図作成の参考にしたのは
https://qiita.com/tayohei@github/items/1a19e1b5a05dccfa8c71
https://www.jigsawacademy.com/waterfall-charts-using-ggplot2-in-r/
の2つです。
マクドナルドの決算データはこちらから取得しました(単位:百万円)。
https://www.mcd-holdings.co.jp/ir/summary/#hd_summary_05
支出はマイナスにしました。

一応、確認のための計算をしました。
サイトにある数字は十万円以下が丸められているので、確認した数字の最後の桁が微妙に異なりますが、このまま使います。

データフレーム型にします。
pl_data <- data.frame(
items = c("売上高", "売上原価", "販売費及び一般管理費", "営業外収益", "営業外費用", "特別利益", "特別損失", "法人税住民税及び事業税", "法人税等調整額", "当期純利益"),
amount = c(288332, -230075, -26966, 1421, -1286, 0, -870, -10140, -226, 20186),
stringsAsFactors=F
)
pl_data #データ確認
items amount
1 売上高 288332
2 売上原価 -230075
3 販売費及び一般管理費 -26966
4 営業外収益 1421
5 営業外費用 -1286
6 特別利益 0
7 特別損失 -870
8 法人税住民税及び事業税 -10140
9 法人税等調整額 -226
10 当期純利益 20186
「ggplot2」用にデータを加工します
今回は**「ggplot2」**を使います。
データの加工をします。
# ggplot2に適用するためのデータ加工
# seq_along()はデータセットのインデックス化したベクトルを返
# データフレームの場合は列単位。リストの場合はリスト単位
pl_data$items <- as.factor(pl_data$items) #ファクター型に変換
pl_data$id <- seq_along(pl_data$amount) #上記参照
pl_data$type <- ifelse(pl_data$amount > 0, "収入", "支出") #「収入」「支出」がわかる列を追加
# items列の"売上高", "営業外損益"の行のtype列に"net" と追記。収入のネット金額
pl_data[pl_data$items %in% c("売上高", "営業外収益"), "type"] <- "net"
pl_data #データ確認
items amount id type
1 売上高 288332 1 net
2 売上原価 -230075 2 支出
3 販売費及び一般管理費 -26966 3 支出
4 営業外収益 1421 4 net
5 営業外費用 -1286 5 支出
6 特別利益 0 6 支出
7 特別損失 -870 7 支出
8 法人税住民税及び事業税 -10140 8 支出
9 法人税等調整額 -226 9 支出
10 当期純利益 20186 10 収入
累積値を追加します。
pl_data$end <- cumsum(pl_data$amount) #cumsum は累積
pl_data #データ確認
items amount id type end
1 売上高 288332 1 net 288332
2 売上原価 -230075 2 支出 58257
3 販売費及び一般管理費 -26966 3 支出 31291
4 営業外収益 1421 4 net 32712
5 営業外費用 -1286 5 支出 31426
6 特別利益 0 6 支出 31426
7 特別損失 -870 7 支出 30556
8 法人税住民税及び事業税 -10140 8 支出 20416
9 法人税等調整額 -226 9 支出 20190
10 当期純利益 20186 10 収入 40376
この後**「geom_rect」**を使い描画するので、矩形範囲を指定するための加工をします。
# end列に end列の1行目を外したものと、末尾に0を加えた ベクトルに差し替える
pl_data$end <- c(head(pl_data$end, -1),0)
pl_data #データ確認
items amount id type end
1 売上高 288332 1 net 288332
2 売上原価 -230075 2 支出 58257
3 販売費及び一般管理費 -26966 3 支出 31291
4 営業外収益 1421 4 net 32712
5 営業外費用 -1286 5 支出 31426
6 特別利益 0 6 支出 31426
7 特別損失 -870 7 支出 30556
8 法人税住民税及び事業税 -10140 8 支出 20416
9 法人税等調整額 -226 9 支出 20190
10 当期純利益 20186 10 収入 0
# start列に 0とend列の-1行目にしたベクトルに差し替える
pl_data$start <- c(0, head(pl_data$end, -1))
pl_data #データ確認
items amount id type end start
1 売上高 288332 1 net 288332 0
2 売上原価 -230075 2 支出 58257 288332
3 販売費及び一般管理費 -26966 3 支出 31291 58257
4 営業外収益 1421 4 net 32712 31291
5 営業外費用 -1286 5 支出 31426 32712
6 特別利益 0 6 支出 31426 31426
7 特別損失 -870 7 支出 30556 31426
8 法人税住民税及び事業税 -10140 8 支出 20416 30556
9 法人税等調整額 -226 9 支出 20190 20416
10 当期純利益 20186 10 収入 0 20190
# 列を並び替える
pl_data <- pl_data[, c(3,1,4,6,5,2)]
pl_data #データ確認
id items type start end amount
1 1 売上高 net 0 288332 288332
2 2 売上原価 支出 288332 58257 -230075
3 3 販売費及び一般管理費 支出 58257 31291 -26966
4 4 営業外収益 net 31291 32712 1421
5 5 営業外費用 支出 32712 31426 -1286
6 6 特別利益 支出 31426 31426 0
7 7 特別損失 支出 31426 30556 -870
8 8 法人税住民税及び事業税 支出 30556 20416 -10140
9 9 法人税等調整額 支出 20416 20190 -226
10 10 当期純利益 収入 20190 0 20186
pl_data_bkup <- pl_data #バックアップ用
**「str」**でデータの型を確認します。
str(pl_data)
'data.frame': 10 obs. of 6 variables:
$ id : int 1 2 3 4 5 6 7 8 9 10
$ items : Factor w/ 10 levels "営業外収益","営業外費用",..: 7 6 8 1 2 5 4 9 10 3
$ type : chr "net" "支出" "支出" "net" ...
$ start : num 0 288332 58257 31291 32712 ...
$ end : num 288332 58257 31291 32712 31426 ...
$ amount: num 288332 -230075 -26966 1421 -1286 ...
# なお、下記にすると、ggploto2実行時にエラーが出るfactor型でないといけない(後でtypeと併せてfactorに変換)
pl_data$items <- as.character(pl_data$items)
str(pl_data)
'data.frame': 10 obs. of 6 variables:
$ id : int 1 2 3 4 5 6 7 8 9 10
$ items : chr "売上高" "売上原価" "販売費及び一般管理費" "営業外収益" ...
$ type : chr "net" "支出" "支出" "net" ...
$ start : num 0 288332 58257 31291 32712 ...
$ end : num 288332 58257 31291 32712 31426 ...
$ amount: num 288332 -230075 -26966 1421 -1286 ...
pl_data$type <- as.factor(pl_data$type) #ファクター型に変換
pl_data$items <- as.factor(pl_data$items) #ファクター型に変換
str(pl_data)
'data.frame': 10 obs. of 6 variables:
$ id : int 1 2 3 4 5 6 7 8 9 10
$ items : Factor w/ 10 levels "営業外収益","営業外費用",..: 7 6 8 1 2 5 4 9 10 3
$ type : Factor w/ 3 levels "net","支出","収入": 1 2 2 1 2 2 2 2 2 3
$ start : num 0 288332 58257 31291 32712 ...
$ end : num 288332 58257 31291 32712 31426 ...
$ amount: num 288332 -230075 -26966 1421 -1286 ...
「ggplot2」と「geom_rect」を使います
**「geom_rect」**を使います。
xmin、xmax、ymin、ymaxで矩形範囲を指定しています。
library(ggplot2)
# geom_rect は 長方形描く。0.45+0.45の幅の長方形
# 0.5より小さければ矩形の間に隙間ができる
ggplot(pl_data, aes(items, fill=type)) + geom_rect(aes(x = items, xmin = id-0.45, xmax = id+0.45, ymin = end, ymax = start)) + theme_gray (base_family = "HiraKakuPro-W3")
# base_family = "HiraKakuPro-W3"は、Macでの文字化け回避用

しかし、このままだとx軸の表示順番が以下のようになっています(最後の行)。
順番を入れ替えます。
pl_data$items
[1] 売上高 売上原価 販売費及び一般管理費
[4] 営業外収益 営業外費用 特別利益
[7] 特別損失 法人税住民税及び事業税 法人税等調整額
[10] 当期純利益
10 Levels: 営業外収益 営業外費用 当期純利益 特別損失 特別利益 売上原価 ... 法人税等調整額
# ファクターの水準の順序を入れ替える
# http://cse.naro.affrc.go.jp/takezawa/r-tips/r/16.html
# 上記を参考に、factor関数でlevels引数を指定
pl_data$items <- factor(pl_data$items, levels=c("売上高", "売上原価", "販売費及び一般管理費", "営業外収益", "営業外費用", "特別利益", "特別損失", "法人税住民税及び事業税", "法人税等調整額", "当期純利益"))
pl_data$items #データ確認
[1] 売上高 売上原価 販管費 営業外損益 特別損益 税金 利益
Levels: 売上高 売上原価 販管費 営業外損益 特別損益 税金 利益
再度描画します。
※下記のように「Ignoring unknown aesthetics: x 」というメッセージが出るのですが、まだ調べがついていません。
※意図通りの可視化はできているので、このまま進めます。
# 再描画設定
options(scipen=100) #Y軸が指数表示になるのでそれを回避
pl_plot <- ggplot(pl_data, aes(items, fill=type)) + geom_rect(aes(x = items, xmin = id-0.45, xmax = id+0.45, ymin = end, ymax = start)) + theme_gray (base_family = "HiraKakuPro-W3")+theme(axis.text.x = element_text(size = 6))
pl_plot

各バーにテキストを追加します。
# 矩形領域に文字を入れる
library("stringr")
pl_plot2 <- pl_plot + geom_text(aes( #文字追加。位置は以下で指定
x = id ,
y = (start+end)/2, #グラフの中央に文字を配置
label = str_c(items,"\n",amount),
family = "HiraKakuPro-W3" #Macでのプロット内ので文字化け防止
)
,size = 3,)+ labs(x = "", y = "amount", fill= "") #軸ラベル付与
# sizeの位置はgeom_text(aes(label=***), size=x.x)
# 描画実行
pl_plot2

了