1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめてのアドベントカレンダーAdvent Calendar 2024

Day 10

【D3】scaleBand、scaleLiner、scaleSqrt の使い分け

Last updated at Posted at 2024-12-01

はじめに

この記事では、JavaScript 向けのデータ可視化ライブラリである D3 のスケール(入力値をもとにして、チャート上に表示する範囲を出力する)に関する以下の関数の使い分けについて、具体例を交えながら記載します。

開発環境

開発環境は以下の通りです。

  • Windows 11
  • Next.js 14.2.4
  • React 18.3.1
  • TypeScript 5.5.2
  • D3 7.9.0
  • @types/d3 7.4.3

ユースケース

以下のコードでは、Next.js でバブルチャートを実装しています。
X軸に element、Y軸に score を表示します。また、バブルの大きさは count で表現します。

data.ts
export const data = [
  { element: "A", score: 1, count: 2 },
  { element: "A", score: 2, count: 2 },
  { element: "A", score: 3, count: 4 },
  { element: "B", score: 1, count: 0 },
  { element: "B", score: 2, count: 5 },
  { element: "B", score: 3, count: 3 },
  { element: "C", score: 1, count: 7 },
  { element: "C", score: 2, count: 7 },
  { element: "C", score: 3, count: 1 },
];

X軸は scaleBand、Y軸は scaleLiner、バブルの大きさは scaleSqrt を使っています。

page.tsx
"use client";

import { useEffect, useRef } from "react";
import * as d3 from "d3";
import { data } from "../data";

export default function Page() {
  const svgRef = useRef<SVGSVGElement | null>(null);
  const width = 600;
  const height = 400;

  const renderChart = () => {
    // Define scales
    const xScale = d3
      .scaleBand()
      .domain(data.map((d) => d.element))
      .range([0, width]);

    const yScale = d3
      .scaleLinear()
      .domain([0, d3.max(data, (d) => d.score) || 0])
      .range([height, 0]);

    const sizeScale = d3
      .scaleSqrt()
      .domain([0, d3.max(data, (d) => d.count) || 0])
      .range([0, 30]);

    // Enable D3 API manipulate svg
    const svg = d3.select(svgRef.current);
    // Clear everything before appending new elements
    svg.selectAll("*").remove();
    // Bind data to bubbles
    const bubbles = svg.selectAll(".bubble").data(data);

    // Enter
    bubbles
      .enter()
      .append("circle")
      .attr("class", "bubble")
      .attr("fill", "teal")
      .attr("cx", (d) => xScale(d.element)! + xScale.bandwidth() / 2)
      .attr("cy", (d) => yScale(d.score))
      .attr("r", (d) => sizeScale(d.count));
  };

  useEffect(() => {
    renderChart();
  }, []);

  return <svg ref={svgRef} width={width} height={height} />;
}

image.png

scaleBand

scaleBand は離散値(カテゴリなど)を等間隔に表示します。
今回のユースケースでは、element(A、B、C)を 0 から width (600) の間に表示しています。

page.tsx
    const xScale = d3
      .scaleBand()
      .domain(data.map((d) => d.element))
      .range([0, width]);

scaleLiner

scaleLiner は連続値を等間隔に表示します。
今回のユースケースでは、score(1、2、3)を 0 から height (400) の間に表示しています。

page.tsx
    const yScale = d3
      .scaleLinear()
      .domain([0, d3.max(data, (d) => d.score) || 0])
      .range([height, 0]);

上記のサンプルコードの range の引数の配列を反対にする(range[0, hegiht])と、チャートの上下も反対になります。

scaleSqrt

scaleSqrtscaleLiner と同じく連続値を入力値として受け取ります。ただ、表示の仕方が異なります。scaleLiner が入力値の大小を直線の長短で表現するのに対し、scaleSqrt では、点の大小で表現します。
今回のユースケースでは、count(0、...7)を 0 から 30 の大きさで表示しています。

page.tsx
    const sizeScale = d3
      .scaleSqrt()
      .domain([0, d3.max(data, (d) => d.count) || 0])
      .range([0, 30]);

まとめ

まとめると以下の通りです。

Scale 入力 出力 ユースケース
scaleBand 離散値、カテゴリ 連続値 カテゴリの軸方向の表示位置
scaleLiner 連続値 連続値 数値の軸方向の表示位置、線の表示位置
scaleSqrt 連続値 連続値 バブルなどの大きさ

参考

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?