
By: Nguyen Hung Vu – CC BY 2.0
目次
C3.js
C3.jsはD3.jsをベースにしたグラフ描画のライブラリ.
データを与えるだけできれいなグラフが描ける上に、カスタマイズも可能.
c3js.org/
使い方は簡単.
適当にライブラリを配置して読み込む.
1 2 | <%= stylesheet_link_tag 'c3.min', plugin: 'redmine_timetable' %> <%= javascript_include_tag 'lib/d3.min', plugin: 'redmine_timetable' %> |
そして、viewにdiv#chartを設置して、c3.generate()すればOK.
1 2 3 4 5 6 7 8 9 | var chart = c3.generate({ bindto: '#chart', data: { columns: [ ['data1', 30, 200, 100, 400, 150, 250], ['data2', 50, 20, 10, 40, 15, 25] ] } }); |
かっこいい感じのグラフが描画される.
インタラクティブにマウスオーバーやツールチップ、クリックで表示非表示、画面サイズに合わせたリサイズなど高機能.
時系列の場合は、こんなデータ.ちょっと今風でない行列の先頭にタイトルデータがはいるという、扱いにくい感じ. <= なんかJSONとかでも大丈夫でした.rowsとかjsonとか結構データによって柔軟に対応できるぽい.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var chart = c3.generate({ data: { x: 'x', // xFormat: '%Y%m%d', // 'xFormat' can be used as custom format of 'x' columns: [ ['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'], // ['x', '20130101', '20130102', '20130103', '20130104', '20130105', '20130106'], ['data1', 30, 200, 100, 400, 150, 250], ['data2', 130, 340, 200, 500, 250, 350] ] }, axis: { x: { type: 'timeseries', tick: { format: '%Y-%m-%d' } } } }); |
gon
今回はgonというgemを使った.
github.com/gazay/gon
gonはコントローラーから、直接、Javascriptにデータを渡してくれる.
その仕組みは、描画されたソースをみると大体わかるけど、htmlにデータを直書きしている.
Jsonの場合はhtmlのあと、また取得することが多く、gonならデータの通信が一回で済むから、ちょっとグラフを描画する程度には最適.
準備として、Rails4の場合はViewに次の通り書き込んでおく.
1 | <%= Gon::Base.render_data({}) %> |
次に、Railsから、上のcolumnsに対応するデータを渡せばOK.
例えば、@tteventsはgroupとかcountとかして集計したデータセット.
1つのデータは、{year: 2014, month: 1, day:5, sum: 5, count:3}とかで、これが集まってActiveRecord_Relationに入ってる.
これをcontrollerでgonに適当に加工していれた.
1 2 3 4 5 6 7 8 9 | dates = ['x'] counts = ['個数'] sums = ['時間'] @ttevents.each do |data| dates << "#{data.year}#{data.month}#{data.day}" counts << data.count sums << data.sum end gon.ttevents = [dates, counts, sums] |
JavaScriptでデータを渡してやればOK
第2軸は、y2という名前固定ぽい.
1 2 3 4 5 6 7 8 9 10 11 | data: { x: 'x', columns: gon.ttevents, type: 'bar', axes: { 個数: 'y2' } }, axis :{ y2: { show: true } }, |
D3.jsより全然お手軽!
バーチャートやドーナッツチャートはよく使うからうれしい
横軸も時系列を使えば、0の日のデータがなくても、ちゃんと間を空けて描画してくれる.データベースから0の日を含んだデータを取ってくるのは結構めんどうくさいからありがたい.
追記 timeseriesになってなかった
axesの指定が必要でした.
参考: Timeseries Chart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | var chart = c3.generate({ bindto: '#chart', data: { x: 'x', xFormat: '%Y%m%d', columns: gon.ttevents, type: 'bar', axes: { 個数: 'y2' } }, axis: { x : { type: 'timeseries' }, y2: { show: true } }, bar: { width: { ratio: 0.3 } }, }); |
複数の時系列データで一方にはある時点のデータがあるけど他方にはある時点のデータがないみたいな場合はMultiple XY Line Chart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var chart = c3.generate({ bindto: '#graph2', data: { xs: { '新規チケット' : 'x1', '終了チケット' : 'x2' }, columns: gon.issues_count }, axis: { x : { type: 'timeseries', tick: { format: '%Y/%m' } }, } }); |
ドーナッツチャートの場合
ドーナッツチャートの場合は、[項目名,データ,…],[項目名,データ,…]というデータセットが必要.
ActiveRecordの集計結果に、これはto_aを使えば簡単に作れる.
例えば、Projectが多数のIssueを持ち、Issueが多数のEventを持つという関係の場合、project名ごとのEventのduration(時間)を集計するにはJoinして,groupすればOK.
1 | gon.project_ratio = Ttevent.joins(issue: :project).group('projects.name').sum(:duration).to_a |
これをJavascriptに渡す.
1 2 3 4 5 6 7 8 9 10 | var chart = c3.generate({ bindto: '#graph', data: { columns: gon.project_ratio, type : 'donut' }, donut: { title: "作業時間の割合" } }); |
これでOK