0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

d3.jsの基本

Last updated at Posted at 2024-10-21

D3.jsを基本からまとめてみます。
今回は棒チャートを例にして、基本的な描画方法とデータの紐づけについて説明します。

Observableを使う

手っ取り早くD3.jsを使いたい方はObservableというオンラインツールを使いましょう。右上の追加ボタンからNew Notebookを選択して、Simple D3を新規追加します。コードを書くときは{}の中に記述しましょう。

スクリーンショット 2024-10-21 21.33.36.png

書き方の順番

  1. 目的の整理
  2. グラフの全体構成を考える
  3. グラフの描画領域(SVG, Scalable Vector Graphics)を定義
  4. データの準備
  5. スケールの設定
  6. データの紐つけ
  7. 要素の描画

1. 目的の整理

まず、どんなデータをどのように可視化するのかを明確にします。たとえば、「時間経過に伴う売上の推移を折れ線グラフで表示したい」という具体的な要件を書き出します。

2. グラフの全体構成を考える

次に、グラフの基本構成を考えます。以下のようなポイントを確認します。

  • 軸は何か? 横軸 (x軸) と縦軸 (y軸) に何を表示するか
  • データの範囲はどれくらいか? 横軸は日付か時間か、縦軸はどの範囲の数値か
  • グラフの種類: 折れ線グラフや棒グラフ、円グラフなどどのタイプを使うか

この時点で大まかなイメージを作り、次に具体的なコーディングに進みます。

3. グラフの描画領域(SVG, Scalable Vector Graphics)を定義

次に、グラフの描画領域(SVG)を定義します。マージン、幅、高さを決めます。この段階では、最終的なグラフのサイズ感や、軸が邪魔にならないようにマージンの調整を行います。また、チャートを描画するためのSVGコンテナを作成します。これは、グラフを表示するための「キャンバス」になります。

const width = 500;
const height = 300;
const margin = { top: 20, right: 30, bottom: 40, left: 40 };

// SVGを作成
const svg = d3.create("svg")  // d3.createを使用
    .attr("width", width)
    .attr("height", height);
  • const svg: ここで変数 svg は、作成されたSVG要素を指しており、以降のコードでこの要素に対して操作を加えるために使います。この変数名は任意の名前であり、例えば const chart や const canvas など、他の名前にしても動作に影響はありません

4. データの準備

今回は簡単な配列をデータとして用意します。

const data = [30, 86, 168, 281, 303, 365];

5. スケールの設定

D3.jsのスケールを使って、データを描画するための座標に変換します。ここでは、棒の高さと幅を設定するためにスケールを定義します。

const x = d3.scaleBand()
    .domain(d3.range(data.length))  // データ数に応じたバンド幅
    .range([margin.left, width - margin.right])
    .padding(0.1);  // 棒同士の間隔を設定

const y = d3.scaleLinear()
    .domain([0, d3.max(data)])  // データの最大値に基づくスケール
    .range([height - margin.bottom, margin.top]);  // Y軸を上下反転して設定
  • d3.scaleBand(): バンドスケールを作成しています。バンドスケールは、カテゴリごとに均等に幅を割り当てて、カテゴリごとに離散的な位置を提供します。棒グラフで、各棒の位置と幅を決めるために使われます。
  • .domain(d3.range(data.length)): スケールの 入力範囲(domain) を設定します。この場合、d3.range(data.length) は data.lengthの数(データの要素数)に応じた連続した数値配列を生成します(例: [0, 1, 2, ..., data.length - 1])。この配列が domain になり、それぞれの値が1つの棒に対応します。
  • .range([margin.left, width - margin.right]): 出力範囲(range) を設定します。xスケールの出力範囲は、棒グラフを描画する領域の左端から右端までの位置を決定します。この場合、margin.leftはグラフの左端の位置、width - margin.rightはグラフの右端の位置を示します。これにより、棒グラフが描画される領域が確定します。
  • .padding(0.1): 棒と棒の間隔を設定します。0.1は各棒の間に10%の余白を持たせることを意味します。棒が互いに少し隙間を空けて表示されます。
  • d3.scaleLinear(): リニアスケール(線形スケール)を作成しています。リニアスケールは、入力範囲(domain)と出力範囲(range)が線形に対応するスケールです。すなわち、入力範囲の値が直線的に出力範囲の値に変換されます。
  • .domain([0, d3.max(data)]): **入力範囲(domain)**を設定します。この場合、[0, d3.max(data)]は、データの最小値を0、最大値をd3.max(data)(データ配列内の最大値)として、縦軸の値の範囲を指定しています。これにより、yスケールは0から最大値までをカバーします。
  • .range([height - margin.bottom, margin.top]): **出力範囲(range)**を設定します。出力範囲はグラフの描画エリアに対応します。height - margin.bottomはグラフの描画エリアの下端を示し、margin.topは上端を示します。この範囲内にデータをマッピングします。
  • 上下反転について: HTMLでは座標の(0, 0)が左上にあるため、y軸のスケールは通常反転させて使います。つまり、0(最小値)はグラフの下側に、最大値は上側に配置されます。このため、rangeの指定が[height - margin.bottom, margin.top]という形で、下から上に変換されています。

6. データの紐つけ

次に、データをSVGのrect要素に紐づけます。d3.selectAll().data()を使ってデータと要素を結びつけます。

svg.selectAll("rect")  // SVG内のすべてのrect要素を選択。棒グラフの棒を描画するために使用される四角形の要素
    .data(data)  // D3のデータ結合機能を使い、配列 data のデータを選択したrect要素に紐づける
    .enter()  // データに対して新しい要素を作成
    .append("rect")  // rect(棒)を追加
    .attr("x", (d, i) => x(i))  // 各棒のX座標をスケールに基づいて設定
    .attr("y", d => y(d))  // 各棒のY座標を設定(データ値に基づいて高さを調整)
    .attr("height", d => y(0) - y(d))  // 棒の高さをデータ値で設定
    .attr("width", x.bandwidth())  // 棒の幅をバンド幅で設定
    .attr("fill", "steelblue");  // 色を設定
  • svg.selectAll("rect"): SVG内の全ての rect 要素を選択(最初は空)。
  • .data(data): data を選択した rect 要素に紐づける。
  • .enter(): データに対応する新しい rect 要素を作成。
  • .append("rect"): 新しい rect 要素をSVGに追加。
  • .attr("x", (d, i) => x(i)): 各棒のX座標を設定。
  • .attr("y", d => y(d)): 各棒のY座標を設定。
  • .attr("height", d => y(0) - y(d)): 各棒の高さを設定。
  • .attr("width", x.bandwidth()): 各棒の幅を設定。
  • .attr("fill", "steelblue"): 各棒の色を設定。

7. 要素の描画

次に、X軸とY軸をSVGに追加して、データをわかりやすくします。

// X軸を追加
svg.append("g")
    .attr("transform", `translate(0,${height - margin.bottom})`)  // X軸をグラフの下に配置
    .call(d3.axisBottom(x));

// Y軸を追加
svg.append("g")
    .attr("transform", `translate(${margin.left},0)`)  // Y軸を左側に配置
    .call(d3.axisLeft(y));

全体のコード

// グラフの設定
{
  const width = 500;
  const height = 300;
  const margin = { top: 20, right: 30, bottom: 40, left: 40 };
  const data = [30, 86, 168, 281, 303, 365];

  const x = d3.scaleBand()
      .domain(d3.range(data.length))
      .range([margin.left, width - margin.right])
      .padding(0.1);

  const y = d3.scaleLinear()
      .domain([0, d3.max(data)])
      .range([height - margin.bottom, margin.top]);

  const svg = d3.create("svg")  // d3.createを使用
      .attr("width", width)
      .attr("height", height);

  // 棒を追加
  svg.selectAll("rect")
      .data(data)
      .enter()
      .append("rect")
      .attr("x", (d, i) => x(i))
      .attr("y", d => y(d))
      .attr("height", d => y(0) - y(d))
      .attr("width", x.bandwidth())
      .attr("fill", "steelblue");

  // X軸を追加
  svg.append("g")
      .attr("transform", `translate(0,${height - margin.bottom})`)
      .call(d3.axisBottom(x));

  // Y軸を追加
  svg.append("g")
      .attr("transform", `translate(${margin.left},0)`)
      .call(d3.axisLeft(y));

  return svg.node();  // SVG要素を返す
}

おまけ

D3.jsの公式チュートリアル

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?