D3.js 散布図グラフを段階的に描画して説明 - scaleLinear(), domain(), range(), axisBottom()
散布図グラフの作成方法
簡単なグラフのサンプルとして、散布図を描いてみる。
散布度または変散度は、変量が散らばっている程度を1つの数で表した値である。
座標点を打つ
今回は次のデータを使用する。
var dataset = [ [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88] ];
[ ]は配列であり、[[x座標1, y座標1], [x座標2, y座標2], ...]のような形式の2次元配列データである。
まず、座標を円を表示するcircleで表示してみる。
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return d[0]; })
.attr("cy", function(d) { return d[1]; })
.attr("r", 4);
全体のコードは次のとおりである。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
var svg = d3.select("body").append("svg").attr("width", 700).attr("height", 100);
var dataset = [ [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88] ];
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return d[0]; })
.attr("cy", function(d) { return d[1]; })
.attr("r", 4);
</script>
</body>
</html>
circleに割り当てたデータは2次元配列なので、circleには[x座標, y座標]のデータが割り当てられる。たとえば最初のcircleには[5, 20]が割り当てられる。このデータをcx、cy属性にそれぞれ設定している。
座標点をテキストで表示する
次に、座標位置をx座標、y座標の形式でテキスト表示してみる。
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("x", function(d) { return d[0]; })
.attr("y", function(d) { return d[1]; })
.attr("fill", "red")
.text(function(d) {
return d[0] + "," + d[1];
});
全体のコードは次のとおりである。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
var svg = d3.select("body").append("svg").attr("width", 700).attr("height", 100);
var dataset = [ [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88] ];
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return d[0]; })
.attr("cy", function(d) { return d[1]; })
.attr("r", 4);
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("x", function(d) { return d[0]; })
.attr("y", function(d) { return d[1]; })
.attr("fill", "red")
.text(function(d) {
return d[0] + "," + d[1];
});
</script>
</body>
</html>
x座標は右へ向かって増えるが、y座標は下へ向かって増えることに注意する。
スケール変換
スケール変換には、次のD3関数を使用する。
var scale = d3.scaleLinear()
.domain([0, 500])
.range([0, 100]);
この関数は、domainで指定した範囲をrangeで指定した範囲へ変換する関数を、scaleという変数に設定する。
たとえば次のように呼び出すことができ、呼び出すと20が返される。
scale(100);
これは[0,500]の範囲を[0,100]の範囲へ変更した、つまり座標を5分の1にした結果である。100 / 5 = 20。
これをグラフに適用してみる。
グラフの幅と高さを次のように設定する。
var width = 400;
var height = 300;
比率を4:3に設定した。
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[0]; })])
.range([0, width]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([height, 0]);
ここではデータの最大値を求めるためにd3.max(..)を使用した。d3.maxは第1引数に配列を指定し、第2引数に戻り値を返す関数を指定できる。
y座標は反転させたいので、rangeの第1引数に大きな値を入れている。
この関数を使用して再描画する。
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.attr("r", 4);
全体のコードは次のとおりである。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
// ここにコードを記述する。
var dataset = [ [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88] ];
var width = 400;
var height = 300;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[0]; })])
.range([0, width]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([height, 0]);
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.attr("r", 4);
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("x", function(d) { return xScale(d[0]); })
.attr("y", function(d) { return yScale(d[1]); })
.attr("fill", "red")
.text(function(d) {
return d[0] + "," + d[1];
});
</script>
</body>
</html>
y座標は下側が小さくなり、縦横比も4:3になった。
軸を描画する
次に軸を描画する。これにはD3の関数が用意されている。
var axisX = d3.axisBottom(xScale);
svg.append("g")
.call(axisX);
先ほどのscaleと一緒に使用する。下側の軸を表すd3.axisBottomのほかに、d3.axisTop、d3.axisRight、d3.axisLeftがある。これをcall関数で呼び出すと、次のように軸を描画してくれる。
上のコードを適用した全体のコードは次のとおりである。軸があるため、text表示は削除した。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
var dataset = [ [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88] ];
var width = 400;
var height = 300;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[0]; })])
.range([0, width]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([height, 0]);
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.attr("r", 4);
var axisX = d3.axisBottom(xScale);
svg.append("g")
.call(axisX);
</script>
</body>
</html>
座標点と軸位置の調整
前の例では、位置と軸を表示するための幅を考慮していない。そのため次のように位置を移動する。
var axisX = d3.axisBottom(xScale);
var padding = 30;
svg.append("g")
.attr("transform", "translate(" + 0 + "," + (height-padding) + ")")
.call(axisX);
これを考慮すると、グラフを描画するコードは次のようになる。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
var dataset = [ [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88] ];
var width = 400;
var height = 300;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var padding = 30;
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[0]; })])
.range([padding, width - padding]);
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d[1]; })])
.range([height - padding, padding]);
var axisx = d3.axisBottom(xScale);
var axisy = d3.axisLeft(yScale);
svg.append("g")
.attr("transform", "translate(" + 0 + "," + (height - padding) + ")")
.call(axisx);
svg.append("g")
.attr("transform", "translate(" + padding + "," + 0 + ")")
.call(axisy);
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(d[0]); })
.attr("cy", function(d) { return yScale(d[1]); })
.attr("fill", "SkyBlue")
.attr("r", 4);
</script>
</body>
</html>
これで散布図が完成した。円の色も空色に変更してみた。