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

Data Science by R and Python

統計学を、広く、深く、わかりやすく。

(番外編1)Rを使ったグラフィック -ggplot2でウォーターフォール図-

Rのグラフィックでウォーターフォールチャートを作成しよう!

さて、今回はRでまさかのウォーターフォールチャートを作成するという完全に趣味の領域の話をします。

ウォーターフォールチャートとは

まずは、Wikipediaから引用しましょう。

滝グラフ(たきグラフ、英語:Waterfall chart)は正負の値の累積的影響を判断する際に役立つ可視化用グラフである。 レンガが宙に浮いているように列が表示されることから、飛行レンガグラフ(英語:flying bricks chart)やマリオ (ゲームキャラクター)グラフ(英語:Mario chart)として知られている。 戦略的コンサルティング会社であるマッキンゼー・アンド・カンパニーにより、顧客向けプレゼンテーション手法として普及した。[1][2] インベントリ分析や性能解析などの多様な定量分析にて利用されている。

まぁ、最初の一文だけで十分ですよね。「正負の値の累積的影響を判断する際に役立つ可視化用グラフ」です。

データの作成

まずは、仮想データを作成します。仮想データは以下のようなバランスシートを考えます。支出・収入などですね。これをウォーターフォールチャートで可視化します。

> #仮想データの構築
> balance <- data.frame(desc = c("Starting Cash","Sales", "Refunds", "Payouts", "Court Losses","Court Wins", "Contracts", "End Cash"), amount = c(2000,3400, -1100, -100, -6600, 3800, 1400, 2800))
> 
> #結果の表示
> balance
           desc amount
1 Starting Cash   2000
2         Sales   3400
3       Refunds  -1100
4       Payouts   -100
5  Court Losses  -6600
6    Court Wins   3800
7     Contracts   1400
8      End Cash   2800


さて、ウォーターフォールチャートではグラフの始点と終点が必要です。それを次にデータフレームとして作成する必要があります。具体的な手順は下のコマンドの通りです。

> #まずは、balance$descをfactorにする(図をかくために)
> balance$desc = factor(balance$desc,levels=balance$desc)
> 
> #idリストを作成
> balance$id = seq_along(balance$amount)
> 
> #収入か、支出かを判別する変数を構築
> balance$type = ifelse(balance$amount >0,"in","out")
> 
> #balance$descの最初と最後のtype変数に"net"を入れる(支出・収入ではない)。
> balance[balance$desc %in% c("Starting Cash", "End Cash"),"type"] <- "net"
> 
> #各数値を計算した後の値を作成する。
> #cumsumは1,2,3なら、1, (1)+2, (1+2)+3と計算するような関数
> balance$end = cumsum(balance$amount)
> 
> #balance$endの最後の項を0に変更
> #head(x,-1)で最後の1項を除いたベクトル
> balance$end = c(head(balance$end,-1),0)
> 
> #startはbalance$endの1つ前の項の値である。
> #i+1番目の始点の値 = i番目のendの値である
> balance$start = c(0,head(balance$end,-1))
> 
> #変数の表示順番を整える(しなくてもok)
> balance = balance[,c(3,1,4,6,5,2)]
> 
> #データフレーム
> balance
  id          desc type start   end amount
1  1 Starting Cash  net     0  2000   2000
2  2         Sales   in  2000  5400   3400
3  3       Refunds  out  5400  4300  -1100
4  4       Payouts  out  4300  4200   -100
5  5  Court Losses  out  4200 -2400  -6600
6  6    Court Wins   in -2400  1400   3800
7  7     Contracts   in  1400  2800   1400
8  8      End Cash  net  2800     0   2800

さて、これを用いると、ウォーターフォールチャートは簡単に書けます。以下のようなggplotを行います。具体的に関数が何をしているのかは中に書いてあります。

#########
##plot###
#########

library(ggplot2)

#plot1
#geom_rectグラフの幅と高さを指定して描画する関数
#xmax-xminがグラフの幅です。・・・0.90です(このためうまく棒の間に空白が空きます)
#また、xmin, xmaxは棒の位置を表しています。ここでxmin=id-0.45,xmax=id+0.45としていますから、id=1のものは0.55 ~ 1.45のところに描かれます。(実際そうなってるはず), ymin, ymaxは棒の長さを示しています。ymin=startなので最初の棒は0 ~2000までの幅を取ります。
ggplot(balance,aes(desc,fill=type))+geom_rect(aes(x=desc,xmin=id-0.45,xmax=id+0.45,ymin=end,ymax=start))

結果はこのような図で得られました。
f:id:tomoshige_n:20140812015604p:plain

でも、なんだか下の変数が重なっていて見づらい。そこで、折り返して表示する方法を考えます。

#plot2
#文字列を折り返す関数を作成
strwr = function(str) gsub(" ","\n",str)

#上のものと同様にグラフを作成.
#scale_x_discrete:離散系の軸パラメータを変更する。ラベルをね。breaksは何で区切るか
ggplot(balance, aes(fill = type)) + geom_rect(aes(x = desc,xmin = id - 0.45, xmax = id + 0.45, ymin = end, ymax = start)) + scale_x_discrete("", breaks = levels(balance$desc),labels = strwr(levels(balance$desc))) 

すると、奇麗になります!

f:id:tomoshige_n:20140812015718p:plain

まとめ

今回は、少しマニアックにggplot2でウォーターフォールチャートを作ることに挑戦しました。参照した記事はこちらです。ggplot2: Waterfall Charts | Learning R。ただ、これの最後にある文字を入れるのが、うまくいかず...最後は挫折したのでここまでにします。いい方法があれば教えてください。それでは。