自分にやさしく学ぶプログラミング

プログラミング学習記録、備忘録

Rechartsの棒グラフにnullが含まれるデータを渡すと表示がおかしくなる場合の対処法

概要

  • Rechartsで棒グラフ作成時、値がnullであるデータがエリア外に描画される場合がある
  • nullが入りうるような場合は、YAxisのdomainを0が範囲内に入るように設定すると良さそう

参考にしたページ、引用元など

下記に記載しているコードは公式ドキュメントの棒グラフのサンプルをちょっとだけ変更したものです。
また、グラフ画像は同じく公式ドキュメントのcodesandboxのリンク先でコードを実行した結果のスクショです。

経緯

お仕事でRechartsを使ったグラフ描画機能を触っています。
RechartsはReactで使えるグラフ描画のためのライブラリです。
ぱっと綺麗なグラフが描けて、アニメーションもついてるのでいいなぁと思ってるのですが、今回ちょっとした不都合に行き当たりました。
公式ドキュメントにそのような場合についての記述が見つけられず、ちょっと戸惑ったので、解決策を書き留めておきます。

正常に表示できる場合

RechartsではデータをObjectのArrayとして渡します。
例えば下記のようなコードを実行した時、

import "./styles.css";
import React from "react";
import {
  BarChart,
  Bar,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  Legend
} from "recharts";

// これがグラフに表示されるデータ
const data = [
  {
    name: "Data A",
    value_1: 1000,
    value_2: 1500
  },
  {
    name: "Data B",
    value_1: 2000,
    value_2: 2300
  },
  {
    name: "Data C",
    value_1: 3000,
    value_2: 2800
  }
];

export default function App() {
  return (
    <BarChart
      width={500}
      height={300}
      data={data}
      margin={{
        top: 5,
        right: 30,
        left: 20,
        bottom: 5
      }}
    >
      <CartesianGrid strokeDasharray="3 3" />
      <XAxis dataKey="name" />
      <YAxis />
      <Tooltip />
      <Legend />
      <Bar dataKey="value_1" fill="#82ca9d" />
      <Bar dataKey="value_2" fill="#8884d8" />
    </BarChart>
  );
}

下図のようなグラフが表示されます。
Y軸(縦軸)は0から3000までのグラフ。左から右へ、Data A, DataB, Data Cの系列が並んでいる。

わかりやすくていいですよね。

値がnullのデータがあると表示がおかしくなる

ところが、ある状況下で表示がおかしくなる場合があります。
その状況というのは、

  • 渡されたデータの中に値がnullであるものがある
  • 他の値が全て負の値である

という場合です。

コード内の変数dataをこの状態に書き換えてみます。
まず、全て負の数にしてみます。

const data = [
  {
    name: "Data A",
    value_1: -1000,
    value_2: -1500
  },
  {
    name: "Data B",
    value_1: -2000,
    value_2: -2300
  },
  {
    name: "Data C",
    value_1: -3000,
    value_2: -2800
  }
];

するとグラフはこうなります。
Y軸(縦軸)は-3000から-1000までのグラフ。左から右へ、Data A, DataB, Data Cの系列が並んでいる。Data A のvalue_1は値が-1000で軸の最大値と等しいため、棒が表示されていない。

この時点でもちょっと嫌ですが、さらに一部の値をnullにしてみると、

const data = [
  {
    name: "Data A",
    value_1: null,
    value_2: -1500
  },
  {
    name: "Data B",
    value_1: -2000,
    value_2: -2300
  },
  {
    name: "Data C",
    value_1: -3000,
    value_2: -2800
  }
];

グラフはこうなります。
Y軸(縦軸)は-3150から-1350までのグラフ。左から右へ、Data A, DataB, Data Cの系列が並んでいる。Data A のvalue_1はなぜかY軸の上端より上に飛び出して棒が表示されている。

軸の外側になんか生えてしまいました。

なぜこうなるのか?

この現象自体への言及は見つけられなかったですが、公式ドキュメントのYAxisの説明によると、Y軸の最小最大をdomainという属性で指定できるようで、これを指定しない場合、デフォルトでは 0 ~ auto の範囲が設定されるようです。
察するに、

  • デフォルトでY軸の範囲は0始まりで正方向に自動で伸びる
  • この範囲外のデータが入ってきた場合、軸の範囲が auto ~ auto に切り替わる(範囲外の値も非表示とはならない)
  • データの中に値がnullであるものが含まれる場合、それは0として読み替えられる。ただし軸の範囲調整が正常に行われず、棒グラフがエリア外に飛び出す(エリア外の0に向かってグラフが伸びる)

という感じになっていると思われます。

どうすればいいか?

Y軸の範囲調整がうまくいっていないようなので、こちらで明示的に指定すれば良さそうです。
その際、0がエリア内に収まるように調整してやります。
例えば上のデータを表示したい場合は、

<YAxis domain={['auto', 0]}/>

のように、YAxisのdomain属性を設定します。
すると、グラフは下図のようになります。
Y軸(縦軸)は-3000から0までのグラフ。左から右へ、Data A, DataB, Data Cの系列が並んでいる。Data A のvalue_1は表示されておらず、すべてのデータが軸の範囲内に表示されている。

軸の外側に飛び出していたものが消えてくれました。

まとめ

というわけで、Rechartsを使用する場合、nullが含まれるデータを渡す場合は軸の範囲設定をしないといけない場合がある、というお話でした。
Recharts、今後も使い倒していきたいなーと思います。