Gruff::Lineの使い方まとめ

はじめに

Rubyでグラフを描くためのライブラリGruff::Lineを使う機会がありましたので,まとめをしておきます.

インストール

環境はMac OS Xを想定しています.
ハマりどころはImageMagickのインストール.
X関連の(正直どうでもよさそうな)ライブラリまで入るので,結構時間が掛かります.

% sudo port install tiff -macosx
% sudo port install imagemagick +q8 +gs +wmf
% sudo gem install rmagick
% sudo gem install gruff

Q&A 基礎編

Q.そもそもGruffで扱えるグラフはどんなのがあるの?
A.線グラフ,棒グラフ,円グラフ等10種類です.gullery photo galleryにイメージがあるので見てもらったほうが早いです.


Q.new時のオプションでできることは?
A.生成する画像のサイズ設定です.

require 'rubygems'
require 'gruff'
g = Gruff::Line.new('640x480')

 他の設定はnew時ではなく,インスタンス生成後に設定します.以下,"g"はGruff::Lineのインスタンスを指します.


Q.データの設定はどうやるの?
A.dataメソッドで設定します.
 my_dataを表示したいデータが入っているArray,labelをデータ名称が入ったStringとします.

my_data = [0, 1, 2, 3, 4, 5]
label = 'ラベル名' # => 凡例として表示されます
g.data(label, my_data)


Q.ファイル出力の方法は?
A.writeメソッドで出力されます.

g.write('graph.png')


Q.お前は信用できないので,Rdocを見たい
A.Gruff Documentationからどうぞどうぞ.CUI派はri.

ri Gruff::Line

Q&A 見た目調整編

Q.画像サイズの指定方法は?
A.new時に設定します.

g = Gruff::Line.new('640x480')

 とすればVGAサイズで出力されます.


Q.背景の設定はどうやってやりますか?
A.テーマが用意されているので,ありがたく使わせていただきましょう.
 全部で6種類あります.デフォルトではkeynoteになるようです.

g.theme_37signals
g.theme_greyscale
g.theme_keynote
g.theme_odeo
g.theme_pastel
g.theme_rails_keynote


Q.当然タイトルもつけたいんだけど
A.そのまんまですがtitleに設定します.

g.title = 'Graph title'


Q.X軸/Y軸にも見出しが無いと先生に怒られるよね
A.こちらもそのまんまですが,[x|y]_axis_labelに設定します.

g.x_axis_label = 'X axis label'
g.y_axis_label = 'Y axis label'


Q.つーか,日本語じゃないと困るのですが
A.何もしないと文字化けします.フォント指定して下さい.

g.font = '/Library/Fonts/好きなフォント.ttf'


Q.文字の大きさ調整したいっす
A.頑張って指定して下さい.

g.title_font_size  = 15 # => タイトルのフォントサイズ
g.marker_font_size = 12 # => X/Y軸のフォントサイズ


Q.凡例も表示したいんだけど
A.デフォルトで表示されます.サイズ指定はこのようにします.

g.legend_box_size  = 10 # => 凡例サイズ
g.legend_font_size = 12 # => 凡例のフォントサイズ

ちなみに表示したくない場合は,

g.hide_legend

としてください.


Q.軸のスケールを変えたいです
A.こちらも頑張って指定して下さい.

g.minimum_value = 0    # => 最小値
g.maximum_value = 50   # => 最大値
g.y_axis_increment = 5 # => Y軸の刻み幅

が,しかし...!!
現状では,y_axis_incrementを設定すると,

/opt/local/lib/ruby/gems/1.8/gems/gruff-0.3.4/lib/gruff/base.rb:666:in `normalize':
 wrong number of arguments (1 for 0) (ArgumentError)

と言われてコケてしまいます.;_;

ひとまず,該当する666行目のtrueを取り去ると動きますので,書き換えましょう.(こんなことしていいのか)

% diff -c base.rb.org base.rb
*** 663,669 ****
          @maximum_value = [@maximum_value.ceil, @y_axis_increment].max
          @minimum_value = @minimum_value.floor
          calculate_spread
!         normalize(true)
  
          @marker_count = (@spread / @y_axis_increment).to_i
          @increment = @y_axis_increment
--- 663,669 ----
          @maximum_value = [@maximum_value.ceil, @y_axis_increment].max
          @minimum_value = @minimum_value.floor
          calculate_spread
!         normalize()
  
          @marker_count = (@spread / @y_axis_increment).to_i
          @increment = @y_axis_increment


Q.なぜかグラフが右に偏って表示されるよ.これじゃカッコ悪くね?
A.マージン設定をされてみてはいかがでしょうか.
 数値は適当に変えてみて下さい.

g.right_margin = 40

Q&A 小手先テクニック編

Q.データの種類が多すぎて,線の色が足りねーよ
A.colorsに色が設定されているので,追加して下さい.
 めんどくさい場合は↓のように色を沢山生成してつっこみましょう.

# Web safe 216 colors
def colors
  colors = []
  0.step(0xFF0000, 0x330000).each do |high|
    0.step(0xFF00, 0x3300).each do |mid|
      0.step(0xFF, 0x33).each do |low|
        colors << sprintf("#%06x", (high + mid + low))
      end
    end
  end
  colors.sort_by { rand }
end

g.colors = colors


Q.私の場合,X軸の値は数値じゃなくて日付なのですが
A.labelsに設定して下さい.こんな感じです.

require 'date'
days = Date.parse('2009/01/01')..Date.parse('2009/02/01')
days.each_with_index do |date, i|
  g.labels[i] = date.strftime('%m/%d')
end


Q.そもそも線グラフじゃなくて点グラフを描きたいのですが
A.Gruff::Lineでは素直に設定する方法はないようです.データを
 [ nil, nil, nil ... nil, Y値 ]
  | nilの個数がX値 |
 となるようにします.
 コード見てもらった方が早い.

g.data(label, Array.new(x) + [y])

Q&A それは多分仕様です編

Q.タイトルとか軸とか凡例にそれぞれ個別のフォントを設定したいんだけど
A.残念ながら,現在の仕様(0.3.4)ではできないようです.


Q.任意の場所に文字列を表示させたいんだけど
A.残念ながら,現在の仕様(0.3.4)ではできないようです.


Q.X軸/Y軸の終端に単位を表示させたいのですが
A.残念ながら,現在の仕様(0.3.4)ではできないようです.


Q.軸を対数にできませんか
A.残念ながら,現在の仕様(0.3.4)ではできないようです.


以上,お役に立てば幸いです.