チャートライブラリを作っている話


PLAID Advent Calendar 2017 4日目です。

今日は僕と@otolabが開発しているEasyDCというチャートライブラリのお話です。

追記
EasyDCを使った簡易ダッシュボードを作ってみました。
クリックして遊んでみてください。

EasyDCとは

  1. データセット(CSV)を用意してHTMLを記述するだけでデータの可視化ができる
  2. チャートへのクリック操作のみでインタラクティブにデータのフィルタリングができる

この2点が大きな特徴のライブラリです

サンプル

こんなCSVがあったとして

expt,run,speed
1,1,10
1,2,20
1,3,30
2,1,20
2,2,40
2,3,60
3,1,15
3,2,30
3,3,45

次のようなHTMLを書くと

<!DOCTYPE html>
<html lang="ja">

  <head>
    <script type="text/javascript" src="https://plaidev.github.io/easy-dc-dash/dist/bundle.browser.js"></script>
  </head>

  <body>
    <easy-dc-dataset
      csv="dataset.csv"
    ></easy-dc-dataset>

    <div>
      <ordinal-bar
        dimension='d.expt'
        reduce='d.speed'
      ></ordinal-bar>

      <list-row
        dimension="d.run"
        reduce="d.speed"
      ></list-row>
    </div>

    <script type="text/javascript">
      EasyDC.run()
    </script>
  </body>
</html>

こんな感じに描画されます。

使用している技術

EasyDCは簡単に言えばVue.jsでdc.jsをラップしたライブラリです。

Vue.js

ご存知の方が多いと思うので説明は省きます

dc.js

  • D3.jsによるデータの可視化
  • Crossfilterによるデータのグループ化・フィルタリング・アグリゲーション

これらによって大きな多変量データに対して高速にグループ化、フィルタリング、アグリゲーションし、なおかつ結果をチャートにインタラクティブに反映することを実現しているライブラリです。

D3.js、Crossfilterについては弊社のエンジニアブログでも取りあげられているのでご参考までに。
D3.js: データの可視化に使えるD3.jsでユーザーのページ遷移を表現してみた
Crossfilter: Bit Matrixを使って超高速にアグリゲーションする

なぜdc.jsをラップする必要があるのか

dc.jsは素晴らしいライブラリですが、D3.jsおよびCrossfilterの簡単な知識とdc.jsの知識が必要になるので、扱うにはそれなりにコストがかかります。
EasyDCのサンプルと同等のことをdc.jsで実現しようとすると、だいたい次のようになります (※動作確認はしてません)

<html lang="ja">

  <head>
    <script type="text/javascript" src="d3.js"></script>
    <script type="text/javascript" src="crossfilter.js"></script>
    <script type="text/javascript" src="dc.js"></script>
  </head>

  <body>
    <div id="bar"></div>
    <div id="row"></div>

    <script>
      var barChart = dc.barChart("#bar");
      var rowChart = dc.barChart("#row");

      d3.csv("dataset.csv", function(error, experiments) {
        experiments.forEach(function(x) {
          x.speed = +x.speed;
        });

        var ndx                 = crossfilter(experiments),
            barChartDimension   = ndx.dimension(function(d) {return +d.expt;}),
            rowChartDimension   = ndx.dimension(function(d) {return +d.run;}),
            barChartSumGroup    = barChartDimension.group().reduceSum(function(d) {return d.speed;});
            rowChartSumGroup    = rowChartDimension.group().reduceSum(function(d) {return d.speed;});

        barChart
          .width(377)
          .height(233)
          .x(d3.scale.ordinal()))
          .brushOn(false)
          .dimension(barChartDimension)
          .group(barChartSumGroup)
          .render()

        rowChart
          .width(377)
          .height(233)
          .x(d3.scale.linear())
          .elasticX(true)
          .dimension(rowChartDimension)
          .group(rowChartSumGroup)
          .render()
      });
    </script>
  </body>
</html>

オーソドックスなバーチャートを2つ表示するだけでもこれくらいの記述量になります。
描画できるチャートは他にもあるので (ラインチャート、パイチャート、バブルチャート、ヒートマップ、テーブル、コロプレス地図、etc...)、 dc.jsに慣れたとしてもダッシュボードを作るにはそれなりの手間がかかると思われます。

もっと簡単にdc.jsを使いたいですよね。

僕と@otolabはそう思いました。

そこで、弊社のプロダクトでも使用しているVue.jsを使ってdc.jsのラッパーライブラリを作っているというわけです。

おわりに

dc.jsを使い始めた時は知るべきことが多くて戸惑いましたが、可視化やダッシュボード作成の方に力を注げるようなライブラリにできるように頑張りたいです。

  • Vue.jsでラップするメリット
  • dc.jsではサポートしていない機能をいくつか入れている話
  • ダッシュボード作成のための機能を開発している話

などなど、今回お伝えできなかった技術的なお話は後日弊社のエンジニアブログで公開する予定ですので、その時もまた読んでいただけたら嬉しいです。