これまでのシリーズでは、データは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″です。
JSON:
JSONはcsvとは違って、入れ子構造が作れます。javascriptオブジェクトとほぼ同じ形式なので、javascriptから保存したり読み込むことが簡単にできるのが特徴です。ファイル名はtest.jsonのようになります。
下の例では、リストの中に同じ形式のレコードが並んでいます。{data:~,close~}のような同じキー名の連想配列をリストに加えると、データを追加することもできます。
下の画像では、stockというキーの中にさらにopenとcloseというキーが入って入れ子になっています。このような入れ子は、ツリー構造や方向性のあるデータを作るときに便利です。
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のカラムを持つ、時間ごとの株価データです。
結果:

コード:
<!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を使って年-月-日に変換しています。
お世話になります。
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);
});
データを普通に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” ]
データを普通に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”]
返信ありがとうございます! 連想配列の値だけを取り出す必要があるのですね
とても難しいですが、頑張って勉強したいと思います。ありがとうございました。