このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

コマンドでお絵描き

例えば、

この図のソースは次。


// -*- coding: utf-8 -*-
// sequent

[
gv:node --shapa=point --style=invis sin1,
gv:node --shape=point --style=invis sin2,
gv:node --shape=point --style=invis sin3,
gv:node --label="> *" --shape=diamond --style=filled --fillcolor=brown sin4,

gv:edge --label=A sin1 seq,
gv:edge --label=B sin2 sin4,
gv:edge --label=C sin3 sin4,
gv:edge --label="B*C" sin4 seq,

gv:node --label="==>" --style=filled --fillcolor=darkseagreen seq,

gv:node --shapa=point --style=invis sout1,
gv:node --label="+ <" --shape=diamond --style=filled --fillcolor=white sout2,
gv:node --shape=point --style=invis sout3,
gv:node --shape=point --style=invis sout4,


gv:edge --label=X seq sout1,
gv:edge --label="Y+Z" seq sout2,
gv:edge --label=Y sout2 sout3,
gv:edge --label=Z sout2 sout4,

] | gv:graph --label=sequent --rankdir=LR --bgcolor=gainsboro

これはスクリプトファイル。実行すると次を出力する(けっこう長いな)。


@digraph {
"graph": {
"rankdir": "LR",
"bgcolor": "gainsboro",
"label": "sequent"
},
"elements": [
@node {
"style": "invis",
"id": "sin1",
"shapa": "point"
},
@node {
"shape": "point",
"style": "invis",
"id": "sin2"
},
@node {
"shape": "point",
"style": "invis",
"id": "sin3"
},
@node {
"shape": "diamond",
"style": "filled",
"id": "sin4",
"fillcolor": "brown",
"label": "> *"
},
@edge {
"nodes": [
"sin1",
"seq"
],
"label": "A"
},
@edge {
"nodes": [
"sin2",
"sin4"
],
"label": "B"
},
@edge {
"nodes": [
"sin3",
"sin4"
],
"label": "C"
},
@edge {
"nodes": [
"sin4",
"seq"
],
"label": "B*C"
},
@node {
"style": "filled",
"label": "==>",
"id": "seq",
"fillcolor": "darkseagreen"
},
@node {
"style": "invis",
"id": "sout1",
"shapa": "point"
},
@node {
"shape": "diamond",
"style": "filled",
"id": "sout2",
"fillcolor": "white",
"label": "+ <"
},
@node {
"shape": "point",
"style": "invis",
"id": "sout3"
},
@node {
"shape": "point",
"style": "invis",
"id": "sout4"
},
@edge {
"nodes": [
"seq",
"sout1"
],
"label": "X"
},
@edge {
"nodes": [
"seq",
"sout2"
],
"label": "Y+Z"
},
@edge {
"nodes": [
"sout2",
"sout3"
],
"label": "Y"
},
@edge {
"nodes": [
"sout2",
"sout4"
],
"label": "Z"
}
],
"id": "graph"
}

GraphvizのDOT形式なら:


strict digraph "graph" {
graph [bgcolor=gainsboro,
label=sequent,
rankdir=LR
];
node [label="\N"];
sin1 [shapa=point,
style=invis];
seq [fillcolor=darkseagreen,
label="==>",
style=filled];
sin1 -> seq [label=A];
sout1 [shapa=point,
style=invis];
seq -> sout1 [label=X];
sout2 [fillcolor=white,
label="+ <",
shape=diamond,
style=filled];
seq -> sout2 [label="Y+Z"];
sin2 [shape=point,
style=invis];
sin4 [fillcolor=brown,
label="> *",
shape=diamond,
style=filled];
sin2 -> sin4 [label=B];
sin4 -> seq [label="B*C"];
sin3 [shape=point,
style=invis];
sin3 -> sin4 [label=C];
sout3 [shape=point,
style=invis];
sout2 -> sout3 [label=Y];
sout4 [shape=point,
style=invis];
sout2 -> sout4 [label=Z];
}

XJSONやDOTのデータとして書いてもいいだろう? って思うかもしんないが、そりゃ違う。最終的にgv:Digraph型のXJSONデータが出来れば途中で何したっていいのが凄く便利。例えば次は、バグ(もう直った)の再現用のスクリプト。なんでもいいから引数(%1)を渡すとバグを再現する。


%1? |
when {
undefined => [],
* => [gv:edge n3 n1, gv:edge n3 n2], // これがバグを引き起こす
} > bug;

[
[
[
gv:node --shape=doublecircle --style=filled --fillcolor=red n1,
gv:node --shape=diamond --style=filled --fillcolor=skyblue n2,
gv:edge --style="dashed, bold" n1 n2,
] | gv:cluster --style=rounded,
gv:node n3,
],
%bug
] | list:concat | gv:graph

ちなみに、gvモジュールでPythonで書かれたコマンドは1個だけ(Graphvizとインターフェースする主要コマンドdraw)。他のユーティリティはCatyScriptで書いている。

あと、本編には貼らないだろう“より現実的な”コマンドの絵。いずれ説明する。


原寸大