「D3でCSVファイルを読み込む」では、CSVファイルからデータを読み込んで表示することができました。ここではもう少し複雑なデータの視覚化を行ってみます。
1945年と2019年の1年間の気温の変化を可視化する
365日の気温の変化を色で可視化してみます。既に作成したcsv_import.htmlファイルを改変します。
CSVファイルは以下のデータを使用します。htmlファイルと同じ階層(testServerフォルダ内)に置いてください。
このファイルは気象庁のサイトからダウンロードしています。
CSVファイルが2枚入っているので、Excelで2枚とも開き、以下のように片方のファイルにコピーしましょう。1945年と2019年はたまたま閏年がある歳なので、日数が一致しています。2種のデータを扱い際は必ず個数が同じものを選びます。
3行目までは削除し、4行目を「date2019, temp2019, date1945, temp1945」に変更します。
このファイルの文字コードは必ず「UTF-8」で保存してください。ファイル名は「temp_tokyo_1945_2019.csv」としておきます。このように、データを作成する場合には列の先頭にアフファベットで列名(カラム名)を記入してください。
366日分のバーを表示する必要があるので、表示画面の幅を1500ピクセルにします。また、最初に表示する年を1945年に設定します。
var w = 1500;
var h = 300;
var year = 1945;
CSVファイルのリンクを変更します。
d3.csv("temp_tokyo_1945_2019.csv").then(function(dataset){
xScaleとyScaleを決めます。この際、1945年と2019年の両方の年での最低気温と最高気温を決める必要があるため、以下のコードに変更します。
var xScale = d3.scaleBand()
.domain(d3.range(dataset.length)) //datasetの数を計算
.rangeRound([0, w]) //range()と同じ機能だが、整数値にする
.paddingOuter(0.5); //バーの外側のpadding
//1945年と2019年の1番低い温度を検索する
var min1945 = d3.min(dataset, function(d) {
return parseFloat(d.temp1945);
});
var min2019 = d3.min(dataset, function(d) {
return parseFloat(d.temp2019);
});
//1945と2019の両方で一番低い気温を決定
var min = d3.min([min1945, min2019]);
//1945年と2019年の1番高い温度を検索する
var max1945 = d3.max(dataset, function(d) {
return parseFloat(d.temp1945);
});
var max2019 = d3.max(dataset, function(d) {
return parseFloat(d.temp2019);
});
//1945と2019の両方で一番高い気温を決定
var max = d3.max([max1945, max2019]);
//最低気温と最高気温に基づいてスケールを作成
var yScale = d3.scaleLinear()
.domain([min, max])
.rangeRound([0, h]);
rectのy属性とheight属性を変更します。さらに、このサンプルのバーは青一色にします。
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
//1945年の温度をyScaleで変換
return h - yScale(parseFloat(d.temp1945));
})
.attr("width", xScale.bandwidth())
.attr("height", function(d) {
return yScale(parseFloat(d.temp1945));
})
.attr("fill", "blue")
mouseoverのツールチップのラベルを変更します。
.on("mouseover", function(event, d) {
d3.select(this)
.attr("fill", "red");
//選択されたDOM要素(ここではdiv)の座標を取得。
var xPosition = parseFloat(d3.select(this).attr("x")) + xScale.bandwidth() / 2;
var yPosition = parseFloat(d3.select(this).attr("y")) + 14;
//tooltipラベルを作成
d3.select("#tooltip")
.style("top", yPosition + "px")
.style("left", xPosition + "px")
.select(".date")
.text(function(){
if(year == 1945){
return d.date1945;
}else{
return d.date2019;
}
});
d3.select("#tooltip")
.select(".temp")
.text(function(){
if(year == 1945){
return d.temp1945 + "度";
}else{
return d.temp2019 + "度";
}
});
//tooltipを表示
d3.select("#tooltip").classed("hidden", false);
})
マウスアウトのイベントを以下のように変更します。
.on("mouseout", function(d) {
d3.select(this)
.attr("fill", "blue");
//tooltippを隠す
d3.select("#tooltip").classed("hidden", true);
});
ボタンで2つの年代の気温を交互に表示する
rectのマウスアウトの下に、ボタンが押された時のイベントを定義します。
//ボタンをクリックして新しいデータに更新
d3.selectAll("button") //selectAllにすることが重要
.on("click", function() {
//ボタンのidを取得
var buttonID = d3.select(this).attr("id");
if (buttonID == "button1945") { //1945年ボタンの場合、
year = 1945;
}else{ //それ以外(2019年ボタン)
year = 2019;
}
svg.selectAll("rect")
.data(dataset)
.transition()
.duration(1000)
.attr("y", function(d) {
if(year == 1945){
return h - yScale(parseFloat(d.temp1945));
}else{
return h - yScale(parseFloat(d.temp2019));
}
})
.attr("height", function(d) {
if(year == 1945){
return yScale(parseFloat(d.temp1945));
}else{
return yScale(parseFloat(d.temp2019));
}
});
});
ツールチップのdivの下にボタンを定義します。
<div id="tooltip" class="hidden">
<p><strong class="date">Label Name</strong></p>
<p><span class="temp">0</span></p>
</div>
<button type="button" id="button1945">1945年</button>
<button type="button" id="button2019">2019年</button>
ボタンのマウスオーバー用とrectの枠線の定義をCSSで行います。
button:hover {
background-color: #deb887; /*ボタンのマウスオーバー時の色*/
}
svg{
display: block; /*ボタンに対して下にレイアウト*/
}
rect{
stroke:white;
}
ボタンを押すと、1945年と2019年の気温が入れ替わります。2019年の方が全体的に暑い日が増えていることが分かります。
折れ線グラフを追加する
ツールチップの表示の後でボタンイベントの前に以下のコードを追加します。
svg.append("path")
.datum(dataset)
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 1)
.attr("d", d3.line()
.x(function(d, i) { return xScale(i); })
.y(function(d){
//1945年の温度をyScaleで変換
return h - yScale(parseFloat(d.temp1945));
}));
1945年の折れ線グラフが表示されます。ボタンを押すことによって2つの年代の気温を交互に表示するため、ボタンアクションの末尾にpathを追加します。
//ボタンをクリックして新しいデータに更新
d3.selectAll("button") //selectAllにすることが重要
.on("click", function() {
//ボタンのidを取得
var buttonID = d3.select(this).attr("id");
if (buttonID == "button1945") { //1945年ボタンの場合、
year = 1945;
}else{ //それ以外(2019年ボタン)
year = 2019;
}
svg.selectAll("rect")
.data(dataset)
.transition()
.duration(1000)
.attr("y", function(d) {
if(year == 1945){
return h - yScale(parseFloat(d.temp1945));
}else{
return h - yScale(parseFloat(d.temp2019));
}
})
.attr("height", function(d) {
if(year == 1945){
return yScale(parseFloat(d.temp1945));
}else{
return yScale(parseFloat(d.temp2019));
}
});
svg.selectAll("path")
.datum(dataset)
.transition()
.duration(500)
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 1)
.attr("d", d3.line()
.x(function(d, i) { return xScale(i); })
.y(function(d){
if(year == 1945){
return h - yScale(parseFloat(d.temp1945));
}else{
return h - yScale(parseFloat(d.temp2019));
}
})); //svg.selectAll("path")
}); //d3.selectAll("button")
アニメーションによって、折れ線グラフが動きます。
参考:以下のサンプルは、温度を明暗に変換しています。他のサンプルに比べるとちょっと難しいですが、参考にしてみてください。
また、以下のサンプルは色をつけたものです。