D3.jsで円グラフを作る方法|ラベル付きで見やすく表示する実装例

D3.jsでグラフを作ろうとすると、棒グラフや折れ線グラフに比べて、円グラフは一見シンプルに見えます。
しかし実際に実装してみると、扇形の生成、色分け、ラベル配置、中央座標、見やすさの調整など、意外と考えることが多いグラフでもあります。

特に初心者のうちは、次のような疑問を持ちやすいです。

  • D3.jsで円グラフはどう作るのか

  • d3.pie()d3.arc() は何が違うのか

  • SVG にどう描画するのか

  • ラベルはどこに置けば見やすいのか

  • パーセント表示はどう計算するのか

  • データが多いとラベルが重なるときはどうするのか

  • 凡例とラベルのどちらを使うべきか

  • ドーナツグラフにも応用できるのか

D3はモジュール構成になっており、図形生成や選択、データ結合などを組み合わせて可視化を作ります。円グラフでは、d3-shapepiearc が中核になります。

この記事では、D3.jsで円グラフを作る方法について、基本構造、サンプルコード、ラベル付き表示、見やすくする工夫、よくあるミス、ドーナツグラフへの応用まで、できるだけわかりやすく解説します。


D3.jsで円グラフを作るときに使う主な要素

D3で円グラフを作るとき、中心になるのは次の3つです。

1. d3.pie()

元データを、円グラフ用の角度情報に変換します。
たとえば、各項目の値をもとに「どこからどこまでの角度を使うか」という情報を作ります。D3のAPIでは d3-shapePies が含まれています。

2. d3.arc()

d3.pie() が作った角度情報から、SVGで描画できる扇形パスを生成します。D3のAPIでは d3-shapeArcs が含まれています。

3. d3-selection

SVG要素を選択し、pathtext を追加して画面に描画します。D3のAPIインデックスでも d3-selection は選択と属性変更のための主要モジュールとして案内されています。

つまり、流れとしては次のようになります。

  1. 配列データを用意する

  2. d3.pie() で角度データへ変換する

  3. d3.arc() で扇形パスを作る

  4. SVGへ path を描画する

  5. 必要なら text でラベルを置く


円グラフの基本構造を理解する

円グラフは「円をそのまま描く」のではなく、複数の扇形を並べて1つの円に見せる構造です。

各扇形には次のような情報があります。

  • 開始角度

  • 終了角度

  • 元データ

  • ラベル用の情報

d3.pie() は、各データ項目に対してこうした角度情報を計算します。
その結果を d3.arc() に渡すと、SVGの path に使える文字列が生成されます。D3では弧や扇形を扱うのが Arcs、円グラフ用の角度生成が Pies という役割分担です。


まずは最小構成の円グラフを作る

最初に、ラベルなしの最小構成から始めます。
データはカテゴリ名と値を持つ単純な配列にします。

サンプルデータ

<div id="chart"></div>

<script type="module">
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";

const data = [
{ label: "A", value: 30 },
{ label: "B", value: 20 },
{ label: "C", value: 25 },
{ label: "D", value: 25 }
];

const width = 400;
const height = 400;
const radius = Math.min(width, height) / 2;

const svg = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", `translate(${width / 2}, ${height / 2})`);

const pie = d3.pie()
.value(d => d.value);

const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius);

const arcs = pie(data);

svg.selectAll("path")
.data(arcs)
.join("path")
.attr("d", arc)
.attr("fill", (d, i) => d3.schemeTableau10[i % 10]);
</script>

このコードでやっていること

  • svg を作る

  • g 要素を中央へ移動する

  • d3.pie() で値から角度を計算する

  • d3.arc() で扇形パスを作る

  • path を4つ描画する

D3では selection を使ってSVG要素を追加し、attr でサイズや位置を設定します。APIインデックスにも d3-selection の選択・属性変更がまとまっています。


なぜ g を中央へ移動するのか

円グラフでは、通常は (0, 0)円の中心として描く方が扱いやすいです。
そのため、SVG全体の中央へ g を移動しておきます。

.attr("transform", `translate(${width / 2}, ${height / 2})`)

こうしておくと、d3.arc() が生成する扇形が自然に中央基準で描けます。
ラベル位置を計算するときも、この方がわかりやすいです。


d3.pie() の役割を詳しく理解する

d3.pie() は、元データをそのまま描くのではなく、円グラフ用データへ変換する関数です。

const pie = d3.pie()
.value(d => d.value);

const arcs = pie(data);

この arcs には、各要素ごとに次のような情報が入ります。

  • startAngle

  • endAngle

  • value

  • index

  • data

つまり、元の { label, value } に加えて、「円グラフのどの角度を担当するか」が付与されます。

D3 の pied3-shape の Pie 機能に属しており、Arc と組み合わせて円グラフを構成します。


d3.arc() の役割を詳しく理解する

d3.arc() は、startAngleendAngle を持つデータを受け取り、SVGの path 属性に使える文字列を生成します。

const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius);

ここで重要なポイント

  • innerRadius(0) にすると通常の円グラフ

  • innerRadius(0より大きい値) にするとドーナツグラフ

つまり、円グラフとドーナツグラフの違いは、内側半径の有無です。


ラベル付き円グラフを作る

ここからが本題です。
見やすい円グラフでは、色分けだけでなく、ラベル表示が重要になります。

まずは扇形の中にラベルを置く基本例を見てみます。

サンプルコード

<div id="chart"></div>

<script type="module">
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";

const data = [
{ label: "営業", value: 35 },
{ label: "総務", value: 20 },
{ label: "開発", value: 30 },
{ label: "人事", value: 15 }
];

const width = 500;
const height = 500;
const radius = Math.min(width, height) / 2 - 20;

const svg = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", `translate(${width / 2}, ${height / 2})`);

const color = d3.scaleOrdinal(d3.schemeTableau10);

const pie = d3.pie()
.value(d => d.value)
.sort(null);

const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius);

const labelArc = d3.arc()
.innerRadius(radius * 0.6)
.outerRadius(radius * 0.6);

const arcs = pie(data);

svg.selectAll("path")
.data(arcs)
.join("path")
.attr("d", arc)
.attr("fill", d => color(d.data.label))
.attr("stroke", "#fff")
.attr("stroke-width", 2);

svg.selectAll("text")
.data(arcs)
.join("text")
.attr("transform", d => `translate(${labelArc.centroid(d)})`)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.style("font-size", "14px")
.style("fill", "#fff")
.text(d => d.data.label);
</script>


ラベル位置に centroid を使う理由

円グラフのラベル配置では、d3.arc() が持つ centroid を使うと便利です。
これは、扇形ラベルを置くための代表的な中心位置を計算するためによく使われます。Arc は D3 の d3-shape に含まれる機能です。

コード

.attr("transform", d => `translate(${labelArc.centroid(d)})`)

ここで labelArc は、ラベル専用の半径を持つ arc です。

const labelArc = d3.arc()
.innerRadius(radius * 0.6)
.outerRadius(radius * 0.6);

つまり、「ラベルをどの半径位置に置くか」を別に決めています。

なぜ本体の arc と分けるのか

本体の扇形は外周までありますが、ラベルは少し内側に置いた方が見やすいからです。
本体用とラベル用で arc を分けると、調整がしやすくなります。

Si quieres conocer otros artículos parecidos a D3.jsで円グラフを作る方法|ラベル付きで見やすく表示する実装例 puedes visitar la categoría Zaisaitukuri.

Go up