14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RubyAdvent Calendar 2015

Day 2

RubyのDSLの表現力と生産性で有向グラフの作図効率を上げつつ, Graphvizをインストールせずにgravizo経由で利用する

Posted at

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のプレビューの様子

gtavizo_output.gif

  • 出力された画像

gravizo_output.png

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;
}
)

外部資料

14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?