サーバーなしでD3.jsを使う

D3.jsはグラフの表示などができるJavaScriptのライブラリです。今回はこれを使って散布図を表示させてみます。

はじめに

データの可視化をする方法として一番有名なものはエクセルです。しかし、エクセルだと操作できるグラフを作ったり、かっこいいグラフを作るのは結構しんどいです。ほかに思いつく方法はPythonとかRとかMATLABですが、普通のパソコンには入っていないので、グラフ作成ツールを作っても共有できません。でもブラウザならどのパソコンにも入ってるし、便利かもと気づいたので、ブラウザで動くD3.jsを試してみました。

HTMLの準備

そもそもJavaScriptを使ったことがないので、勉強もかねています。(WEB系の技術も勉強しないと。。)

<html>
<head>
 <title>ドラッグ&ドロップで散布図</title>
 <script src="jquery-2.1.4.min.js"></script>
 <script src="d3/d3.min.js" charset="utf-8"></script>
 <script language="javascript">TODO</script>
 <body>
 <div id="droppable"
        style="border: gray solid 5px; padding: 2px; width:250px; height:50px;">
    ここにファイルをドラッグ&ドロップ
 </div>
 </body>
</html>

このHTMLのdroppableなdivにファイルをドラッグ&ドロップすると散布図を表示させるよう改造していきます。JavaScriptの制約でローカルにあるファイルにはアクセスできないですが、ドラッグ&ドロップならオッケーみたいです。WEBサーバーを立てればローカルファイルでもいいんですけど、ソフトを配った人にサーバー入れて!なんて言えないですよね。

ドラッグ&ドロップ

HTML5を使うとブラウザにファイルをドラッグ&ドロップして読み込むことができます[1]。ファイルが読み終わると、drawScatter()という自作の関数を呼びます。この関数に散布図表示コードを書いていきます。

var fileReader = new FileReader();
fileReader.onload = function(event) {
 drawScatter(event.target.result);
}
fileReader.readAsText(file);

散布図の表示

データセット

表示させるデータはPRMLという本のclassificationを使います。前にもC#で試したことがありました。
wildpie.hatenablog.com
データ形式は1.208985 0.421448 0.000000みたいに、x軸 y軸 labelとなっています。labelは0と1の二種類です。これはcsvのパース関数を使うとそれぞれの数値を配列に入れることができます[2]。

function drawScatter(data) {
  var csvArray = parseCSV(data);
  console.log(csvArray);
}

console.log()の結果を一部表示すると下記のようになります。これが200個ある感じです。
f:id:wildpie:20151226193401p:plain

D3.jsで表示

D3.js チュートリアル[3]に散布図の作り方が詳しく載っていたので参考にしています。詳しくはこのサイトをご覧ください。
はじめに表示する領域を作ります。

var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 500 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

スケールの設定をします。データの範囲は[-2.5,3]でプロット画面は[0,width]の範囲とします。

var xScale = d3.scale.linear()
	  .domain([-2.5, 3])
	  .range([0, width]);
var yScale = d3.scale.linear()
	  .domain([-3, 3])
	  .range([height, 0]);

軸の設定をします。

svg.append('g')
	.attr("class", "x axis")
	.attr("transform", "translate(0," + height + ")")
	.call(xAxis);
svg.append('g')
	.attr("class", "y axis")
	.call(yAxis);

プロットするデータを定義します。csvArrayのデータを取り出して、'circle'を生成して、'cx'、'cy'で位置、'r'で大きさ、'fill'で色を指定します。

var colorCategoryScale = d3.scale.category10();
var points = svg.selectAll('circle')
	.data(csvArray)
	.enter()
	.append('circle')
	.attr('cx', function(d) {
	  return xScale(d[0])
	})
	.attr('cy', function(d) {
	  return yScale(d[1])
	})
	.attr('r', 7)
	.attr('fill', function(d) {
	  return colorCategoryScale(d[2]);
	});

そんなこんなでこれを実行すると以下のようになります。


f:id:wildpie:20151226195111p:plain

散布図を操作する

JavaScriptを使っているので、マウスで操作することができます。下の例ではマウスオーバー時は点を緑にして、大きさを2倍にしています。マウスオーバーをやめると元に戻ります。

points.on('mouseover', function() {
		d3.select(this)
		  .attr('r', 14)
		  .attr("fill", function(d) {
		    return "green";
		  });
       })
       .on('mouseout', function() {
		d3.select(this)
		  .attr('r', 7)
		  .attr('fill', function(d) {
		    return colorCategoryScale(d[2]);
		  })
	});

f:id:wildpie:20151226202155p:plain