PHPとMySQLで取得した値をD3.jsを使って描画するときの備忘録

サーバーサイドからデータを取得して、非同期でグラフを描画したいというケースがあるかと思います。更にそこからレスポンシブでグラフを変化させるという事を求められることがありますが、今回は第一段階としてシンプルにサーバーからデータを取得して、JavaScriptで受け取って、そのままd3.jsで描画するという流れについてご紹介します。

d3.jsとは

d3.js

D3.js はデータに基づいてドキュメントを操作するための JavaScript ライブラリです。d3というのはデータ・ドリヴン・ドキュメントの略称となっていて、d3.jsを利用する事によってHTML、SVG、CSSをサポートして比較的簡単に複雑なグラフを視覚化できます。

 

d3.jsの公式ドキュメント

http://ja.d3js.node.ws/

英語のドキュメント
https://d3js.org/

d3.jsで描画したもの

d3.js

データをビジュアル化する目的

Rplayでは就活イベントを多数掲載しており、直接就活生がイベントにエントリーできるようになっています。Rplayを経由してエントリーしたイベントの名前や大学、性別など様々なデータを解析していて、テーブル表示にしても直感的・視覚的に分かりにくいのでグラフィカルに表示したいというニーズがありました。

d3.js

単純に上記の画像のようなデータをテーブル表示にしても分かりやすい、比較しやすいというものもあります。

3つぐらいの大学の偏差値や内定先の企業、学費、強い部活などを比較するというようなデータ(テーブル)を作成し、ビジュアル化するのであればテーブルの方が分かりやすいと思います。

大事なのはデータの内容と目的を明確にし、ビジュアル化するということです。目的があると納得しやすいので、そこを明確にしておくことをお勧めします。

「データの羅列は見たくないけど、ビジュアル化されていたら見ることもある。」ということもありますので、そのページの滞在時間や離脱などで、グラフ化したページのUXを計測するというのも手ではあります。

そこから、まず第一段階として、「イベントに参加している学生の大学名と比率を円グラフで表示」というのを実装してみました。

簡単な実装の流れ

1. データベースからデータを取得する

上記は、イベントに参加している就活生の出身大学上位10大学をデータベースから取得して、更にその大学に通っている大学生の人数を取得します。

その後、大学生の10校のイベント参加者を母数としたいので合計値を算出します。
※若干冗長的になってしまっているのは、筆者がPHPに慣れていないということがございますので、ご了承くださいませ。

  	$sql = "SELECT university, count(*) AS num FROM テーブル名 GROUP BY university ORDER BY num DESC LIMIT 11";
		$result = mysql_query($sql);

		$totalNum = 0;

		$row = mysql_fetch_array($result, MYSQL_ASSOC);

		for ($i=0; $i < $row["num"]; $i++) { 
			$totalNum += $row["num"];
		}

データが取得できたら、データを加工して、JSON形式にしておきます。
これは、JavaScriptでフロント側から取得したいためです。

if($result){
	while($row = mysql_fetch_assoc($result)){	
		$data[]=array(
			'university'=>$row["university"],
			'num'=>$row["num"],
			'rate'=> $row["num"] / $totalNum,
		);
	}			
	echo json_encode($data);
}

2. フロント側でデータを取得する

そのままd3.jsなどのグラフィカルな使い方をせずに、表示するときもあります。tableなどにそのままレンダリングするというケースですが、今回はd3.jsを使います。

$.ajax({
  type: 'GET',
  dataType: 'json',
  url: 'url',
  success: function(data){
		// データを取得する
  }
});

Rplayではこちらをapiとして作成しており、同一ドメインであるためにクロスドメインの問題は起きませんが、クロスドメインの問題が起きた場合は、jsonpを利用してください。

successの中でd3.jsの関数を書いていきます。dataで取得したらそのままデータを渡すように実装しています。綺麗に書く方法もありますが、今回は分かりやすさだけを追求してそのまま書きます。

function drawPie(id, dataset) {
    // コンテナ
    var width = 550,
        height = 300,
        radius = Math.min(width, height)/2;
    var svg = d3.select(id)
            .attr({
                width : width,
                height : height
            })
            .append("g")
            .attr("transform",  "translate(" + width / 2 + "," + height / 2 + ")");

    // パイを定義
    var pie = d3.layout.pie()
            .sort(null)
            .value(function(d) { 
              console.log(d);
              return d.rate; 
            });


    // 円弧の外径と内径を定義
    var arc = d3.svg.arc()
            .outerRadius(radius - 10)
            .innerRadius(5);

    // データバインド
    var g = svg.selectAll("path")
            .data(pie(dataset))
            .enter()
            .append("g")
            .attr("class", "arc");

    // 描画
    g.append("path")
        .attr("d", arc); // 円弧を設定

    // テキスト
    g.append("text")
        .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) //centroidはデータから自動で計算される関数
        .attr("font-size", "12")
        .style("text-anchor", "middle")
        .style("fill", "#fff")
        .text(function(d) { return d.data.university; });

    // グラフに利用する色
    var colorArr = [
                    '#E74C3C',
                    '#F16745',
                    '#FFC65D',
                    '#7BC8A4',
                    '#4CC3D9',
                    '#93648D',
                    '#404040',
                    '#652681',
                    '#404040',
                    '#652681',
                    ];
    g.attr("stroke", "white")    // 円グラフの区切り線を白色にする
        .style({
            fill: function(d, i) {
                return colorArr[i];
            }
        });

}

// 円グラフの表示データ
drawPie("#pie", data);  //html内に<svg id="pie></svg>と書くとそこにグラフができる

ajaxで取得したデータを、drawPie関数の第二引数に渡して、そのまま描画の関数を実行しています。
#pieは、HTML側に、下記を用意することによって、そこにグラフが挿入されます。

<svg id="pie"></svg>

今回は取得したデータを直接d3.jsを使って描画していますが、ネットに落ちている情報ですと結構ファイルから取得するケースがあります。
下記のようなケースです。この方が綺麗に書くことができますが、リアルタイムでのグラフ変更をするときには変数を第一引数に渡すことができませんでした。ですので、今回はご紹介してきた実装方法で実装しています。

d3.json("ファイルパス", function(json) {

});

d3.csv("ファイルパス", function(json) {

});

さいごに: d3.jsは以外と簡単

以上いかがでしたでしょうか。

以外と一連の流れをやってみると簡単に実装できてある程度綺麗なグラフが表示できるので楽しいです。

ここからグラフをホバーしたときにアニメーションさせたり、値がリアルタイムで変化したり、ブラウザのサイズによって可変させたり、様々な要件が追加されることがあります。そういうリアルタイムでのインタラクションを含むビジュアル化をするときにd3.jsは威力を発揮します。

それに関しては引き続きタイミングがありましたら書いていきます。