Chartkickを利用して「Ruby on Railsの記述のみ」で簡単にドーナツグラフを作る

# はじめに
プログラミングスクールでのポートフォリオ制作で得た学びをアウトプットします。
Rails初学者のため、誤りやアドバイスがありましたらご指摘いただけると嬉しいです！

今回は、Railsで以下のような「ドーナツグラフ」を簡単に作る方法についてまとめます。
使用するのはGemの「Chartkick」とJavaScriptのライブラリ 「Highcharts」です。
![index_donut.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635852/75c5cea7-9fce-1b3e-1581-8a13cd59d9b3.png)

:::note info
記載したコードは、わかりやすいよう一部省略している場合があります。不明点はGitHubでご確認いただくか、お問い合わせいただければ幸いです。
:::

:::note warn
Highchartsは、「商用利用では有料」です。
:::

# 開発環境
- Ruby（2.6.5）
- Ruby on Rails（6.0.0）

# ポートフォリオ
URL: https://good-yen.onrender.com
GitHub: https://github.com/Asami119/good_yen


# 前提となる情報
- Chartkick（Gem）を利用することで、Highcharts（JavaScriptのグラフ描画ライブラリ）を「Rubyの記述だけ」で利用し、グラフを簡単に実装することができる！
- ポイントは、データを以下のようなハッシュ形式でセットし、ビューへ渡すこと
```ruby:コントローラー
@data = { '項目名1': sample1, '項目名2': sample2, '項目名3': sample3 }
# keyに項目名、valueに対応する数値（または数値を代入した変数）を指定
```
```ruby:ビュー
# 「pie_chart（=円グラフ）」はグラフの種類を指定する記述
# 続けて、データを代入したインスタンス変数を記述
<%= pie_chart @data %>
```


# 手順
:::note info
大まかな流れ
・環境設定（①〜③）
・ビュー（④）・コントローラー（⑤）・モデル（⑥）への記述
＊④〜⑥の作業は、順番通りでなくて大丈夫です。
:::

## ① Chartkickをインストール
以下を記述して、ターミナルで bundle install します。
```ruby:Gemfile
gem 'chartkick'
```


## ② Highchartsを追加
ターミナルで以下を実行します。
```ruby:ターミナル
yarn add chartkick highcharts
```

:::note warn
この部分（作業②）はうろ覚えで正確性に自信がない箇所です。他の情報元（以下）を参照したためおそらく合っているとは思うのですが、念のためその旨を記載させていただきます。
- [chartkick × Highchartsでドーナツグラフを作る](https://study-diary.hatenadiary.jp/entry/2020/12/30/192937)
- [Chartkick公式サイト](https://chartkick.com/#rails-6-webpacker)
＊ 公式では「Highcharts」ではなく、別のJavaScriptのグラフ描画ライブラリ「Chart.js」を利用するための記述が記載されています。
:::

## ③ application.jsファイルに以下の記述を追加
```ruby:app/javascript/packs/application.js
import 'chartkick/highcharts'
```

## ④ ビューに以下のような任意の記述を追加

:::note info
公式の記述例と、実際の記述の両方を記載します。
:::

```ruby:ビューファイル
#公式の例
<%= pie_chart Yogurt.group(:flavor).count %>
```

「Yogurt.group(:flavor).count」で、ヨーグルトの「フレーバーごとのレコード数」を算出しています。
```ruby:groupメソッドとcountメソッドを併用した場合の戻り値（予想）
Yogurt.group(:flavor).count
=> {"Blueberry"=>10, "Strawberry"=>5, "Banana"=>5, "Apple"=>5, "Grape"=>2}
```
戻り値はハッシュ形式で返されるため、上記のようなビューファイルの記述1行で、以下のような円グラフの反映が可能となります。
[![Image from Gyazo](https://i.gyazo.com/42a3a677e9046fd299933dc9608f54d5.png)](https://gyazo.com/42a3a677e9046fd299933dc9608f54d5)
＊上記画像は[Chartkick公式サイト](https://chartkick.com/)より引用
＊ groupメソッドとcountメソッドについては、以下のサイトを参考にしました。
[【Rails】 groupメソッドの使い方とは？仕組みを図解で丁寧に解説！](https://pikawaka.com/rails/group)


そして、以下が実際の記述です。公式よりも記述が複雑なのは、データをユーザーで絞り込んだり、表示形式を変更したりする必要があったためです。

:::note info
ポイントは以下の3つです。
・1行目の「pie_chart」の記述でグラフの種類を指定
・続くインスタンス変数「@price_sums」には、反映したいデータが代入されている
・続く「options」以下の記述で、グラフの「色」や「位置」などの表示形式を指定
:::

```ruby:app/views/posts/search.html.erb
# 実際の記述
<%= pie_chart @price_sums, options = {
  donut: true,  # ドーナツグラフにするための記述
  colors: ["#ACFF40", "#FFF33F"],  # 色を指定
  thousands: ",",   # 金額表示にする（カンマを入れる）
  suffix: "円",  # 単位を指定
  label: "金額",  # ホバーした時に表示される詳細の項目名を指定
  library: {
    title: {
      text: "Good yen!<br>#{@price_true_percent}%",  # 中央(ドーナツの穴)部分の記述を指定
      align: 'center',  # 位置を指定（水平方向）
      verticalAlign: 'middle'  # 位置を指定（垂直方向）
    },
    plotOptions: {
      pie: {
        dataLabels: {
          enabled: false  #データラベルを表示するか否か
        },
        innerSize: '50%',  # 中央(ドーナツの穴)部分のサイズを指定
      }
    }
  }
} %>
```
反映イメージは以下です。
グラフの右上部分に重なっている金額の詳細は、グラフをホバーすると表示されます。
![Screenshot_20220416-110908.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635852/deb5ff92-7a13-7cbd-1ea9-b0cd346e2115.png)

他に、グラフやフォントのサイズ指定など、様々な設定が可能なようです。
以下のサイト（再掲）がとても参考になります！
[chartkick × Highchartsでドーナツグラフを作る](https://study-diary.hatenadiary.jp/entry/2020/12/30/192937)

## ⑤ コントローラーに以下のような任意の記述を追加
以下の記述では、Postモデルに自作したcalc_donutメソッドを呼び出し、引数postsを用いた計算結果を2つのインスタンス変数に代入しています。
これによりビューファイル「search.html.erb」にて、インスタンス変数の記述でデータをグラフ化できるようにしています。

```ruby:app/controllers/posts_controller.rb
def search
  posts = @q.result.order(date_of_post: :DESC, created_at: :DESC)
  @price_sums, @price_true_percent = Post.calc_donut(posts) if posts.present?
  # 引数postsには、反映したいデータ（検索で絞り込んだデータ）を代入
  # 引数postsが空だった場合、上記は実行しない（ifで条件分岐）
end
```

## ⑥ モデルに以下のような任意の記述を追加

```ruby:app/models/post.rb
def self.calc_donut(posts)
  price_true = posts.where(select_yen: true).sum(:price) # true(Good yen!)の値を合計 
  price_false = posts.where(select_yen: false).sum(:price) # false(あと一歩)の値を合計
  price_total = (price_true + price_false).to_f
  price_true_percent = (price_true / price_total * 100).floor(1) # trueの割合を計算
  [{ 'Good yen!': price_true, 'あと一歩': price_false }, price_true_percent] # 戻り値2つをセット
end
```
最後に記述した角カッコ内の値が、「@price_sums」「@price_true_percent」にそれぞれ代入されます。
上記では項目が「Good yen!」と「あと一歩」の2つですが、同じ形式で続けて記述することで、必要な項目をさらに増やすことも可能です。

今回は以上です。
読んでくださってありがとうございました！

# 参考URL（感謝です！）
- [chartkick × Highchartsでドーナツグラフを作る](https://study-diary.hatenadiary.jp/entry/2020/12/30/192937)
- [Chartkick公式サイト](https://chartkick.com/)
- [【Rails】 groupメソッドの使い方とは？仕組みを図解で丁寧に解説！](https://pikawaka.com/rails/group)