D3.js 基本9 – csvとJSONファイルの読み込み

Share

これまでのシリーズでは、データはhtmlやjavascriptファイルに書き込んだものを使っていました。外部のファイルが使えるようになると、他のウェブサイトからデータを取って使うことができます。また、何千もあるようなリストを読み込むことも簡単にできます。

 

csvとJSONの構造

外部ファイルとして一番使われているデータ形式はcsvとJSONです。

csv:
csvはエクセルと似ていて、縦と横に広がるテーブルです。ファイル名はtest.csvのように語尾にcsvをつけます。
エクセルと違うところは、csvは列をカラムとして使い、行は同じ属性のデータを入れるところです。カラムはコンマを使って区別します。改行は次の行に行くという目印です。

たとえば下の例では、dateとcloseという2つの属性カラムが一番上の行で宣言されています。
それより下の行は、それぞれdateとcloseの値です。2行目なら、dateは”1-May-12″で、closeは”582.13″です。
d3基本9-1csv_format

JSON:
JSONはcsvとは違って、入れ子構造が作れます。javascriptオブジェクトとほぼ同じ形式なので、javascriptから保存したり読み込むことが簡単にできるのが特徴です。ファイル名はtest.jsonのようになります。

下の例では、リストの中に同じ形式のレコードが並んでいます。{data:~,close~}のような同じキー名の連想配列をリストに加えると、データを追加することもできます。
d3基本9-2json_format

下の画像では、stockというキーの中にさらにopenとcloseというキーが入って入れ子になっています。このような入れ子は、ツリー構造や方向性のあるデータを作るときに便利です。
d3基本9-3json_nest

 

D3でcsvとJSONファイルを読み込む

d3を使ってこういったファイルを読み込むのは簡単です。

たとえばtest.csvというファイルを読み込む時は下のようにd3.csvを使います。

d3.csv("test.csv", function(data){
	console.log(data);
});

function(data)のdataという名前は任意なので、dでもgdpでも大丈夫です。その名前をfunction(data){}の中で使えば、データにアクセスできます。
結果、javascriptには下のようなデータが読み込まれます。

[{"date":"1-May-12","close":"582.13"},{"date":"30-Apr-12","close":"583.98"},{"date":"27-Apr-12","close":"603"},{"date":"26-Apr-12","close":"607.7"},{"date":"25-Apr-12","close":"610"},{"date":"24-Apr-12","close":"560.28"},{"date":"23-Apr-12","close":"571.7"},{"date":"20-Apr-12","close":"572.98"},{"date":"19-Apr-12","close":"587.44"}]

たとえば一番最初のcloseのデータを取り出したい時は、下のようにします。

d3.csv("test.csv", function(data){
	var d = data[0].close; // 0番目のcloseというキーの値を出す。
	console.log(d);
});

JSONファイルを読み込む時は下のようにd3.json()を使います。

d3.json("test.json", function(data){
 console.log(data);
});

結果は下のようになります。

[{"date":"1-May-12","close":"582.13"},{"date":"30-Apr-12","close":"583.98"},{"date":"27-Apr-12","close":"603"},{"date":"26-Apr-12","close":"607.7"},{"date":"25-Apr-12","close":"610"}]

Javascriptに読み込まれればデータ形式は同じなので、csvの時と同じようにデータにアクセスできます。

 

最後に、1000以上の行があるcsvファイルを読み込むとどんな風になるか、時系列の散布図を作ってみました。使ったcsvファイルはこちらで、dateとcloseのカラムを持つ、時間ごとの株価データです。

結果:

クリックすると実際のhtmlが開きます。
クリックすると実際のhtmlが開きます。

コード:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<!-- 軸の属性を決めている。特にfill:none;にしないと真っ黒になる。-->
	<style>
		.axis text {
		  font: 10px sans-serif;
		}

.axis path {
/*
fillとopacityで半透明な背景色。
		*/
		  fill: Aquamarine;
		  opacity: 0.1;
		  stroke: #000;
		  stroke-width: 1;
		  shape-rendering: crispEdges;
		}

		.axis line {
  		  stroke: #000;
  		  stroke-width: 1;
  		  shape-rendering: crispEdges;
		}

	</style>
</head>
<body>	

	<script src="http://d3js.org/d3.v3.min.js"></script>

	<script>

var margin = {top: 20, right: 30, bottom: 30, left: 40},
    width = 700 - margin.left - margin.right,
    height = 400 - 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 + ")");

d3.csv("timeseries.csv", function(data){

	// yScaleのために、closeの最大値を出す。
	var yMax = d3.max(data,function(d){ return +d["close"]; });

	// "日-月-年"からDateオブジェクトを作る。
	var format = d3.time.format("%d-%b-%y");
	// Dateオブジェクトから"年-月-日"に変換する。
	var newFormat = d3.time.format("%y-%b-%d");

	// xScaleには、データレコードの数を最大値に使う。
	var xScale = d3.scale.linear()
					.domain([0,data.length])
					.range([width,0]); // データが新-旧順なので、逆にする。

	var yScale = d3.scale.linear()
					.domain([0,yMax])
					.range([height,0]);

	var xAxis = d3.svg.axis()
				    .scale(xScale)
					.ticks(6)
				    .orient("bottom")
				    .tickSize(6, -height)
					.tickFormat(function(i){
						var f = format.parse(data[i]["date"]); // dateからDateオブジェクトを作る。
						return newFormat(f); // Dateオブジェクトから新しい"年-月-日"の並びに変える。
					});

	var yAxis = d3.svg.axis()
					.ticks(5)
				    .scale(yScale)
				    .orient("left")
				    .tickSize(6, -width);

	svg.selectAll("circle")
		.data(data)
		.enter()
		 .append("circle")
		 .attr("r",2)
		 .attr("fill", "steelBlue")
		 .attr("cx", function(d,i){ return xScale(i); })
		 .attr("cy", function(d){ return yScale(d["close"]); });

	svg.append("g")
		.attr("class", "y axis")
		.call(yAxis)
	    .append("text")
	      .attr("y", -10)
		  .attr("x",10)
	      .style("text-anchor", "end")
	      .text("Price($)");

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

	</script>

</body>
</html>

解説:
たくさんの小さな円を並べているので、まるで線グラフのようになりました。

外部データを使うと、表示するときにうまく合わないデータが出てきます。
このcsvデータの場合、時間が最近のものが上で、古いものが下に来ているので、そのまま表示するとx方向に逆の形になってしまいます。それをスケールを使って対処しています。
さらに年月日の形式が”15-May-03″のように、日-月-年になっているので、それもd3.time.formatを使って年-月-日に変換しています。


4 thoughts on “D3.js 基本9 – csvとJSONファイルの読み込み

  1. お世話になります。
    scriptの中に
    var englishArray =[ “I am pen.”,”He is OK”,”I am a pen”,”I am OK”,”I am Kevin”];

    ↑のデータがあるのですが、これを外部ファイルCSVに置いて、そこから読み取って

    var englishArray に格納したいのですが、やり方がわかりません。
    CSVファイルの中のある列にデータを入れた場合、その列からデータを読み出すにはどうしたらいいのでしょうか?
    例)
    test.csv

    englishArray

    I am pen.

    He is OK.

    I am a pen.

    というふうにデータが入っているとして

    d3.csv(“test.csv”, function(data){
    var englishArray のセルからデータを持ってきて、 var englishArray の中に格納したい。
    console.log(data);

    });

    1. データを普通にd3.csv()で読み込むと、一番上のカラム名をキーとした連想配列として読み込まれます。
      例:
      d3.csv(“test.csv”, function(data){
       console.log(data);
      })
      >>[{“englishArray”:”I am pen”},{“englishArray”:”He is OK”},{“englishArray”:”I am a pen”}]

      リストとして読み込みたいときは、d3.csv()ではなくd3.text()で読み込んだ後、d3.csv.parseRows()でリストのリストとして変換できます。
      このままだとリストの中にリストがたくさんできてしまうので、d3.merge()でフラットなひとつのリストとしてマージできます。
      例:
      d3.text(“test.csv”, function(data){
      var list_data = d3.csv.parseRows(data);
      var englishArray = d3.merge(list_data);
      console.log(englishArray);
      })
      >>[ “englishArray”, “I am pen”, “He is OK”, “I am a pen” ]

    2. データを普通にd3.csv()で読み込むと、一番上のカラム名をキーとした連想配列として読み込まれます。
      例:
      d3.csv(“test.csv”, function(data){
       console.log(data);
      })
      >>[{“englishArray”:”I am pen”},{“englishArray”:”He is OK”},{“englishArray”:”I am a pen”}]

      連想配列の値だけを取り出すには、data.forEach()内でリストの要素それぞれにd3.values()を適用していって、これをvar valuesに入れていきます。
      このままだとリストの中にリストができてしまうので。d3.mergeでフラットな一つのリストに変換します。
      例:
      d3.csv(“test.csv”, function(data){
      var values = [];
      data.forEach(function(d){
      values.push(d3.values(d));
      })

      var englishArray = d3.merge(values);
      console.log(englishArray);
      })
      >>[“I am pen”,”He is OK”,”I am a pen”]

      1. 返信ありがとうございます! 連想配列の値だけを取り出す必要があるのですね
        とても難しいですが、頑張って勉強したいと思います。ありがとうございました。

コメントを残す