D3 で棒グラフを作る

ファイルの準備

d3.js を使って、棒グラフを作ってブラウザで表示します。下準備で作ったテンプレートフォルダをコピーして、ファイルを用意します。

barchart/
  index.html
  js/
    d3.js
    d3.min.js
    main.js
  data/
    tokyo.csv

https://www.e-stat.go.jp/ から
都道府県,年齢(5歳階級),男女別人口-総人口,日本人人口 のデータをダウンロードして整形し、東京都の5歳階級別人口を tokyo.csv として保存します。このファイルを読み込んで グラフにします。

年齢5歳階級,人口【千人】
0~4歳,539
5~9歳,516
10~14歳,495
15~19歳,554
20~24歳,867
25~29歳,911
30~34歳,961
35~39歳,1013
40~44歳,1109
45~49歳,1167
50~54歳,1005
55~59歳,810
60~64歳,687
65~69歳,797
70~74歳,750
75~79歳,647
80~84歳,500
85歳以上,494

JavaScript の記述

main.js ファイルに処理を記述していきます。

グラフの描画領域をつくる

画像のサイズ(幅・高さ)とグラフを描画する範囲を決めます。幅・高さはピクセル数で指定します。

//マージン設定
const margin = { left:80, right:20, top:50, bottom:100 };

//SVGのサイズ設定
const svgWidth = 1000;
const svgHeight = 600;

//グラフのサイズ設定
const chartWidth = svgWidth - margin.left - margin.right;
const chartHeight = svgHeight - margin.top - margin.bottom;

html の body 要素を選択して、svg 要素を追加します。svg 要素にグラフを描画するグループ要素を追加します。グループの座標を左上原点からマージン分移動します。

//SVG要素を追加
const svg = d3.select("body").append("svg")
            .attr("width", svgWidth)
            .attr("height", svgHeight);

//グループ要素の追加
const g = svg.append("g")
        .attr("transform", "translate(" + margin.left + ", " + margin.top + ")");

CSV データを読み込む

csv ファイルからデータを読み込みます。d3 組み込みの d3.csv を使います。ほかに、d3.tsv や d3.json もあり、タブ区切りテキストや json ファイルから読み込みできます。ファイルから読み取った直後は数値も文字列になっています。人口の列の値を文字列から数値に変換します。

//CSVファイルを読み込み
d3.csv("data/tokyo.csv").then(function(data){
    
    //人口【千人】列の値を数値に変換する
    data.forEach(function(d) {
        d["人口【千人】"] = +d["人口【千人】"];
    });
    
    //以下読み込んだデータを使って処理を行う
    
})

スケール

d3 のスケールを利用して、データ値を画面の座標値に変換します。棒グラフの作成では、入力値を直線的に変換する scaleLinear と、幅に変換するscaleBand を使います。domain は入力値の範囲、range は出力値の範囲です。scaleBand では padding で棒グラフの棒の間隔を調節します。padding が0で棒と棒がくっつきます。xScale の domain には map で “年齢5歳階級” の値の配列を作って渡します。range は0からグラフの幅までです。yScale の domain の上限は、d3.max を使い “人口【千人】” の最大値に設定します。グラフが下から上に伸びるように、range は、(0からグラフの高さでなく) グラフの高さから0までと、最大値と最小値を反転して指定します。

// Xスケール
const xScale = d3.scaleBand()
    .domain(data.map(function(d){ return d["年齢5歳階級"] }))
    .range([0, chartWidth])
    .padding(0.2);

// Yスケール
const yScale = d3.scaleLinear()
    .domain([0, d3.max(data, function(d) { return d["人口【千人】"] })])
    .range([chartHeight, 0]);

縦軸横軸のメモリを作ります。axisBottom は下用、axisLeft は左用の軸を作ります。軸にスケールを渡します。svg にグループを追加し、call で軸をよびだします。そのままだと原点が基準になるので、X軸はグラフの高さ分だけ座標を下にずらします。

// X軸
const xAxisCall = d3.axisBottom(xScale);
g.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + chartHeight +")")
    .call(xAxisCall);

// Y軸
const yAxisCall = d3.axisLeft(yScale);
g.append("g")
    .attr("class", "y axis")
    .call(yAxisCall);

棒を描画する

データと要素を結びつけ、グラフの棒を描画します。g.selectAll(“rect”) で、g要素内の rect 要素を、まだ追加されていないものも含めてすべて参照し、.data(data) で、データと結びつけます。rects.enter().append(“rect”) で、データの数だけ rect 要素を追加します。棒の開始位置のy座標は、データの “人口【千人】” 値を yScaleで変換したもの、x座標は、 データの “年齢5歳階級” を xScale で変換したもので、棒の高さは、棒の開始位置をグラフの高さから引いた分、棒の幅は xScale の bandwidth です。塗りをグレーにしておきます。

// 棒を描く
const rects = g.selectAll("rect")
    .data(data);
        
rects.enter()
    .append("rect")
        .attr("y", function(d){ return yScale(d["人口【千人】"]); })
        .attr("x", function(d){ return xScale(d["年齢5歳階級"]) })
        .attr("height", function(d){ return chartHeight - yScale(d["人口【千人】"]); })
        .attr("width", xScale.bandwidth)
        .attr("fill", "grey");

ここまでの main.js は以下のようになります。

//マージン設定
const margin = { left:80, right:20, top:50, bottom:100 };

//SVGのサイズ設定
const svgWidth = 1000;
const svgHeight = 600;

//グラフのサイズ設定
const chartWidth = svgWidth - margin.left - margin.right;
const chartHeight = svgHeight - margin.top - margin.bottom;

//SVG要素を追加
const svg = d3.select("body").append("svg")
            .attr("width", svgWidth)
            .attr("height", svgHeight);

//グループ要素の追加
const g = svg.append("g")
        .attr("transform", "translate(" + margin.left + ", " + margin.top + ")");

//CSVファイルを読み込み
d3.csv("data/tokyo.csv").then(function(data){
    
    //人口【千人】列の値を数値に変換する
    data.forEach(function(d) {
        d["人口【千人】"] = +d["人口【千人】"];
    });
    
    //以下読み込んだデータを使って処理を行う
    // Xスケール
    const xScale = d3.scaleBand()
        .domain(data.map(function(d){ return d["年齢5歳階級"] }))
        .range([0, chartWidth])
        .padding(0.2);
    
    // Yスケール
    const yScale = d3.scaleLinear()
        .domain([0, d3.max(data, function(d) { return d["人口【千人】"] })])
        .range([chartHeight, 0]);

    // X軸
    const xAxisCall = d3.axisBottom(xScale);
    g.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + chartHeight +")")
        .call(xAxisCall);

    // Y軸
    const yAxisCall = d3.axisLeft(yScale);
    g.append("g")
        .attr("class", "y axis")
        .call(yAxisCall);
    
    // 棒を描く
    const rects = g.selectAll("rect")
        .data(data);
        
    rects.enter()
        .append("rect")
            .attr("y", function(d){ return yScale(d["人口【千人】"]); })
            .attr("x", function(d){ return xScale(d["年齢5歳階級"]) })
            .attr("height", function(d){ return chartHeight - yScale(d["人口【千人】"]); })
            .attr("width", xScale.bandwidth)
            .attr("fill", "grey");
    
})

これで bar フォルダで http-server を起動してブラウザからローカルサーバーにアクセスすると、以下のような棒グラフが表示できます。次回以降グラフの見栄えを少し整えます。