(追記:2014-3-3) Gvizについてのまとめ頁を作りました。

Gvizの目次 - Rubyの世界からGraphvizの世界にこんにちは!


(追記:2013-08-09) Gvizバージョンアップによりgvizコマンドの仕様が変更になりました(version0.2.0)。詳細は以下の記事を参照してください。

ピクミンがGraphvizにやって来た!


RubyによるGraphvizラッパーGvizのversion0.0.7を公開しました。

gviz | RubyGems.org | your community gem host

Gvizを使えば簡単に有向グラフ米国統計地図地下鉄路線図が書けます。

インストール

Graphvizが必要です。自分のプラットフォームに合ったものを以下から入手して下さい。

Download. | Graphviz - Graph Visualization Software

Gvizのインストールはgem install gvizでOKです。Rubyはたぶん1.9.3が必要となります。

追加機能

ver0.0.7で以下の機能が追加されました。

1. gvizコマンド
2. multiple edge指定
3. Object#to_id

gvizコマンド

gvizコマンドで一層簡単にグラフを作成できるようになりました。

適当なディレクトリにgraph.ruファイルを用意して、そこに次のようなグラフコードを書きます。

#graph.ru
nodes style:'filled', colorscheme:'set39'
route :Lisp => [:Ruby, :Python, :Ocaml, :Perl]
route :Ruby => [:Mantra, :Groovy], :Python => [:Ruby, :JavaScript]
route :JavaScript => [:ActionScript, :ObjectiveJ]
rank :same, :Ruby, :Python, :Ocaml, :Perl
nodeset.each { |n| node n.id, color:[*1..9].sample }

save(:sample, :png)

gvizコマンドを実行します。

gviz

これにより次のようなsample.dotおよびsample.pngが生成されます。

Alt title noshadow

つまりgvizコマンドは、Gviz#graphのブロックで上記コードを書いたときと同じものを出力します。

graph.ru以外のファイル名を使いたいときはコマンドに渡して下さい。

multiple edge指定

Gviz#edgeに渡すidが*(アスタリスク)を含むとき、複数のエッジを更新します。

add(:a => [:b, :c])
edge('a_*', color:'red')

上記により:a_b, :a_cの2つのエッジの色をまとめて赤に変更できます。つまりこれは以下と等価です。

edge(:a_b, color:'red')
edge(:a_c, color:'red')

Object#to_id

ノードやエッジのidを簡単に生成するための補助メソッドです。Object#to_idはそのオブジェクト固有のidを生成しシンボルで返します。次のように使います。

name = "秋元康"
id = name.to_id # => :"2572637362590069661" 
node name.to_id, label:name

以上です。

Gvizのソースはギットハブにあります。

melborne/Gviz

AKB48をビジュアライズする

やっぱり新機能の紹介だけではつまらないので、少し凝ったサンプルを示します。

今時AKBのメンバー名と所属チームくらいは知っておきたいものです。関係グラフを作って覚えましょう。

データの取得

次のような汎用スクレイパーをでっち上げて、AKB48公式サイトからメンバーのデータをぶっこ抜きます。

これで以下のような出力が得られます。

{"チームA"=>[["iwasa_misaki", "岩佐 美咲"], ["ohta_aika", "多田 愛佳"], ["ooya_shizuka", "大家 志津香"], ["katayama_haruka", "片山 陽加"], ["kuramochi_asuka", "倉持 明日香"], ["kojima_haruna", "小嶋 陽菜"], ["shinoda_mariko", "篠田 麻里子"], ["takajo_aki", "高城 亜樹"], ["takahashi_minami", "高橋 みなみ"], ... 中略 ... "研究生"=>[["omori_miyuu", "大森 美優"], ["sasaki_yukari", "佐々木 優佳里"], ["hirata_rina", "平田 梨奈"], ["eguchi_aimi", "江口 愛実"], ["Aigasa_Moe", "相笠 萌"], ["Iwatate_Saho", "岩立 沙穂"], ["Umeta_Ayano", "梅田 綾乃"], ["Okada_Ayaka", "岡田 彩花"], ["Kitazawa_Saki", "北澤 早紀"], ["Shinozaki_Ayana", "篠崎 彩奈"], ["Takashima_Yurina", "髙島 祐利奈"], ["Murayama_Yuiri", "村山 彩希"], ["Mogi_Shinobu", "茂木 忍"], ["Uchiyama_Natsuki", "内山 奈月"], ["Okada_Nana", "岡田 奈々"], ["Kojima_Mako", "小嶋 真子"], ["Nishino_Miki", "西野 未姫"], ["Hashimoto_Hikari", "橋本 耀"], ["Maeda_Mitsuki", "前田 美月"]]}

graph.ruを書く

さてこのデータを使ってグラフを描きます。layoutをfdpとして各メンバーの情報からノードとエッジを作ります。

# encoding: UTF-8
MEMBER = {"チームA"=>[["iwasa_misaki", "岩佐 美咲"], ["ohta_aika", "多田 愛佳"], ["ooya_shizuka", "大家 志津香"], ["katayama_haruka", "片山 陽加"], ["kuramochi_asuka", "倉持 明日香"], ["kojima_haruna", "小嶋 陽菜"], ... 中略 ... ["Shinozaki_Ayana", "篠崎 彩奈"], ["Takashima_Yurina", "髙島 祐利奈"], ["Murayama_Yuiri", "村山 彩希"], ["Mogi_Shinobu", "茂木 忍"], ["Uchiyama_Natsuki", "内山 奈月"], ["Okada_Nana", "岡田 奈々"], ["Kojima_Mako", "小嶋 真子"], ["Nishino_Miki", "西野 未姫"], ["Hashimoto_Hikari", "橋本 耀"], ["Maeda_Mitsuki", "前田 美月"]]}

global layout:'fdp', label:'AKB48', size:16

MEMBER.each do |team, members|
  node team.to_id, label:team
  members.each do |id, name|
    route team.to_id => id.to_id
    node id.to_id, label:name
  end
end

save :akb, :png

routeでチーム名ノードを中心にその所属メンバーのノードがリンクするようにします。

graph.ruのディレクトリでgvizコマンドを実行します。

gviz

これにより次のようなakb.pngが出力されます。

akb noshadow (クリックで拡大します)

色を付ける

色情報を適当に用意して、各ノードに色を付けます。

COLOR = [["チームA", '#F576A3'], ["チームK", '#77B800'], ["チームB", '#34B6E4'], ["チーム4", '#F8D800'], ["研究生", '#9932CC'], ["昇格メンバー", '#FF8C00']]

global layout:'fdp', label:'AKB48', size:16
+nodes style:'filled'
+edges color:'#777777'

MEMBER.each do |team, members|
+  color = COLOR.assoc(team)[1]
+  node team.to_id, label:team, color:color
  members.each do |id, name|
    route team.to_id => id.to_id
+    node id.to_id, label:name, color:color, fillcolor:color+'33'
  end
end

save :akb, :png

再度gvizコマンドを実行します。

akb noshadow (クリックで拡大します)

グラフに色が付きました。

リーダーを区別する

AKBの各チームにはリーダーがいます。リーダーのノードを2重円にして他と識別できるようにします。

LEADERS = ["takahashi_minami", "akimoto_sayaka", "kashiwagi_yuki", "oba_mina"]

LEADERS.each do |leader|
  node leader.to_id, peripheries:2
end

出力です。 akb noshadow (クリックで拡大します)

仕上げ

最後にノードを真円とし、フォントや線の幅を調整して完成とします。

+global layout:'fdp', label:'AKB48', size:16, fontsize:48, fontname:'Helvetica'
+nodes style:'filled', shape:'circle', fontname:'Futura', width:1.3
+edges color:'#777777', arrowhead:'none', penwidth:2

MEMBER.each do |team, members|
  color = COLOR.assoc(team)[1]
  node team.to_id, label:team, color:color
  members.each do |id, name|
+    name.sub!(/\s+/, "\n")
    route team.to_id => id.to_id
+    node id.to_id, label:name, color:color, fillcolor:color+'33', penwidth:3
  end
end

LEADERS = ["takahashi_minami", "akimoto_sayaka", "kashiwagi_yuki", "oba_mina"]

LEADERS.each do |leader|
  node leader.to_id, peripheries:2
end

save :m, :png

出力です。

akb noshadow (クリックで拡大します)

いいですね!

One More Thing..

あっ、大事な要素を一つ忘れていました..

画像付きのノードを一つだけ足します。画像は適当なところから拾ってきて同じディレクトリに置きます。

node :yasusu, label:"", image:'yasusu.jpg', shape:'circle', width:1.5, penwidth:10, color:'pink', fillcolor:'white', imagescale:true, fixedsize:true, peripheries:5

これで完成です!

akb noshadow (クリックで拡大します)

ホントはもちろんメンバーの画像がいいんですけどねぇ。

あなたもGvizでAKB48してみませんか?


AKB48+Me



blog comments powered by Disqus
ruby_pack8

100円〜で好評発売中!
M'ELBORNE BOOKS