😽

rechartsの円グラフ入門(TypeScript)

2024/06/16に公開

記事作成時の recharts のバージョン: 2.12.7

はじめに

React でグラフを描画するライブラリの1つにrechartsがあります。

今回、業務で recharts を使って円グラフを作成する機会があったので、公式サイトのサンプルコードの読み解きと自分なりのカスタマイズを行いました。

下記で記載するコードはすべて github 上にアップしています。
(recharts や React, TypeScript のバージョンなども github のコードを見てください)

TwoLevelPieChart

公式のサンプルコード:https://recharts.org/en-US/examples/TwoLevelPieChart

ドーナッツ状の円グラフの中に、普通の形の円グラフが入っている形状をしています。
一見2つの円グラフは何かしらの関係を持っていそうですが、実際は完全に独立しています。

import { PieChart, Pie, ResponsiveContainer, Tooltip } from "recharts";

const data01 = [
  { name: "Group A", value: 400 },
  { name: "Group B", value: 300 },
  { name: "Group C", value: 300 },
  { name: "Group D", value: 200 },
];
const data02 = [
  { name: "A1", value: 100 },
  { name: "A2", value: 300 },
  { name: "B1", value: 100 },
  { name: "B2", value: 80 },
  { name: "B3", value: 40 },
  { name: "B4", value: 30 },
  { name: "B5", value: 50 },
  { name: "C1", value: 100 },
  { name: "C2", value: 200 },
  { name: "D1", value: 150 },
  { name: "D2", value: 50 },
];

export const TwoLevelPieChart = () => {
  return (
    <ResponsiveContainer width="80%" height={400}>
      <PieChart>
        <Pie data={data01} dataKey="value" outerRadius="60%" fill="#8884d8" />
        <Pie
          data={data02}
          dataKey="value"
          innerRadius="70%"
          outerRadius="80%"
          fill="#82ca9d"
          paddingAngle={5}
          label={{ fontSize: "1.5em" }}
        />
        <Tooltip />
      </PieChart>
    </ResponsiveContainer>
  );
};

<PieChart><Pie /></PieChart>のように、
PieChartコンポーネントを親、Pieコンポーネントを子として使います。
上記のように2種類の円グラフを書きたい場合は、Pieコンポーネントを2つ使います。

Pieコンポーネントの超基本的なプロパティは以下です。

  • data
    • 円グラフに使用するデータのオブジェクトを指定します
  • dataKey
    • dataで指定したオブジェクトの中で、円グラフの値として使うプロパティを指定します
  • fill
    • 円グラフの色を指定します
  • label
    • label={true}とすると円グラフにラベルが表示されます。デフォルトはfalseです。


公式のサンプルコードからカスタマイズした点

  • Pieコンポーネントのプロパティ
    • cx, cy
      • 円グラフの中心座標を指定します
      • 公式のサンプルコードでは200などの値で指定されていますが、デフォルトはcx, cyとも50%であり、大体のケースではデフォルトのままで問題ないかと思います。
      • そのため上記のサンプルコードではプロパティの指定を省略しています。
    • outerRadius
      • 円グラフの大きさ(厳密には外側の円の大きさ)を指定します
      • デフォルトは 80%であり、こちらも基本的にはデフォルトのままで良いかと思います。
      • 上記のような2つの円グラフを重ねるケースでは、このプロパティの値を指定して調整する必要があります
        • 公式のサンプルコードでは70などの値で指定されていますが、%による指定の方がレスポンシブ対応しやすいかと思うので%での指定に変更しました。
    • innerRadius
      • デフォルトは 0%であり、これを 0 より大きくするとドーナツ型の円グラフになります。
        (値が大きいほど穴が大きいドーナツになります)
      • 公式のサンプルコードでは70などの値で指定されていますが、%による指定の方がレスポンシブ対応しやすいかと思うので%での指定に変更しました。
    • paddingAngle
      • 円グラフの要素間のスペースの大きさを指定します。デフォルトは0です。
      • 見栄えを良くするためのプロパティのため、特に指定せずとも問題ないです。
      • また説明が難しいですが、ドーナツ型ではない円グラフにこのプロパティを指定すると歪な感じになるため、基本ドーナツ型の円グラフでのみ使用することになりそうです。
    • label
      • デフォルトの設定(true)では円グラフの大きさとラベルの文字フォントの大きさが連動しません。
      • そのため、{ fontSize: "1.5em" }のようにフォントサイズをオブジェクトで渡すことでフォントサイズを可変にしています。


  • 追加したコンポーネント
    • ResponsiveContainer
      • recharts で作成したグラフをレスポンシブ対応させるには、ResponsiveContainerコンポーネントで囲む必要があるので追加しました。
      • 横幅でレスポンシブ対応させる場合は、このコンポーネントにwidth="80%"などのように相対的に指定しておけば OK です。
      • 公式:https://recharts.org/en-US/api/ResponsiveContainer
    • Tooltip
      • このコンポーネントを追加することで、ホバーした際にデータの情報(ツールチップ)の表示をさせることができます。
      • 要するにグラフの UI がより良い感じになります。
      • ツールチップがあることで困るケースはほぼ無いかと思うので、基本的には追加しておくで良いかと思います。

StraightAnglePieChart

半円の形をした円グラフです。

公式のサンプルコード:https://recharts.org/en-US/examples/StraightAnglePieChart

import { PieChart, Pie, ResponsiveContainer, Tooltip } from "recharts";

const data = [
  { name: "Group A", value: 400 },
  { name: "Group B", value: 300 },
  { name: "Group C", value: 300 },
  { name: "Group D", value: 200 },
  { name: "Group E", value: 278 },
  { name: "Group F", value: 189 },
];

export const StraightAnglePieChart = () => {
  return (
    <ResponsiveContainer width="80%" height={400}>
      <PieChart>
        <Pie
          dataKey="value"
          startAngle={180}
          endAngle={0}
          data={data}
          fill="#8884d8"
          label={{ fontSize: "1.5em" }}
        />
        <Tooltip />
      </PieChart>
    </ResponsiveContainer>
  );
};
  • Pieコンポーネントのプロパティ
    • startAngle
      • 円グラフの開始位置を指定します
      • 0で 3 時の位置、90で 12 時の位置、-90で 6 時の位置、、、のように調整できます
      • デフォルトの値は0です
    • endAngle
      • 円グラフの終了位置を指定します
      • 数値による指定方法はstartAngleと同じです
      • デフォルトの値は360です

TwoSimplePieChart

1つの描画領域に2つの円グラフを並べて表示しています。

公式のサンプルコード: https://recharts.org/en-US/examples/TwoSimplePieChart

import { PieChart, Pie, Tooltip, ResponsiveContainer } from "recharts";

const data01 = [
  { name: "Group A", value: 400 },
  { name: "Group B", value: 300 },
  { name: "Group C", value: 300 },
  { name: "Group D", value: 200 },
  { name: "Group E", value: 278 },
  { name: "Group F", value: 189 },
];

const data02 = [
  { name: "Group A", value: 2400 },
  { name: "Group B", value: 4567 },
  { name: "Group C", value: 1398 },
  { name: "Group D", value: 9800 },
  { name: "Group E", value: 3908 },
  { name: "Group F", value: 4800 },
];

export const TwoSimplePieChart = () => {
  return (
    <ResponsiveContainer width="80%" height={400}>
      <PieChart>
        <Pie
          dataKey="value"
          isAnimationActive={false}
          data={data01}
          cx="25%"
          fill="#8884d8"
          label={{ fontSize: "1.5em" }}
        />
        <Pie
          dataKey="value"
          data={data02}
          cx="75%"
          innerRadius="40%"
          outerRadius="80%"
          fill="#82ca9d"
        />
        <Tooltip />
      </PieChart>
    </ResponsiveContainer>
  );
};
  • Pieコンポーネントのプロパティ
    • isAnimationActive
      • 円グラフの表示の際にアニメーションを行うかを設定できます
      • デフォルトはtrue(アニメーションあり)です

PieChartWithCustomizedLabel

円グラフの各要素に異なる色になっており、かつラベルが円グラフの中に表示されています。
(巷でよく見る円グラフはこのデザインが多い気がします)

公式のサンプルコード:https://recharts.org/en-US/examples/PieChartWithCustomizedLabel

import { PieChart, Pie, Cell, Tooltip, ResponsiveContainer } from "recharts";

const data = [
  { name: "Group A", value: 400 },
  { name: "Group B", value: 300 },
  { name: "Group C", value: 300 },
  { name: "Group D", value: 200 },
];

const COLORS = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"];

const RADIAN = Math.PI / 180;

type Props = {
  cx: number;
  cy: number;
  midAngle: number;
  innerRadius: number;
  outerRadius: number;
  percent: number;
};
const renderCustomizedLabel = ({
  cx,
  cy,
  midAngle,
  innerRadius,
  outerRadius,
  percent,
}: Props) => {
  // ちょうどいい位置にラベルを表示するための計算
  const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
  const x = cx + radius * Math.cos(-midAngle * RADIAN);
  const y = cy + radius * Math.sin(-midAngle * RADIAN);

  return (
    <text
      x={x}
      y={y}
      fill="white"
      textAnchor={x > cx ? "start" : "end"}
      dominantBaseline="central"
      fontSize="1.5em"
    >
      {`${(percent * 100).toFixed(0)}%`}
    </text>
  );
};

export const PieChartWithCustomizedLabel = () => {
  return (
    <ResponsiveContainer width="80%" height={400}>
      <PieChart>
        <Pie
          data={data}
          dataKey="value"
          labelLine={false}
          label={renderCustomizedLabel}
          fill="#8884d8"
        >
          {data.map((_entry, index) => (
            <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
          ))}
        </Pie>
        <Tooltip />
      </PieChart>
    </ResponsiveContainer>
  );
};

円グラフの内側にラベルを表示する

Pieコンポーネントのlabelプロパティに DOM 要素を返す関数を設定することで、円グラフのラベルを自由にカスタマイズすることができます。

上記のサンプルコードでこれを行っているのがrenderCustomizedLabel関数で、円グラフの各要素(扇形の部分)の真ん中にラベルを表示するような SVG のtext要素を返しています。

真ん中の位置を求める計算はなにか組み込みの便利な関数があるのか、、、と思いきや三角関数を使って自前でゴリゴリ計算しています。

円グラフの要素ごとの色の設定

これまでの例のようにPieコンポーネントに通常の props を渡すのではなく、<Pie><Cell /></Pie>の形でCellコンポーネントを children として渡しています。

このCellコンポーネントのfillプロパティに任意の色を設定することで、円グラフの要素ごとの色を設定できるようになります。

CustomActiveShapePieChart

文量が多くなったので別記事にしました。

まとめ

recharts の円グラフの基本的な使い方を紹介しました。
正直、データ分析の領域では Tableau や Power BI などが普及していく中で、円グラフを JavaScript で書きたいニーズはとても限定的な気がしますが、
スクラッチのアプリケーションに組み込みたい場合では便利なライブラリだと感じました。
(あとやっぱり自分で作るのは楽しい)

Discussion