LoginSignup
6
4

More than 3 years have passed since last update.

ggplot2でウォータフォールチャート?滝グラフ?を描く

Last updated at Posted at 2019-08-22

売上とか利益とかでよく見るこんなグラフです。
ウォータフォールプロット?滝グラフ?とか呼ばれるらしいです。初めて知りました。
image.png

例えばこんなデータで。

# サンプルデータ
sanple_data <- data.frame(
    費目 = c("売上高", "売上原価",  "販管費", "営業外損益", "特別損益", "税金"),
    金額 = c(3251, -720, -420, -850, -281, -311),
    stringsAsFactors=F
)

image.png
※数字は適当です。

パッケージを使うと楽。

いろいろ調べていると、お手軽なパッケージありました。
https://rkabacoff.github.io/datavis/Other.html#waterfall-charts

# インストールして
install.packages("waterfalls")
library("waterfalls")

# こんな感じで。
waterfall(
    sanple_data, 
    calc_total=TRUE,  # 収支の差分のところを描画する
    total_axis_text = "利益", # そこの文字列
    total_rect_text_color="black", # そこの線の色
    total_rect_color="goldenrod1"  # そこの線の塗りつぶし
) 

実行すると、、
image.png

なるほどらくちん。でも、こまごました部分はオプションを付けていくスタンスで、
できればggplotでスパっと描けないものかと調べてみて、

ggplotで描く

作図用のデータ作って、geom_rect で描く感じ。
http://tomoshige-n.hatenablog.com/entry/2014/08/11/235816
https://gist.github.com/rentrop/36f07b67cb6c4b82088e2115fee2498f
などを参考にしました。

作図用のデータを作る。

# 作図用のデータ作成
tmp <- sanple_data %>% 
mutate(
    end = cumsum( 金額 ), # 上端
    start = dplyr::lag(end, default = 0), # 下端
    type = if_else( 金額 >=0,"収入","支出"), # 色分けのため
    id = seq(1, n())
) %>% 
bind_rows(summarise(., 費目 = "利益", 金額 =last(end), start = 0, end = last(end), id = n()+1L, type = "利益")) # 収支の差分のところ

image.png

こんな感じ。よく読めはなるほどだけど、元データの項目名以外はコピペでいけそう。

グラフを描く

library("tidyverse")

# 可視化
tmp %>% ggplot(aes(費目, fill = type)) + 
    geom_rect(aes(
        x = 費目 ,
        xmin = id-0.5, xmax= id+0.5, # 隙間なくするなら0.5、隙間空けるなら小さくする
        ymin = end, ymax= start 
    )) +
    geom_text(aes( # 文字を入れる
        x = id ,
        y = (start+end)/2, # グラフの中央に
        label = str_c(費目,"\n",金額) 
    )) +
    labs(x = "", y = "金額", fill= "")

image.png
できた!

facetで複数描画する。

ggplotで描きたかったのは、facet_wrapで複数一度に書けるんじゃないかなと思ったゆえで。
下記みたいなデータで、、

library(tidyverse)

# サンプルデータ
sanple_data <- data.frame(
    費目 = c(
        "売上", "売上原価",  "販管費", "営業外損益", "特別損益", "税金",
        "売上", "売上原価",  "販管費", "営業外損益", "特別損益", "税金",
        "売上", "売上原価",  "販管費", "営業外損益", "特別損益", "税金"
    ),
    金額 = c(
        3251, -720,  -420, -850, -281, -311,
        4728, -1650, -130, -250, -975, -535,
        2560, -320,  -540, -90,  -154, -241
    ),
    支店 = c(
        rep("西日本",6),
        rep("東日本",6),
        rep("海外",6)
    ),
    stringsAsFactors=F
)

image.png

グラフを描く

# 作図用のデータ作成
tmp <- sanple_data %>% 
group_by(支店)%>%   # ※ここを追記
mutate(
    end = cumsum( 金額 ),
    start = dplyr::lag(end, default = 0),
    type = if_else( 金額 >=0,"収入","支出"),
    id = seq(1, n())
) %>% 
bind_rows(summarise(., 費目 = "利益", 金額 =last(end), start = 0, end = last(end), id = n()+1L, type = "利益"))

# 可視化
tmp %>% ggplot(aes(費目, fill = type)) + 
    geom_rect(aes(
        x = 費目 ,
        xmin = id -0.45, xmax = id + 0.45,
        ymin = end, ymax = start
    )) +
    geom_text(aes(
        x = id ,
        y=(start+end)/2,
        label=str_c(費目,"\n",金額)
    )) +
    labs(x = "", y = "金額", fill="") +
    facet_wrap(~支店)   # ※ここを追記

image.png

できた!

6
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4