今回は、Reactでチャートを描画するライブラリ、Rechartsを使ってレーダーチャートを描画します。

早速余談ですが地名からじゃんけん力を算出してじゃんけんできるサービスをつくりました。グー力(りょく)とかが算出されます。残念ながら対人戦はできません。

https://next-fws.vercel.app

janken-screen

が、こんな数字見せられても心底意味がわからないのでRechartsを使ってレーダーチャートで表現することにします。チャートにしたところで意味がわからないことに変わりはないのですが。

導入

Reactでチャートを描画できるライブラリはいろいろあるみたいです。中でも今回利用するRechartsは断トツでスター数が多いようですね。

参考: https://qiita.com/quzq/items/8dc0ab885ab6a3c9cd77

今回はレーダーチャートを作成しますが、もちろん他の色々なチャートを描画することができます。棒グラフや折れ線グラフはもちろん、FunnelChart(ピラミッドみたいなやつ)やTreemap(市場規模マップとかで見るようなやつ)等も描画できます。面白い。

さて、まずはrechartsを入れます。

https://recharts.org/en-US

$ yarn add recharts

描画

まずは公式のサンプルを描画してみましょう。下記コードを適当なコンポーネントにコピペしてください。

import {
  Radar,
  RadarChart,
  PolarGrid,
  PolarAngleAxis,
  PolarRadiusAxis
} from "recharts";

const data = [
  {
    subject: "Math",
    A: 120,
    B: 110,
    fullMark: 150
  },
  {
    subject: "Chinese",
    A: 98,
    B: 130,
    fullMark: 150
  },
  {
    subject: "English",
    A: 86,
    B: 130,
    fullMark: 150
  },
  {
    subject: "Geography",
    A: 99,
    B: 100,
    fullMark: 150
  },
  {
    subject: "Physics",
    A: 85,
    B: 90,
    fullMark: 150
  },
  {
    subject: "History",
    A: 65,
    B: 85,
    fullMark: 150
  }
];

const radar = (
  <RadarChart
    cx={300}
    cy={250}
    outerRadius={150}
    width={500}
    height={500}
    data={data}
  >
    <PolarGrid />
    <PolarAngleAxis dataKey="subject" />
    <PolarRadiusAxis />
    <Radar
      name="Mike"
      dataKey="A"
      stroke="#8884d8"
      fill="#8884d8"
      fillOpacity={0.6}
    />
  </RadarChart>
)

このraderコンポーネントを使うと、こんなチャートが表示されるはずです。

chart-sample

実データを入れて描画する

propsを渡して、それを表示するようにします。渡す値は各都市のじゃんけん力です。

こんな感じでコンポーネント化

components/RadarChart.js

import { PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart } from "recharts";

const RadarChartComponent = (props) => {
  const data = [
    {
      subject: "グー",
      A: props.gu,
      fullMark: 2
    },
    {
      subject: "チョキ",
      A: props.choki,
      fullMark: 2
    },
    {
      subject: "パー",
      A: props.pa,
      fullMark: 2
    }
  ];

  return (
    <RadarChart
      cx={300}
      cy={250}
      outerRadius={150}
      width={500}
      height={500}
      data={data}
    >
      <PolarGrid/>
      <PolarAngleAxis dataKey="subject"/>
      <PolarRadiusAxis/>
      <Radar
        name="janken"
        dataKey="A"
        stroke="#8884d8"
        fill="#8884d8"
        fillOpacity={0.6}
      />
    </RadarChart>
  )
}

export default RadarChartComponent

ちなみにRadarChartのdataのfullMarkはうまく動かない説がありました。

https://github.com/recharts/recharts/issues/933

これを表示してみます。

      <div style={{ display: 'flex' }}>
        <RadarChart
          gu={result.guPower}
          choki={result.chokiPower}
          pa={result.paPower}
        />

        <RadarChart
          gu={result.enemyGuPower}
          choki={result.enemyChokiPower}
          pa={result.enemyPaPower}
        />
      </div>

result-charts

良いですね。しかしまだ比較するのがちょっと面倒です。重ねてしまいましょう。

components/JankenResults.js

import { PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart } from "recharts";

const JankenResults = (props) => {
  const data = [
    {
      subject: "グー",
      choice: props.gu,
      enemy: props.enemyGu,
      fullMark: 2
    },
    {
      subject: "チョキ",
      choice: props.choki,
      enemy: props.enemyChoki,
      fullMark: 2
    },
    {
      subject: "パー",
      choice: props.pa,
      enemy: props.enemyChoki,
      fullMark: 2
    }
  ];

  return (
    <RadarChart
      cx={300}
      cy={250}
      outerRadius={150}
      width={500}
      height={500}
      data={data}
    >
      <PolarGrid/>
      <PolarAngleAxis dataKey="subject"/>
      <PolarRadiusAxis/>
      <Radar
        name="choice"
        dataKey="choice"
        stroke="#8884d8"
        fill="#8884d8"
        fillOpacity={0.6}
      />
      <Radar
        name="enemy"
        dataKey="enemy"
        stroke="#82ca9d"
        fill="#82ca9d"
        fillOpacity={0.6}
      />
    </RadarChart>
  )
}

export default JankenResults

RadarChartコンポーネントの子にRadarを複数置きます。dataKeyをちゃんと指定してあげるのがポイントですね。

結果はこんな感じ

result-kasanari

それぞれの力関係がわかりやすくなりましたね。

ちなみに、RechartsのレーダーチャートではRadarChartコンポーネントに渡す子コンポーネントによって描画オプションをカスタマイズすることができます。他のライブラリだと、RadarChartコンポーネントに渡すpropsによってカスタマイズしたりしてますね。

例えばこんな感じにすると、

    <RadarChart
      cx={300}
      cy={250}
      outerRadius={150}
      width={500}
      height={500}
      data={data}
    >
      <PolarGrid/>
      <PolarAngleAxis dataKey="subject"/>
      <Radar
        name="choice"
        dataKey="choice"
        stroke="#8884d8"
        fill="#8884d8"
        fillOpacity={0.6}
      />
      <Radar
        name="enemy"
        dataKey="enemy"
        stroke="#82ca9d"
        fill="#82ca9d"
        fillOpacity={0.6}
      />
      <Legend />
    </RadarChart>

result-option

各チャートの色が何を表しているのかラベルを表示したり、尺度(?)ポイント(?)が表示されなくなったりします。

渡せるものはここに書いてあります。

https://recharts.org/en-US/api/RadarChart

まとめ

というわけで、チャートの描画でした。とても簡単ですね。
Reactでチャートを描画するライブラリはいろいろとあるので、他のものも試してみると楽しいかもしれません。大量のスターがついてるものがたくさんあります。

ちなみに今回題材にした超絶都市じゃんけんは、弊社のイベント mof1week にて作ったものです。1週間でなにか作るというイベントです。
スキーマファーストのGraphQLサーバに触れてみたいなと思い、Goとgqlgenをキャッチアップして作りました。フロントはNextで適当に。プロダクトはクソみたいなものですが、知らない技術に触るのは楽しかったです。

以上、Reactでレーダーチャート描画でした。