使い方(つづき)

前回前々回に引き続き、Graphvizの使い方を解説します。
今回は、例題を元に試行錯誤しながら「正解」に近づけていくプロセスを順に追っていきます。

サンプル7

WikipediaのArtificial neural networkのページにあるこちらの画像に近くなるようにDOTを書いてみます。

Wikipedia: Artificial neural network(CC BY-SA 3.0)

まず、基本的な要件をリストします。

  • 有向グラフである
  • 2〜4個のノードが縦に3列並んでいる
  • 隣り合った列の各ノードがすべて左から右への矢印で結ばれている
  • 各列の上部に列のタイトルがある
  • ノードは円形でラベルはなく大きさはすべて同じである
  • ノードとタイトル文字列は列ごとに赤、青、緑の色になっている

以下の順で作成してきます。

  1. 有向グラフを定義し、基本的な配置を行う
  2. ラベル付け、整形を行う
  3. 色をつける
  4. エッジを調整する
  5. その他の調整をする

有向グラフを定義し、ノードを配置する

各階層にラベルがあるのでサブグラフを定義することにします。

// ann01.dot
digraph ann02 {
  graph [ rankdir=LR ];
  subgraph cluster_i {
    i1 i2 i3;
  }
  subgraph cluster_h {
    h1 h2 h3 h4;
  }
  subgraph cluster_o {
    o1 o2;
  }
  {i1;i2;i3} -> {h1;h2;h3;h4}; // このように「多対多」のひも付けが1行でできます。
  {h1;h2;h3;h4} -> {o1;o2};
}
ann01

ラベル付け、整形を行う

ノードのラベルを空にして、形をcircleにします。
また、各サブグラグごとにラベルを追加し、penwidth=0にして枠線を消します。
この例の場合、ノードのラベルがすべて空なので結果的にノードのサイズが同じになりますが、通常はnodeの属性widthとheightでノードのサイズを調整します。

// ann02.dot
digraph ann02 {
  graph [ rankdir=LR ];
  node [ label=“”; shape=circle ]; // 追加
  subgraph cluster_i {
    label=“Input”; // 追加
    penwidth=0; // 追加
    i1 i2 i3;
  }
  subgraph cluster_h {
    label=“Hidden”; // 追加
    penwidth=0; // 追加
    h1 h2 h3 h4;
  }
  subgraph cluster_o {
    label=“Output”; // 追加
    penwidth=0; // 追加
    o1 o2;
  }
  {i1;i2;i3} -> {h1;h2;h3;h4};
  {h1;h2;h3;h4} -> {o1;o2};
}
ann02

色をつける

各サブグラグごとにそれぞれ色をつけます。

// ann03.dot
digraph ann03 {
  graph [ rankdir=LR ];
  node [ label=“”; shape=circle ];
  subgraph cluster_i {
    label=“Input”;
    fontcolor=red; // 追加
    penwidth=0;
    node [ color=red ]; // 追加
    i1 i2 i3;
  }
  subgraph cluster_h {
    label=“Hidden”;
    fontcolor=blue; // 追加
    penwidth=0;
    node [ color=blue ]; // 追加
    h1 h2 h3 h4;
  }
  subgraph cluster_o {
    label=“Output”;
    fontcolor=darkgreen; // 追加
    penwidth=0;
    node [ color=darkgreen ]; // 追加
    o1 o2;
  }
  {i1;i2;i3} -> {h1;h2;h3;h4};
  {h1;h2;h3;h4} -> {o1;o2};
}
ann03

エッジを調整する

エッジがカーブしているので、graphの属性splinesをfalseにしてまっすぐにします。
また、エッジの線の太さと矢印の大きさを変えます。

// ann04.dot
digraph ann04 {
  graph [ rankdir=LR; splines=false ]; // splinesの属性を追加
  node [ label=“”; shape=circle ];
  edge [ arrowsize=0.5; penwidth=0.35 ]; // 追加
  subgraph cluster_i {
    label=“Input”;
    fontcolor=red;
    penwidth=0;
    node [ color=red ];
    i1 i2 i3;
  }
  subgraph cluster_h {
    label=“Hidden”;
    fontcolor=blue;
    penwidth=0;
    node [ color=blue ];
    h1 h2 h3 h4;
  }
  subgraph cluster_o {
    label=“Output”;
    fontcolor=darkgreen;
    penwidth=0;
    node [ color=darkgreen ];
    o1 o2;
  }
  {i1;i2;i3} -> {h1;h2;h3;h4};
  {h1;h2;h3;h4} -> {o1;o2};
}
ann04

その他の調整をする

サブグラフのラベルのフォントサイズ調整とノードのpenwidthの指定、マージンの調整を行います。

// ann05.dot
digraph ann05 {
  graph [ rankdir=LR; splines=false ];
  graph [ dpi=250; pad=0; margin=0; fontsize=9.5 ]; // 追加
  node [ label=“”; shape=circle; penwidth=0.35 ]; // penwidthの属性を追加
  edge [ arrowsize=0.5; penwidth=0.35 ];
  subgraph cluster_i {
    margin=0; // 追加
    label=“Input”;
    fontcolor=red;
    penwidth=0;
    node [ color=red ];
    i1 i2 i3;
  }
  subgraph cluster_h {
    margin=0; // 追加
    label=“Hidden”;
    fontcolor=blue;
    penwidth=0;
    node [ color=blue ];
    h1 h2 h3 h4;
  }
  subgraph cluster_o {
    margin=0; // 追加
    label=“Output”;
    fontcolor=darkgreen;
    penwidth=0;
    node [ color=darkgreen ];
    o1 o2;
  }
  {i1;i2;i3} -> {h1;h2;h3;h4};
  {h1;h2;h3;h4} -> {o1;o2};
}
Wikipedia: Artificial neural network(CC BY-SA 3.0)
ann05

左(または上)がお手本、右(または下)が今回作成したものです。
もう一歩というところですが、まあまあそれっぽくなりました。

まとめ

いかがだったでしょうか。前回覚えたサブクラスを使用しながら、graphnodeedgeのそれぞれいくつかの代表的な属性を扱うことができるようになりました。
実際の作業は、今回のように属性のリファレンスを見ながらコツコツ修正していくということが多いと思います。設定できる属性が非常に多いので覚えるのが大変そうな気もしますが、ひとつひとつは簡単なものが多いので慣れれば(そして、細部にこだわりすぎなければ)やりたいことがすぐできるようになると思います。