GraphvizのDOT言語の代わりにRubyのDSLを利用できるGvizからdotファイルを生成します。
生成したdotファイルを利用してgravizoで図を表示します。
前提
- Rubyのインストール
- gviz gem のインストール
$ gem install gviz
CUIで描画する利点
- GUIの描画ツールやホワイトボードを使う場合に比べ少ない手間で作図が可能となる
- 特に頻繁に変更する場合に作業量の差が顕著
- バージョン管理で差分を管理しやすくなる
- gravizo等、ツール間をとりもつツールがあると利用ドキュメントにそのまま図の元テキストを埋め込める
Gvizを利用する利点
- DOT言語は制御構造を持っていないため複雑な描画が難しい(手間がかかる)という弱点を補うことができる
- 一定のルールでグラデーションさせるなど、プログラムを利用できる点を活かせる
手順
お題
QiitaのAdvent CalendarということでQiitaの中の@r7kamuraさんが作成した
rubotyのリポジトリのコミット履歴を有向グラフにしてみたいと思います。
ほとんどが@r7kamuraさんのコミットになっているので、
コミットした人物が入れ替わったタイミングで別Edgeで描画してみます。
コミットユーザーを取得
$ git log --pretty="%an" > ruboty_committers
処理の都合上、[a-zA-Z]の名前のみを扱いたかったため Aydın Doğan
氏のコミットだけ除外しました。
Gvizのプログラム
require 'gviz'
class String
def normalize_gviz_id
self.gsub(/[ _¥(¥)]/, "")
end
end
file = File.open("ruboty_committers", "r:utf-8"){|f|f.read}
committers = file.each_line.map(&:chomp).map(&:normalize_gviz_id).reverse.map.with_index(1){|e, i|"#{e}#{i}"}
committers.unshift("start")
committers.push("goal")
Graph do
committers.each_slice(2) do |a, b|
break if b.nil?
edge :"#{a}_#{b}"
end
save :sample
end
出力されたdotファイル
digraph G {
start;
RyoNakamura1;
RyoNakamura174;
RyoNakamuraV175;
TaikiONO176;
TaikiONO177;
RyoNakamura178;
RyoNakamura183;
ShotaFukumorisorah184;
RyoNakamura185;
RyoNakamura203;
parroty204;
RyoNakamura205;
RyoNakamura206;
rochefort207;
RyoNakamura208;
amacou209;
RyoNakamura210;
RyoNakamura220;
amacou221;
amacou223;
RyoNakamura224;
RyoNakamura236;
TakehiroSUGITA237;
RyoNakamura238;
RyoNakamura240;
TaikiOno241;
RyoNakamura242;
goal;
start -> RyoNakamura1;
RyoNakamura174 -> RyoNakamuraV175;
RyoNakamuraV175 -> TaikiONO176;
TaikiONO177 -> RyoNakamura178;
RyoNakamura183 -> ShotaFukumorisorah184;
ShotaFukumorisorah184 -> RyoNakamura185;
RyoNakamura203 -> parroty204;
parroty204 -> RyoNakamura205;
RyoNakamura206 -> rochefort207;
rochefort207 -> RyoNakamura208;
RyoNakamura208 -> amacou209;
amacou209 -> RyoNakamura210;
RyoNakamura220 -> amacou221;
amacou223 -> RyoNakamura224;
RyoNakamura236 -> TakehiroSUGITA237;
TakehiroSUGITA237 -> RyoNakamura238;
RyoNakamura240 -> TaikiOno241;
TaikiOno241 -> RyoNakamura242;
RyoNakamura242 -> goal;
}
esaのプレビューでgravizo埋め込みを試行
- gravizoの呼び出し
![Alt text](http://g.gravizo.com/g?
digraph G {
start;
RyoNakamura1;
RyoNakamura174;
RyoNakamuraV175;
TaikiONO176;
TaikiONO177;
RyoNakamura178;
RyoNakamura183;
ShotaFukumorisorah184;
RyoNakamura185;
RyoNakamura203;
parroty204;
RyoNakamura205;
RyoNakamura206;
rochefort207;
RyoNakamura208;
amacou209;
RyoNakamura210;
RyoNakamura220;
amacou221;
amacou223;
RyoNakamura224;
RyoNakamura236;
TakehiroSUGITA237;
RyoNakamura238;
RyoNakamura240;
TaikiOno241;
RyoNakamura242;
goal;
start -> RyoNakamura1;
RyoNakamura174 -> RyoNakamuraV175;
RyoNakamuraV175 -> TaikiONO176;
TaikiONO177 -> RyoNakamura178;
RyoNakamura183 -> ShotaFukumorisorah184;
ShotaFukumorisorah184 -> RyoNakamura185;
RyoNakamura203 -> parroty204;
parroty204 -> RyoNakamura205;
RyoNakamura206 -> rochefort207;
rochefort207 -> RyoNakamura208;
RyoNakamura208 -> amacou209;
amacou209 -> RyoNakamura210;
RyoNakamura220 -> amacou221;
amacou223 -> RyoNakamura224;
RyoNakamura236 -> TakehiroSUGITA237;
TakehiroSUGITA237 -> RyoNakamura238;
RyoNakamura240 -> TaikiOno241;
TaikiOno241 -> RyoNakamura242;
RyoNakamura242 -> goal;
}
)
- esaのプレビューの様子
- 出力された画像
Qiitaに埋め込んでみる
このQiitaの記事内にgravizoの画像を埋め込んでみます。
中身が気になる方は当ページの末尾に .md
をつけてご確認ください。
![Alt text](http://g.gravizo.com/g?
digraph G {
start;
RyoNakamura1;
RyoNakamura174;
RyoNakamuraV175;
TaikiONO176;
TaikiONO177;
RyoNakamura178;
RyoNakamura183;
ShotaFukumorisorah184;
RyoNakamura185;
RyoNakamura203;
parroty204;
RyoNakamura205;
RyoNakamura206;
rochefort207;
RyoNakamura208;
amacou209;
RyoNakamura210;
RyoNakamura220;
amacou221;
amacou223;
RyoNakamura224;
RyoNakamura236;
TakehiroSUGITA237;
RyoNakamura238;
RyoNakamura240;
TaikiOno241;
RyoNakamura242;
goal;
start -> RyoNakamura1;
RyoNakamura174 -> RyoNakamuraV175;
RyoNakamuraV175 -> TaikiONO176;
TaikiONO177 -> RyoNakamura178;
RyoNakamura183 -> ShotaFukumorisorah184;
ShotaFukumorisorah184 -> RyoNakamura185;
RyoNakamura203 -> parroty204;
parroty204 -> RyoNakamura205;
RyoNakamura206 -> rochefort207;
rochefort207 -> RyoNakamura208;
RyoNakamura208 -> amacou209;
amacou209 -> RyoNakamura210;
RyoNakamura220 -> amacou221;
amacou223 -> RyoNakamura224;
RyoNakamura236 -> TakehiroSUGITA237;
TakehiroSUGITA237 -> RyoNakamura238;
RyoNakamura240 -> TaikiOno241;
TaikiOno241 -> RyoNakamura242;
RyoNakamura242 -> goal;
}
)