Rubyでアニメーション・グラフを作ろう!


ベルマンフォードのアルゴリズムで実行される結果も逐次表示 - Seeking for my unique color.


を見てGraphVizの出力からアニメーションgifを作りたくなった
Rubyにはruby-graphvizというGraphVizのinterface libraryと
RMagickというImageMagickのinterface libraryがあり
これらを使えば目的は達成できるみたいだ


ruby-graphvizのinterfaceは自分にはわかり辛かったので
これをラップする形でGraphAz*1というクラスを書いて
上のアニメーションgifを出力してみた
用途が限定的で実装にも問題がありそうだけれど
GraphVizのDOTデータの出力としても使えるので
無責任無保証で使ってくれる人がいればうれしい

使い方

コードを見るのが早いと思うので
簡単な例を示した
まずはDOTデータを作る例

require "graphaz"

routes = [
  ':main => :parse => :execute',
  ':main => :init',
  ':main => :cleanup',
  ':execute => :make_string',
  ':execute => :printf',
  ':init => :make_string',
  ':main => :printf',
  ':execute => :compare'
  ]

ga = GraphAz.new(:G)
routes.each { |route| ga.add route }
ga.print_graph

GraphAz.newでオブジェクトを生成し
addメソッドで用意したルートを追加する
addメソッドは対応するノードとエッジを同時に生成する
最後にprint_graphメソッドを呼べば
DOTデータが標準出力に出力される


コマンドラインから以下のように実行すれば
DOTファイルが生成される

> ruby small_graph.rb > small_graph.dot


pixelglow | graphviz
などのツールで開けば以下のような
グラフが得られるはずだ




今度はアニメーションgifを作成してみる
コードを示す

require "graphaz"

routes = [
  ':main => :parse => :execute',
  ':main => :init',
  ':main => :cleanup',
  ':execute => :make_string',
  ':execute => :printf',
  ':init => :make_string',
  ':main => :printf',
  ':execute => :compare'
  ]

ga = GraphAz.new(:G)
routes.each { |route| ga.add route }
ga.lap

color = 'tomato'
ga.node('main', :style => 'filled', :fillcolor => color)
ga.lap

ga.edge('main_parse', :color => color)
ga.node('parse', :style => 'filled', :fillcolor => color)
ga.lap

ga.edge('parse_execute', :color => color)
ga.node('execute', :style => 'filled', :fillcolor => color)
ga.lap

ga.edge('execute_make_string', 'execute_compare', 'execute_printf', :color => color)
ga.node('make_string', 'compare', 'printf', :style => 'filled', :fillcolor => color)
ga.lap

ga.write

15行目までは同じで
16行目でprint_graphに代えてlapメソッドを使う
lapメソッドはそこまでのコードに基づいて
グラフをimageファイルとしてcurrent directoryに出力する*2


次にnodeまたはedgeメソッドを使って
グラフの属性を変化させる
node,edgeメソッドは
複数のnode, edgeおよび属性を取ることができる
その後lapメソッドを使ってそこまでの変化を出力する


これを繰り返し
最後にwriteメソッドを呼ぶことによって
lapメソッドで出力したファイルを読み込み
1つのgifファイルout.gifを生成する
他のimageファイルはdefaultでは削除される


out.gifをブラウザなどで開き
アニメーションgifが完成しているか確認する




ノードを後から追加するなどイメージデータのサイズが変わると
うまくいかないなどの問題があります

(追記:2010-02-04) タイトルとrubyclass_graph.rbを修正しました
(追記:2010-02-18) Ruby1.9対応です。それ以前のRubyで使うときはnodeとedgeメソッドの第一引数の*を削除して配列を渡すようにしてください
(追記:2010-10-24) graphvizの0.9.9以降のヴァージョンではうまく動作しません。version0.9.8を使ってください
(追記:2010-10-25) graphviz ver.0.9.18に対応しました。clusterを表現できるようになりました。


melborne's graphaz at master - GitHub

*1:Graph Animatize?

*2:defaultでファイル名はout0.png