56
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ateam Lifestyle x cymaAdvent Calendar 2018

Day 12

Reactのチャート描画ライブラリRechartsで様々なチャートを出力する

Last updated at Posted at 2018-12-11

Ateam Lifestyle x cyma Advent Calendar 2018の12日目は、株式会社エイチームライフスタイルのエンジニア@kazenomachiが担当します。

本稿では、Reactのチャート描画ライブラリRechartsで様々なチャートを出力する方法を紹介していきます。

やりたいこと

  • Reactで、簡単なグラフ(折れ線グラフや棒グラフ)を描画したい
  • できるだけ簡単に分かりやすいコードで書きたい

Rechartsとは?

Reactで簡単にSVGチャートを描画できるライブラリです。

他にもチャートを描画することができるライブラリは多くありますが、今回は以下の点を理由にRechartsを選びました。

  • Reactコンポーネントを使ってReactらしくコードを書ける(読みやすい)
  • ある程度カスタマイズも可能で、レスポンシブ対応も簡単そう

基本編

まずは早速、基本のグラフを書いてみます。
公式ドキュメントに従って実装すれば簡単にグラフを作ることができます。

折れ線グラフ

See the Pen 折れ線グラフ by Nao Kubota (@kazenomachi) on CodePen.

今回グラフで表示したデータは以下の通りです。
X軸に日付、Y軸に気温を表示しています。

const data = [
  { date: moment('2018-12-01').unix() * 1000, 最高気温: 10, 最低気温: 1 },
  { date: moment('2018-12-02').unix() * 1000, 最高気温: 12, 最低気温: 4 },
  { date: moment('2018-12-03').unix() * 1000, 最高気温: 18, 最低気温: 8 },
  { date: moment('2018-12-04').unix() * 1000, 最高気温: 10, 最低気温: 0 },
  { date: moment('2018-12-05').unix() * 1000, 最高気温: 9, 最低気温: 1 },
  { date: moment('2018-12-06').unix() * 1000, 最高気温: 13, 最低気温: 2 },
  { date: moment('2018-12-07').unix() * 1000, 最高気温: 16, 最低気温: 5 },
]

グラフは以下の通りです。
折れ線グラフでは LineChart を使います。
ResponsiveContainer で囲めば、レスポンシブになります。便利!

<ResponsiveContainer width="95%">
  <LineChart
      data={this.props.data} // 表示するデータ  
      margin={{top: 5, right: 50, left: 50, bottom: 25}}>
    <XAxis // X軸
      dataKey="date" // X軸の基準となるデータ項目名
      tickFormatter={(props) => moment(props).format('YYYY/MM/DD')} // X軸を YYYY/MM/DD 形式で表示します
    />
    <YAxis // Y軸
      domain={['dataMin', 'dataMax']}
      ticks={[-10,-5,0,5,10,15,20,25,30]} // Y軸に表示する温度
      unit="℃" // Y軸の単位
    />
    <CartesianGrid // ガイド線の表示
      stroke="#ccc"
      strokeDasharray="3 3"
    />
    <Tooltip // ツールチップの表示
      labelFormatter={(props) => moment(props).format('YYYY/MM/DD(ddd)')} // ラベルの表示フォーマット(日付)
    />
    <Line // 最高気温のデータを表示
      name="最高気温"
      dataKey="最高気温" // this.props.data のキー
      stroke="salmon" // 線の色
      unit="℃" //単位
    />
    <Line // 最低気温のデータを表示
      name="最低気温"
      dataKey="最低気温" // this.props.data のキー
      stroke="skyblue" // 線の色
      unit="℃" //単位
    />
  </LineChart>
</ResponsiveContainer>

棒グラフ

渡すデータは同じですが、LineChartBarChart にすれば棒グラフになります。

See the Pen 棒グラフ by Nao Kubota (@kazenomachi) on CodePen.

棒グラフ(データを配列で渡す)

BarChartではデータを配列で渡すこともできます。表示が以下のように変わります。

See the Pen 棒グラフ2 by Nao Kubota (@kazenomachi) on CodePen.

応用編

Reactstateを使って操作できるグラフを作ってみます。
凡例をクリックし、表示項目を指定できるようにします。

See the Pen stateでグラフの表示を切り替える by Nao Kubota (@kazenomachi) on CodePen.

stateは以下の通り初期化します。

constructor(props) {
  super()
  this.state = {
    data: props.data, // グラフデータ
    chartColors: { // グラフ表示色
      総売上: '#ffd700',
      商品A: '#3cb371',
      商品B: '#87ceeb',
      来客数: '#9370db'
    },
    leftYAxisUnit: '', // Y軸左側に表示する単位
    rightYAxisUnit: '', // Y軸右側に表示する単位
    leftYAxis: ['総売上', '商品A', '商品B'], // Y軸左側に合わせる項目
    rightYAxis: ['来客数'], // Y軸右側に合わせる項目
    disabled: ['来客数'] // 非表示項目
  }
}

項目名がクリックされた時に行う処理を実装します。
setStatestatedisabled項目を変更します。

toggleChart = toggleKey => {
  if (_.includes(this.state.disabled, toggleKey)) {
    // 表示されている項目を非表示にします
    this.setState({
      // disabledから指定されたキーを削除
      disabled: this.state.disabled.filter(value => value !== toggleKey)
    })
  } else {
    // 非表示の項目を表示します
    this.setState({
      // disabledに指定されたキーを追加
      disabled: this.state.disabled.concat(toggleKey)
    })
  }
}

グラフの上に表示する凡例をカスタマイズします。
onClicktoggleChartを呼び出すようにします。

customizedLegend = () => {
  return(
    <div className="customized-legend">
      {
        _.toPairs(this.state.chartColors).map(pair => {  // 項目名と表示色のペア
          const disable = _.includes(this.state.disabled, pair[0])
          const style = {
            marginRight: 10,
            color: disable ? "#ccc" : "#000", // 非表示項目のフォントの色を変えます
            cursor: 'pointer'
          }
          return (
            <span
              className="legend-item"
              onClick={() => this.toggleChart(pair[0])} // onClickでtoggleChartを実行します
              style={style}
            >
              { // 凡例の ● を表示 }
              <Surface width={20} height={20} viewBox="0 0 20 20">
                <Symbols cx={13} cy={13} type="circle" size={100} fill={pair[1]} />
                  {
                    // 非表示項目の場合 ● を ○ にするため、円の中に白丸を描きます
                    disable && (
                      <Symbols
                        cx={13}
                        cy={13}
                        type="circle"
                        size={50}
                        fill="#fff"
                      />
                    )
                  }
                </Surface>
              { // 項目名を表示 }
              <span>{pair[0]}</span>
            </span>
          )
        })
      }
    </div>
  )
}

グラフ部分は以下の通りとなります。
LegendcontentcustomizedLegendを表示するようにしています。

stateが変わると、this.stateを使用している部分が再描画されるので、グラフを動かしながら読んでみるとおもしろいと思います。

今回はdisabled項目しか変更していませんが、例えばchartColorsを変えるとグラフの色が変わったりします。

<ResponsiveContainer width="95%">
  <ComposedChart
      data={this.state.data}
      margin={{top: 0, right: 50, left: 50, bottom: 25}}>
    <XAxis
      dataKey="date"
      tickFormatter={(props) => moment(props).format('YYYY/MM/DD')}
    />
    <YAxis
      orientation="left"
      yAxisId="leftYAxis"
      domain={['dataMin', 'dataMax']}
      ticks={[600000,700000,800000,900000,1000000,1100000,1200000,1300000]}
      unit="円"
    />
    <YAxis
      orientation="right"
      yAxisId="rightYAxis"
      domain={['dataMin', 'dataMax']}
      ticks={[700,800,900,1000,1100,1200,1300,1400]}
      unit="人"
    />
    <CartesianGrid 
      stroke="#ccc"
      strokeDasharray="3 3"
    />
    <Tooltip
      labelFormatter={(props) => moment(props).format('YYYY/MM/DD(ddd)')}
    />
    <Legend
      verticalAlign="top"
      height={50}
      align="left"
      content={this.customizedLegend()}
    />
    {
      _.toPairs(this.state.chartColors)
        .filter(pair => !_.includes(this.state.disabled, pair[0]))
        .map(pair => (
        <Bar
          key={pair[0]}
          name={pair[0]}
          dataKey={pair[0]}
          stackId={_.includes(['商品A', '商品B'], pair[0]) ? 'sales' : ''}
          yAxisId={_.includes(this.state.leftYAxis, pair[0]) ? 'leftYAxis' : 'rightYAxis'}
          unit={_.includes(this.state.leftYAxis, pair[0]) ? this.state.leftYAxisUnit : this.state.rightYAxisUnit}
          fill={pair[1]}
        />
      ))
    }
  </ComposedChart>
</ResponsiveContainer>

まとめ

データを用意してコンポーネントに渡し、いくつかオプションを指定するだけで簡単にグラフを表示することができました。
stateを使って再描画するような処理も、Reactらしく簡単に書けて良かったです。

今回紹介したグラフ以外にも、公式サイトのExamplesAPIドキュメントにあるように、様々なグラフを簡単に実装できます。
ドキュメントに無いような特殊なグラフを実装するのには向いていませんが、手早く簡単に一般的なグラフを実装したい時には役に立つと思います!


Ateam Lifestyle x cyma Advent Calendar 2018、明日は @kiitan さんに書いてもらう予定です。ぜひお楽しみに!

エイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
https://www.a-tm.co.jp/recruit/

56
36
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
56
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?