Rからdc.jsのグラフを描くパッケージを(手抜きで)つくりました

dc.jsは、インタラクティブにグラフをいじりつつデータを探索できるJavascriptのライブラリです。crossfilterというデータを様々な条件で絞り込むのをお手軽にするライブラリを使ってます。

と、日本語でのこなれた説明が思いつかないので、公式ページの例を触ってみるのがいいと思います。グラフをポチポチクリックすると、それが絞り込み条件に使われて、他のグラフでも連動してその絞り込みが使われます。

dc.js - Dimensional Charting Javascript Library

で、このグラフをRから描くパッケージをつくりました。

といっても、上の公式ページの例と同じグラフしか描けません。まじめにすべてのバインディングをつくると大変そうなので手を抜きました。

yutannihilation/dcStockR · GitHub

インストール

devtools::install_github("yutannihilation/dcStockR")

本気でやると大変なので手を抜く

dc.js のドキュメントを読むと、けっこうパラメータがいっぱいあります。おまけにCrossfilterの概念もなんか複雑でよく分かりません。大変そう。

dc.js/api-1.7.0.md at master · dc-js/dc.js · GitHub

なのでもう潔く、どのグラフを描くかくらいしか選べなくてパラメータはまったくいじれないようにしました。

dc <- function(data, chartRecipe = c("yearlyBubbleChart", "gainOrLossChart",
                                     "quarterChart", "dayOfWeekChart", "fluctuationChart",
                                      "moveChart", "dataCount", "dataTable"),
               title = NULL, width = NULL, height = NULL)

chartRecipeでグラフの種類が選べるのと、タイトル・高さ・幅が変えられるくらいです。各chartRecipeでどんなグラフが描けるのかはRPubsに例をあげたのでこちらをご参照ください。

RPubs - example of dcStockR

パラメータをほとんどR側でいじらないと高をくくってしまえばあとは楽です。データ形式だけまねて、公式ページのJavascriptを少しいじったものに渡せばそれでもうグラフ描けちゃうので。

グラフ間でオブジェクトを共有する

公式サイトの例のようにグラフ間で絞り込みを連動させるには、グラフ間で同じcrossfillterオブジェクトを使う必要があります。同じデータでもグラフを描くたびにcrossfillterオブジェクトを生成しなおしていては連動しません。dcStockRでは、windowを介してcrossfillterオブジェクトを共有するようにしています。

まず、initialize()で、crossfilterを格納するためのプロパティをつくります。(一度だけつくればいいので、すでに同名のプロパティがあればスキップします)

if(!window.__ndx) {
  window.__ndx = {};
}

(https://github.com/yutannihilation/dcStockR/blob/c6091c89dce8b230861f3c50d30de4d5606c1c47/inst/htmlwidgets/dc.js#L9-L11)

R側からは、同じデータかどうかを判別するため、データとともにハッシュ値を渡すようにします。

x <- list(
  data = data,
  datahash = digest(data),
  chartRecipe = match.arg(chartRecipe),
  title = title
)

(https://github.com/yutannihilation/dcStockR/blob/c6091c89dce8b230861f3c50d30de4d5606c1c47/R/dc.R#L13-L18)

このハッシュ値をキーにしてwindow.__ndxにデータを入れます。

if(!window.__ndx[x.datahash]) {
  data.forEach(function(d) {
    d.dd = dateFormat.parse(d.date);
    d.month = d3.time.month(d.dd);
    d.close = +d.close;
    d.open = +d.open;
  });
  window.__ndx[x.datahash] = crossfilter(data);
}

(https://github.com/yutannihilation/dcStockR/blob/c6091c89dce8b230861f3c50d30de4d5606c1c47/inst/htmlwidgets/dc.js#L32-L40)

グラフを描く時は、データを直接関数に渡すのではなく、やはりこのハッシュ値を渡してwindow.__ndxからデータを取り出すようにします。

    var ndx = window.__ndx[datahash];

(https://github.com/yutannihilation/dcStockR/blob/c6091c89dce8b230861f3c50d30de4d5606c1c47/inst/htmlwidgets/lib/stock.js#L14)

ざっくりいうとそんなことをしてます。あと細かい工夫があった気もするんですけど、コード読んでもあんまり思い出せないので気にしないことにします!笑

Shinydashboardにしてみる

これを使うと、こんな感じのDashboardがつくれます。(無料版なので、すぐ見れなくなるかもしれません)

f:id:yutannihilation:20150301010817p:plain

このあとどう開発してけばいいのか思いつかないので、何かあればコメント欄、TwitterIssuesでお知らせください。