我需要用 graphviz/dot 绘制一个图表,其中节点之间有共同的边类型,并且我试图找到一种方法来为每种类型的边定义一个标签,然后在图中多次使用该标签。
例如,想象一下传统的吊扇 FSM 示例,它最初处于关闭状态,每次有人拉动电源线时,它都会根据风扇的速度更改为新状态:
Pull Pull Pull
OFF ------> HIGH ------> MED ------> LOW
^ |
| Pull |
+------------------------------------+
每条边都被命名为“Pull”,我可以使用以下方法在点中定义它:
digraph fan {
OFF -> HIGH [label="Pull"];
HIGH -> MED [label="Pull"];
MED -> LOW [label="Pull"];
LOW -> OFF [label="Pull"];
}
但我不想每次都指定相同的文本标签,因为
- 我的标签可能会变得很长,因此很容易出错,并且
- 除了标签之外,我的边缘还有其他属性,例如颜色,并且
- 我有多种不同类型的边可供选择,因此我想确保图表中不同上下文中使用的边类型“A”始终具有所有相同的属性。
我希望 dot 有一种语法,可以让我为边缘类型定义名称,例如:
digraph fan {
edge_a [label="Pull"];
OFF -> HIGH edge_a;
HIGH -> MED edge_a;
MED -> LOW edge_a;
LOW -> OFF edge_a;
}
但当然,真正做的是创建一个名为“Pull”的节点和未标记的边。
我已经在网上搜索了几个小时没有成功。任何人都知道如何预先定义边缘类型以在多个位置使用?
更新: @vaettchen 建议定义一个边缘类型,然后列出该边缘类型的所有转换,然后定义下一个边缘类型,然后是它的转换。虽然这在技术上可以解决我的问题,但它会引入其他几个问题,因为我今天的图表看起来像:
digraph {
subgraph cluster_1 {
a -> b [label="type x", color=red, style=solid];
b -> a [label="type y", color=green, style=dashed];
b -> c [label="type x", color=red, style=solid];
c -> b [label="type y", color=green, style=dashed];
c -> d [label="type z", color=blue, style=dotted];
}
subgraph cluster_2 {
d -> e [label="type x", color=red, style=solid];
e -> d [label="type y", color=green, style=dashed];
e -> f [label="type x", color=red, style=solid];
f -> e [label="type y", color=green, style=dashed];
f -> c [label="type z", color=blue, style=dotted];
}
}
并通过边缘类型重新排列,我会在代码中失去直接的视觉清晰度,让双向边缘彼此相邻(a-> b 和 b-> a),我必须明确列出每个内的节点子图,我必须将子图内部边缘定义拉到主图中:
digraph {
edge [label="type x", color=red, style=solid];
a -> b;
b -> c;
d -> e;
e -> f;
edge [label="type y", color=green, style=dashed];
b -> a;
c -> b;
e -> d;
f -> e;
edge [label="type z", color=blue, style=dotted];
c -> d;
f -> c;
subgraph cluster_1 {
a; b; c;
}
subgraph cluster_2 {
d; e; f;
}
}
因此,虽然它可以解决我提出的问题并且我很欣赏这个建议,但我不确定它是否值得权衡,因为你最终得到了一个 C 程序,你必须在函数之外定义所有变量,并且按它们的类型而不是逻辑关联来组织它们。
需要明确的是,在上面的示例中,如果存在这样的“edge_type”定义关键字,我真正希望的内容如下所示:
digraph {
edge_type edge_x [label="type x", color=red, style=solid];
edge_type edge_y [label="type y", color=green, style=dashed];
edge_type edge_z [label="type z", color=blue, style=dotted];
subgraph cluster_1 {
a -> b edge_x;
b -> a edge_y;
b -> c edge_x;
c -> b edge_y;
c -> d edge_z;
}
subgraph cluster_2 {
d -> e edge_x;
e -> d edge_y;
e -> f edge_x;
f -> e edge_y;
f -> c edge_z;
}
}