D3.js を使って円グラフを描画するには、d3.pie()
と d3.arc()
を組み合わせて使用します。
d3.pie() 関数で扇形の角度を計算する
D3.js の d3.pie()
関数を使うと、円グラフ (pie chart) やドーナツチャート (donut chart) を描画するための 角度を計算する関数オブジェクトを生成 できます。
生成した関数にデータ配列を渡すと、各データに対応する扇形部分の開始角度 (startAngle
) と終了角度 (endAngle
) を計算してくれます。
角度はラジアンで表現されるので、180° は 3.1415 になります。
const data = [5, 3, 2] // 任意のデータ配列
const pie = d3.pie() // pie 関数の生成
const arcs = pie(data) // データ配列に角度情報を付加する
console.log(args);
[
{
"data": 5, "index": 0, "value": 5, "startAngle": 0,
"endAngle": 3.141592653589793, "padAngle": 0
},
{
"data": 3, "index": 1, "value": 3, "startAngle": 3.141592653589793,
"endAngle": 5.026548245743669, "padAngle": 0
},
{
"data": 2, "index": 2, "value": 2, "startAngle": 5.026548245743669,
"endAngle": 6.283185307179586, "padAngle": 0
}
]
任意のデータ配列を pie()
関数に渡すと、上記のように startAngle
、endAngle
といった角度情報付きデータ配列を返してくれます。
元のデータ配列の各要素は data
プロパティに格納されているので、これ以降は元のデータ配列の代わりにこの角度情報付きのデータ配列だけを使えばよいことになります(例えば、D3.js のコンポーネントの data()
メソッドにはこの配列を渡せばよい)。
TypeScript を使って、pie()
関数に渡すデータ配列の型を指定するには次のようにします。
配列型ではなく、個々の要素の型を指定することに注意してください。
単一のデータであることを強調するために、data の単数系である datum という単語を使っています。
/** 円グラフ内の各セグメントの値と装飾情報を表します。 */
type PieDatum = {
value: number
color: string
}
const data: PieDatum[] = [
{ value: 30, color: "red" },
{ value: 20, color: "blue" },
{ value: 10, color: "yellow" },
// ...
]
// value() メソッドに角度計算用のプロパティを取り出すための関数を渡します
const pie = d3.pie<PieDatum>().value((d) => d.value)
const arcs = pie(data) // 角度計算
d3.arc() 関数で SVG の path 情報に変換する
SVG にはネイティブで円グラフを描画するための要素は存在しないので、扇形の図形などを表現するための path
要素を作成しなければいけません。
D3.js の d3.arc()
関数を使用すると、扇形用の path
要素の d
属性の値を求めるための関数 (arc ジェネレーター) を生成できます。
生成した関数には、各扇形の開始角度 (startAngle
) と終了角度 (endAngle
) を渡します。
TypeScript を使用している場合は次のように型指定すると、生成された arc()
関数に正しく型情報が設定されます。
これは、arc()
関数の引数として、前述の pie()
関数で生成した角度情報付きデータ配列の各要素を渡すということを表しています(pie()
関数の戻り値は d3.PieArcDatum<PieDatum>
の配列です)。
const arc = d3.arc<d3.PieArcDatum<PieDatum>>()
.innerRadius(0)
.outerRadius(radius)
d3.pie() と d3.arc() を組み合わせて円グラフを描画する
上記で説明した関数を利用すれば、次のような手順でデータ配列を円グラフとして描画できます。
d3.pie()
を使って、データ配列から角度情報(startAngle
とendAngle
)を生成する。d3.arc()
を使って、角度情報をpath
要素用のd
属性の値に変換する。- 上記のように作成したデータをもとに
path
要素を生成する。
次の例では、データ配列 ([5, 3, 2]
) を入力情報として円グラフを描画しています。
ちなみに、扇形の色 (fill
) の設定には、d3.scaleOrdinal()
で生成したカラースケール関数 を使用しています。
<svg id="svg-7wvnsew" width="300" height="200"></svg>
<script>
const svg = d3.select("#svg-7wvnsew")
const width = +svg.attr("width")
const height = +svg.attr("height")
const radius = Math.min(width, height) / 2
const data = [5, 3, 2] // データ配列
const pie = d3.pie() // 扇形の角度を求める関数
const arc = d3.arc().innerRadius(0).outerRadius(radius) // 角度からパスを生成する関数
const color = d3.scaleOrdinal(d3.schemeCategory10) // 色を生成する関数
// 円グラフ用の g 要素を作って SVG の中央に表示するよう位置調整
const pieChart = svg.append("g")
.attr("transform", `translate(${width/2}, ${height/2}) scale(0.8)`)
// 円グラフの各扇形の path 要素を作成する
pieChart
.selectAll("path")
.data(pie(data))
.join("path")
.attr("d", arc) // 円グラフのお決まり
.attr("fill", (_, i) => color(i.toString()))
</script>
表示方法のカスタマイズ
ドーナツチャート
arc ジェネレーターの innerRadius()
メソッドで、内側の半径を設定すると、ドーナツチャートを描画することができます。
const arc = d3.arc().innerRadius(radius / 2).outerRadius(radius)
扇形の隙間
arc ジェネレーターの padAngle()
メソッドで、各扇形の間の隙間を指定することができます。
この隙間は、ラジアン単位の角度で指定するので、かなり小さい値を指定する必要があります(1 度は 0.017453 ラジアンです)。
// padAngle() を設定するときは innerRadius() も調整する
const arc = d3.arc().innerRadius(1).outerRadius(radius).padAngle(0.02)
扇形の境界を表現する方法としては、各扇形の path
要素に stroke
スタイルを設定する方法もあります。
むしろこちらの方がシンプルでよいかもしれません。
下記では分かりやすいように黄色で境界線を描画しています。
ドーナツチャートの中心にテキストを表示
ドーナツチャートの中心の隙間にテキストを表示するには、単純に SVG の text
要素を追加するだけです。
pieChart.append("text")
.attr("x", 0)
.attr("y", 0)
.attr("text-anchor", "middle") // 水平方向のアンカー
.attr("dominant-baseline", "middle") // 垂直方向のアンカー
.attr("font-size", 20)
.attr("font-weight", 600)
.attr("fill", "#666")
.text("合計:" + d3.sum(data))
扇形(円弧)の中にテキストを表示
pie(data)
で生成した各データを arc.centroid()
メソッドに渡すと、扇形の領域の中央座標(重心)を返してくれます。
これを利用して、各扇形(あるいは円弧)の中央にテキストを配置することができます。
ちょっと複雑なので全体のコードを示しておきます。