グラフ作成スクリプトはレイアウト指定がイマイチ
Table of Contents
tunnel ツールのネタを書いた時、 dot を使ってグラフを作った。
dot は手軽にグラフを書ける便利なツールだが、 レイアウト制御に難があると思う。
この記事は、そんな思いを書いた単なる愚痴だ。 解決策は用意していない。
1 グラフ作成ツールの利点と欠点
dot などのグラフ作成ツールの利点には次が挙げられる。
ノードのリンクを指定するだけで、後はツールが良い感じにグラフを自動で作成してくれる。
パワポ等でグラフを作成するのと比べると、これは大きな利点だ。
そして多くの場合、ツールが作成するグラフは、それなりに見易いグラフになってくれる。
ただ、自動で作成するため、 意図とは異なるレイアウトのグラフが出来あがることもある。
レイアウトのことは割り切って使うとか、 気に入らないなら他のパワポなどの draw 系のツールで描けば良いという話もあるが、 それは何か違うと思っている。
2 dot のグラフ
例えば次の図は、 tunnel と host を繋ぐ処理をグラフ化したものだ。
このグラフの dot コードは次になる。
digraph G {
rankdir = RL;
tunnel [shape=doublecircle];
subgraph clusterA {
packetWriter [shape=rect; margin=0.2;];
packetReader [shape=rect; margin=0.2;];
keepalive [shape=rect; margin=0.2;];
WriteQueue
tunnel2Stream [shape=rect; margin=0.2;];
stream2Tunnel [shape=rect; margin=0.2;];
ReadQueue
{rank = max; packetReader; packetWriter}
{rank = same; WriteQueue; ReadQueue}
{rank = min; tunnel2Stream; stream2Tunnel; keepalive}
}
host [shape=box3d];
tunnel -> packetReader
packetReader -> ReadQueue
ReadQueue -> tunnel2Stream
stream2Tunnel -> WriteQueue 
WriteQueue -> packetWriter
packetWriter -> tunnel
keepalive -> WriteQueue
tunnel2Stream -> host
host -> stream2Tunnel
{rank=min;host}
}
コードの細かい部分はここでは触れないが、
{rank=} を次の 4 つ指定していることを確認して欲しい。
{rank = max; packetReader; packetWriter}{rank = same; WriteQueue; ReadQueue}{rank = min; tunnel2Stream; stream2Tunnel; keepalive}{rank=min;host}
この rank 指定を取ってグラフを生成すると次のようになる。
3 rank 指定の有無の違い
グラフの違い分かり易いように並べて表示する。
- rank 指定あり
 
- rank 指定なし
 
rank 指定ありは矢印の向きが素直に円を描いる一方で、 rank 指定なしは矢印が交差していたり、矢印が長かったりで、 動きが捉え辛くないだろうか?
rank を指定して、目的のレイアウトになったから良いといえば良いんだが、 その rank の指定が試行錯誤の末、なんでこの指定でいけたかの納得がいかない。
4 rank 指定の意味
今回指定した 4 つの rank の内、次の 3 つは中央の四角の中の並び順を指定している。
{rank = max; packetReader; packetWriter}{rank = same; WriteQueue; ReadQueue}{rank = min; tunnel2Stream; stream2Tunnel; keepalive}
そもそも、 rank は何を指定するものなのかというと、 ノードの配置ランクを指定する。
上記の 3 つの指定は、 packetReader, packetWriter が max のランクで、 WriteQueue, ReadQueue が同じランクで、 tunnel2Stream, stream2Tunnel, keepalive が min のランクであることを設定している。
これは、 rank 指定した時の図と見比べて、 中央の四角の中の左側から max, same, min の順で並べられていることから納得できる。
次に 4 つの内の最後の rank 指定は、 host の場所を指定している。
{rank=min;host}
これは、 host が min のランクであることを設定している。
これも rank 指定した時の図と見比べて、 host が一番右に配置されていることから納得できる。
じゃぁ、この章の最初に「納得いかない」と言ったのは何だったのか?と思うだろう。
それは、これと同じ考え方で rank を指定しても、 思った通りにならないことが多いということだ。
例えば、次の指定を追加で行なうと、