LoginSignup
7
8

More than 5 years have passed since last update.

NVD3でドラッグされた範囲のデータを再描画する散布図を作ってみた

Posted at

前回の記事で紹介したQiitaのタグの情報を使い、ドラッグして範囲を指定し、ドリルダウンできる散布図を作ってみました。

今回の完成がこちらです。
http://bl.ocks.org/ganezasan/9098135dae6ce1552194

ドラッグ&ドリルダウン

最初にこのコードは汎用化はできていません。
まず動くというのを目指しました。
そのため、NVD3のライブラリを直接いじっています。
なので、試す際にはこのリポジトリにおいてあるnv.d3.jsを使用しないと動作しません。
今後もう少し綺麗に書いてNVD3にPull Requestを送りたいと思います。

修正したソースコード部分

.extent {
  stroke: #cfd7e5;
  fill: #cfd7e5;
  fill-opacity: 0.4;
  shape-rendering: crispEdges;
}
nv.d3.js

// brushオブジェクト    
var callback = function(){
  console.log("bashend");
  var brushElem = d3.select('.extent');
  var _x = new Number(brushElem.attr('x'));
  var _y = new Number(brushElem.attr('y'));
  var _width = new Number(brushElem.attr('width'));
  var _height = new Number(brushElem.attr('height'));

  // xMin,xMax等設定&選択範囲内のデータ抽出。
  var xMin = 0;
  var xMax = 0;
  var yMin = 0;
  var yMax = 0;
  var newState = {"disabled":[]};

  //選択範囲が0じゃない場合
  if (_width != 0 && _height != 0){
    xMin = x.invert(_x);
    xMax = xMin + x.invert(_width);
    yMin = y.invert(_y + _height);
    yMax = y.invert(_y);
    data = data.filter(function(row,i){
      var rowX = row["values"][0]["x"];
      var rowY = row["values"][0]["y"];
      if(xMin <= rowX && rowX <= xMax && yMin <= rowY && rowY <= yMax){
        newState.disabled[i] = false;
        row.disabled = false;
        return true;
      }else{
        newState.disabled[i] = true;
        row.disabled = true;
        return false;
      }
    });
  }else{
    //単純なクリックの場合、スケールを戻す
    data = data.filter(function(row,i) {
      row.disabled = false;
      newState.disabled[i] = false;
    });
  }

  state.disabled = newState.disabled;

  //グラフ再描画
  dispatch.stateChange(state);
  chart.update();

  //選択範囲を非表示に
  d3.select('.extent').attr({width: 0, height: 0, x: 0, y: 0});
};

var _brush  = d3.svg.brush()
  .x(x) // x軸を選択可能範囲に指定
  .y(y).on('brushend',callback);

var wrapEnter = d3.select(".nv-groups");
wrapEnter.call(_brush).selectAll("rect");

ちょっとだけ解説

まず範囲指定するためにd3.svg.brush()を使用しています。
d3.svg.brush()を使用すると「rect」タグが自動で作られクラス名が「extent」になっています。

<rect class="extent" x="0" width="0" y="0" height="0" style="cursor: move;"></rect>

範囲指定後の「bashend」のイベントを拾って「extent」のx,y,width,heightを取得し、範囲内のデータをfilterで絞り込み表示するようにしています。

次にドットを表示する、しないについて、NVD3の散布図「nv.models.scatterChart」にはlegend(凡例)を表示する機能があり、凡例をクリックした際に、凡例と同じグループのドットを表示する、しないを指定できる機能があり、今回はそちらを利用しました。

具体的に言うと、
もともとの散布図のデータはこうなっています。

[{key: グループ名 ※legend(凡例)として表示される,
values:[{
         x: x軸の位置
      , y: y軸の位置
      , size: 円の大きさ
      , shapes: '円の形'
}]}]

再描画時にドットを表示しない場合は「disabled:true」を追加します。

[{disabled: true,
key: グループ名 ※legend(凡例)として表示される,
values:[{
         x: x軸の位置
      , y: y軸の位置
      , size: 円の大きさ
      , shapes: '円の形'
}]}]

さらにstate.disabledというオブジェクトにgroupの数true,falseの配列が入っているので、表示したくないgroupと同じ配列番号にtrueを入れて上げ、
以下のメソッドを実行すると再描画されます。

dispatch.stateChange(state);
chart.update();

まとめ

d3.js単体で作った方が処理速度は早い気がしますが、
nvd3は便利な関数が多いので好きです。

散布図にドラッグでドリルダウン機能はすごく欲しかったので、
できてよかったです。

ソースはアップしているので、
よかったら使ってみてください。

7
8
0

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
7
8