D3.js 基本3 – データを使ってSVG要素を表示する

Share

ここではデータを使ってSVGを表示していきます。D3.jsの目的がまさにこのデータバインドなので、はじめてD3らしさが出ます。

 

テンプレート

まずテンプレートとしてscriptタグの中にsvg要素作成までのコードを用意します。

var width = 960;
var height = 700;

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);

この下にコードを書きます。2~5を試す時は、同じコードの中にいれないで、独立したコードとして1のテンプレートの下に書いてください。

 

リストデータを使って円を描く

var listData = [30,70,60];

svg.selectAll("circle")
 .data(listData) // データをバインド。
 .enter()
	.append("circle")
	.attr("r",10)
	.attr("fill","blue")
	.attr("cx", function(d){ return d*2; }) // データをcxに使う。
	.attr("cy", function(d,i){ return (i+1)*50; }); // データのインデックスをcyに使う。

結果:
d3基本3-1data_index

解説:
縦に3つ並べた円が表示されています。縦の位置がデータのリスト内での位置=インデックス、横の位置がデータの数字と対応しています。

var listData = [30,70,60];

svg.selectAll("circle")
 .data(listData) // データをバインド。
 .enter()
    .append("circle")

この部分を見ると、まず3つの数を持っている単純なリストデータを作っています。
.selectAll()で、何の要素にデータをバインドするかを指定してます。指定する前にその要素が存在していなくても大丈夫です。この場合はcircle要素とデータをつなげていますが、g要素やクラス属性などでもOKです。
.data()でデータを読み込みます。
.enter()で、リストデータ内の数分だけ、それ以下の処理を行います。
.append()でcircleを追加しています。この場合は3つのデータを含んでいるので、この段階で3つのcircle要素がHTMLに書き込まれます。ただしappendだけでは属性がないのでこの段階では画面には何も表示はされないはずです。

 

ここまででリストに含まれるデータの数(3つ)と円の数(3つ)が関連づけられています。次に.attr()で属性を設定しています。リストの中の数字(30,70,60)とリストのインデックス(0,1,2)を使って、円の横と縦の位置を変えています。

 

.attr("cx", function(d){ return d*2; })

この部分を見ると、本来は.attr(“cx”,10)という感じになるところに、function(d){ return ~}が入っています。このdが、リストの中のそれぞれの数字を表しています。つまりdは1周目は30、2周目は70、3周目は60になります。このdに2をかけてreturnすることで、cxに設定する数字として値が出力されます。

.attr("cy", function(d,i){ return (i+1)*50; });

この部分を見ると、function(d,i)となっています。こうすることで、iをリストのインデックスとして使えます。つまり1周目は0、2周目は1、3周目は2となります。
cxは縦の位置ですが、縦が0だと円が画面の一番上に来てしまって半分しか見えないので、(i+1)で1から始まるようにしています。それに50をかけた数字をreturnで出力しています。

 

円の色や大きさも変える

色や大きさもデータに対応して変えられます。

var listData = [30,70,60];

svg.selectAll("circle")
 .data(listData)
 .enter()
  .append("circle")
 	.attr("cx",100)
	.attr("stroke-width",1)
	.attr("stroke","black")
 	.attr("r",function(d){ return d/3; })
	.attr("cy", function(d){ return d*2; })
	// 条件文を使って、数字の大きさによって色を変えている。
 	.attr("fill", function(d){ if(d<=50){ return "red"; }else{return "green"; } });

結果:
d3基本3-2data_if
解説:
ここでは円を縦に並べて、rとfillもデータにしたがって変えています。

// 条件文を使って、数字の大きさによって色を変えている。
    .attr("fill", function(d){ if(d<=50){ return "red"; }else{return "green"; } });

fillの部分を見ると、function(d){}の中にif文があり、50より小さいと赤く、それ以外なら緑になるようにしています。if文を使えば数字をこのように文字列として出力することもできます。

 

連想配列を使う + 円にテキストを付け加える

データを使って2種類以上のsvg要素を作ることもできます。また、今回はリストではなく連想配列を使ってみます。

var dicData = [{"科目": "国語", "点数":30},
								{"科目": "数学", "点数":70},
								{"科目": "社会", "点数":60},];		

var boxes = svg.selectAll("boxes")
					   .data(dicData)
					   .enter()
							.append("g");

// g要素に円要素を加えている。
boxes.append("circle")
			.attr("cy",100)
			.attr("r",10)
			.attr("fill","blue")
			.attr("cx", function(d){ return d["点数"]*2; });

// g要素にテキスト要素を加えている。
boxes.append("text")
			.text(function(d){ return d["科目"]; })
			.attr("fill","gray")
			.attr("y",80)
			.attr("x", function(d){ return d["点数"]*2; })
			.attr("font-size", 10);

結果:
d3基本3-4dictionary
解説:

var dicData = [{"科目": "国語", "点数":30},
                                {"科目": "数学", "点数":70},
                                {"科目": "社会", "点数":60},];  

この連想配列には科目と点数という2種類のキーを使っています。さらに連想配列はリストに入れられています。
連想配列から値を取り出すには、function(d){ return d[“点数”]*2; }のように、d[]を使うか、d.でアクセスします。

さて、一つのデータからsvg要素を2種類作るときには注意が必要です。単純にappend(“circle”)と.attr()の後にappend(“text”)を作っても、テキストはうまく表示されません。なぜならこうすると、circle要素の内側にtext要素が入ってしまうからです。

circleの中にtextが入っているのでtextは表示されない。
circleの中にtextが入っているのでtextは表示されない。

円やテキストのようなグラフィック要素は、必ずgやsvgのようなコンテナ要素の中に入るようにしましょう!

ここではcircleとtextをg要素に入れるために、boxesという変数でgを作った所で区切りをつけています。circleとtextはどちらもboxes.から始まっていることに注目してください。
そうするとcircleとtextがgの下に並置されます。

circleとtextがgの下に並置されている
circleとtextがgの下に並置されている

このようにすると、種類の異なるグラフィック要素をひとつのデータから作ることができます。

 

ネストした奥行きがあるデータを使う

リストの中に連想配列があり、さらにその連想配列の中にリストがある場合があります。ここではそのような奥行きがあるデータを表示してみます。

var nestedData = [{"科目": "国語", "点数": 30, "過去の点数":[20,50,10]},
								{"科目": "数学", "点数": 70, "過去の点数":[96,88,73]},
								{"科目": "社会", "点数": 60, "過去の点数":[76,88,66]}];

var boxes = svg.selectAll("g")
						 .data(nestedData)
						 .enter()
						  .append("g");

	boxes.append("circle")
			.attr("r",10)
			.attr("fill","blue")
			.attr("cy",function(d,i){ return (i+1)*50; })
			.attr("cx", function(d){ return d["点数"]*2; });

	boxes.selectAll("rect")
			.data(function(d){ return d["過去の点数"]; }) // "過去の点数"を新たなデータとして使う。
		  .enter()
			 .append("rect")
			 .attr("y",200)
			 .attr("width",10)
			 .attr("height",10)
			 .attr("fill","orange")
			 .attr("stroke","black")
			 .attr("x", function(d){ return d*2; });

結果:
d3基本3-5nested_data
解説:

var nestedData = [{"科目": "国語", "点数": 30, "過去の点数":[20,50,10]},
                                {"科目": "数学", "点数": 70, "過去の点数":[96,88,73]},
                                {"科目": "社会", "点数": 60, "過去の点数":[76,88,66]}];

今回のデータは、このようにリストの中に連想配列が入っていて、そのキーは科目、点数、過去の点数になっています。過去の点数の中にさらにリストが含まれています。どうやってこのリストのデータを使うかが問題です。

circleを追加して属性を設定するまでは、ふつうに点数の値を使っています。その下でrectを作る時を見てください。

boxes.selectAll("rect")
		.data(function(d){ return d["過去の点数"]; })

2回目に登場するdata()の中で、function(d)を使って”過去の点数”をデータとして入れています。つまり、データの一部をさらにデータとして読み込むことで、孫にあたるデータを使うことができるようになります。
このdは、一周目ならば、{“科目”: “国語”, “点数”: 30, “過去の点数”:[20,50,10]}のことです。d[“過去の点数”]をデータに入れると、[20,50,10]がデータとして取り込まれてその下のチェインから使うことができます。
使う場合は同じくfunction(d)を使うと、最後に読み込んだデータつまり[20,50,10]を使えます。
こうすることで、奥のデータを新たなデータとして使うことができます。

詳しくいうと、一周目では国語の点数である30をcircleの属性として使った後、過去の点数のリストをrectに使っています。このrectは3つ作られ、それぞれ20、50、10のデータとつながっています。rectのx属性にそれぞれのデータを使うことで、過去の点数に合わせて四角形の横の位置が変わるようになっています。

実際のhtmlはリンク先にあります:
2.リストデータを使って円を描く
3.円の色や大きさも変える
4.連想配列を使う + 円にテキストを付け加える
5. ネストした奥行きがあるデータを使う
次のチュートリアルではスケールを扱いたいと思います。


コメントを残す