データ穴リストのブログ

すべては喰いっぱぐれないために

バブルチャートではなく四角でグラフ化~geom_rect()ってなんだ

バブルチャートもしくはバブルプロットは、 天下のExcel様でも作れますし、 「イケてるグラフ2008*1」にもノミネートされるほど便利なグラフで有名ですが、 残念なのはX軸、Y軸にZ軸を含めた3次元までしか表せないってところです。

ggplotであれば*2、 colour、shapeや、geom_path()なんかも含めると5次元まではいけます*3

ただ、size指定じゃ物足りない! もっと次元欲しい!

ってことで、これはついに自作geomの作成必要か…? と思ったら、フツーにありました。 geom_rect github.com

色んな説明にね、「矩形(くけい)」って書いてあったの。

読 め な い ★

コレ長方形ってことだったのね〜
お父さん35歳になって初めて知ったよ〜

長方形って書いて!!!(書いてあった)

とりあえずまずは公式の例をコピーして書いてみたけど、
なんかしっくりこない。
コレでやりたいこと出来るのか全くピンと来ない。
大体、geom_rectで検索して出てくる画像、コレだよ?
「geom_rect」の検索結果 - Yahoo!検索(画像)

anotateの進化版?みたいな。いや実際そういうことがしたかったんだけど、geom_barみたいなものと同じように思ってた。

まぁ何はともあれやってみる。

require(tidyverse)
require(lubridate)
require(plotly)


df <- data.frame(
  x = sample(10, 10, replace = TRUE),
  x_range = sample(5, 10, replace = TRUE),
  y = sample(10, 10, replace = TRUE),
  y_range = sample(5, 10, replace = TRUE),
  pd = letters[1:10]
)

# geom_rectってなんだ?
g <- ggplot(df, aes(xmin = x, xmax = x + x_range,
                    ymin = y, ymax = y + y_range,
                    color = pd, fill = pd, alpha = .3)) +
  geom_rect()+
  xlim(0,15) + ylim(0,15)+
  geom_text(aes(x=x + x_range/2, y=y + y_range/2, label = pd, alpha = 1))

欲しかったのは、各描画要素が要素ごとに異なる範囲を示す二次元グラフで、
グラフ要素同士は重なってて良い(ってか重なって欲しかった)ものなので、コレピッタリ。

出来上がったのが、はい、こんな感じです

alphaのlegendは消しとくべきか

引数は当然ながらいつものx、yだけではないんだけど、
「始点と長さ」ということではなく、あくまで2つの座標を示すものらしいです。

んだもんで、座標が同じだとただの点。

# xmax・ymaxはあくまで座標を表すらしい。
# 線分の長さではないから長さデータがあるなら各minに足さないといけないので注意
# 以下だとただのgeom_textと同じになっちゃう
g0 <- ggplot(df, aes(xmin = x, xmax = x + 0,
                    ymin = y, ymax = y + 0,
                    color = pd, fill = pd, alpha = .3)) +
  geom_rect()+
  xlim(0,15) + ylim(0,15)+
  geom_text(aes(x=x + x_range/2, y=y + y_range/2, label = pd, alpha = 1))

# あと大好きplotlyで変換すると値がよくわからん
ggplotly(g, width = 800, height = 600)

f:id:cun-wang:20180815141709p:plain
点。

コレで例えば、以下のような期間データを二次元に示したわけのわからん動きをするグラフをイイカンジにしたいのです*4

# 時系列っぽい複数次元データでやってみる
df1 <- data.frame(
  hiduke = ymd("2015-01-01") %m+% months(c(0:36)),
  product1 = cumsum(rnorm(37)),
  product2 = cumsum(rnorm(37)),
  product3 = cumsum(rnorm(37)),
  product4 = cumsum(rnorm(37))
  ) %>% gather(product, val1, -hiduke) %>% na.omit() %>% 
  mutate(val2 = cumsum(round(val1 * rnorm(1), digits = 0)))

f:id:cun-wang:20180815141720p:plain

例えば、「その要素の最小値-最大値」の範囲を示す
みたいなことが出来ますね。

ggplot(df1, aes(val2, val1, colour = product)) + geom_path()

df2 <- df1 %>% group_by(product) %>% summarise_if(is.numeric, funs(min, max))

ggplot(df2, aes(xmin = val1_min, xmax = val1_min + val1_max,
                ymin = val2_min, ymax = val2_min + val2_max, 
                fill = product, colour = product))+
  geom_rect(alpha = .1)+
  geom_text(aes(x=val1_min + val1_max/2, y=val2_min + val2_max/2, label = product))

はいどーん

お分かりいただけるだろうか…?
コレって、データ整理にものすごく役立つんですよね。

1つ1つの次元を1つずつグラフにしていってもちっとも分からないしアタマが追いつかないんですが、
まとめてみるとアラ不思議!

ということで、geom_rect、
この夏、オススメのグラフですよ………!?

※ちなみに当初やりたかったのはひし形でxy軸と関係のない別の二次元を付けたかったんですが、
 それは流石に分かりづらいですかね…(今のgeom_rectでも書けるけど)。

*1:そんなものは知らぬ

*2:geom_pointでsizeを指定しますが詳しくは他の方のブログなどをおググりください

*3:他にもcontourとか足すのもアリだけど

*4:ランダムなので値によってはわけわからんです。。ミミズがニョロニョロするような値の方が見やすいです。。