2017-10-05 156 views
0

我需要绘制graphviz/dot图,其中节点之间存在常见的边缘类型,并试图找到一种方法来为每种类型的边界定义标签,然后在图中多次使用该标签。如何在Graphviz/dot/neato中创建命名边“类型”?

例如想象传统的吊扇FSM例如它的最初状态OFF和每次有人拉它基于风扇的转速变化到一个新的状态线:

 Pull   Pull  Pull 
OFF ------> HIGH ------> MED ------> LOW 
^         | 
|    Pull    | 
+------------------------------------+ 

每个边缘命名为“拉”,我可以通过定义一个对点:

digraph fan { 
    OFF -> HIGH [label="Pull"]; 
    HIGH -> MED [label="Pull"]; 
    MED -> LOW [label="Pull"]; 
    LOW -> OFF [label="Pull"]; 
} 

,但我不希望保留每次都指定同一个文本标签,因为

  1. 我的标签就会变得很长,所以这是容易出错,并且
  2. 我边有其他属性除了像标签颜色,并
  3. 我有一个选择的多个不同类型的边缘,所以我想拍确保图中不同上下文中使用的边缘类型“A”始终具有所有相同的属性。

我的预期点有一个语法,它可以让我定义我的边缘类型的名称,像:

digraph fan { 
    edge_a [label="Pull"]; 

    OFF -> HIGH edge_a; 
    HIGH -> MED edge_a; 
    MED -> LOW edge_a; 
    LOW -> OFF edge_a; 
} 

但当然什么的确实是创建一个名为“拉”节点未标记的边缘。

我一直在网上搜索几个小时,没有成功。任何人都知道如何定义边缘类型以在多个位置使用?

更新:@vaettchen had suggested定义了一个边类型,然后列出该边类型的所有转换,然后定义下一个边类型,然后定义它的转换。虽然这在技术上解决我的问题,它会介绍一些其他的,因为今天我的图表可以关注一下:

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; 
    } 
} 
+0

亲爱的驱动由downvoter - 护理解释为什么?这个问题有样本输入,输出,试图解决方案和需求声明,所以我不知道我能做些什么来改进它。 –

+1

对于下面的'm4'解决方案,我已经做了一些工作并将它添加到[github](https://github.com/vaettchen/m4gv)。我希望你仍然可以使用它... – vaettchen

+0

再次感谢,我会看看。谈到github,我希望能找到一种方法在README.md中包含.dot规范,并在有人在github上查看时自动呈现图形。因此,如果我在.dot中有一个系统的文本模型,我不必手动更新它的图像。我发现一个网站(https://github.com/TLmaK0/gravizo)我可以链接到一个对我的.dot文件的引用,并且实际上工作,但是我正在使用的github网站是专有的,所以外部网站可以'实际上看到我的内部.dot文件。你有没有遇到类似的东西? –

回答

1

不是一个真正的答案,但“精神食粮”因为我不认为graphviz中存在命名标签:您可以为以下边缘定义默认标签。如果您的工作流程允许在一个地方定义所有边缘,那么效果很好。例如:

digraph rs 
{ 
    node[ shape = box, style = rounded] 

    edge[ label = "pull" ]; 
    { A B } -> C; 
    G -> H; 
    C -> D[ label = "stop" ]; 
    edge[ label = "push"]; 
    D -> { E F }; 
    edge[ color = red, fontcolor = red ]; 
    { E F } -> G; 
} 

这将产生

enter image description here

我也试图与

digraph fan 
{ 
    splines = ortho; 
    node [ shape=box ] 

    edge [ xlabel = "Pull", minlen = 4 ]; 
    { rank = same; OFF -> HIGH -> LOW; } 
    LOW:s -> OFF:s; 
} 

产生

enter image description here

实现你diagramm

所以它看起来不错,但所有的调整很难扩大。

+0

感谢您的建议。我可以在技术上做你建议定义边缘特征的建议,然后列出所有类型的转换,但是现在我在大多数节点之间有双向边缘(例如Off-> On和On-> Off)加上我有子图的边缘类型A出现在多个子图中,所以我会在每个子图中明确列出节点时添加一些更多的工作,将内部边界定义从子图中拉出来,并且我会失去对/从并列的每对节点的边缘。 –

+1

是的,我认为这比粉丝更复杂 - 你知道'gvpr'吗?这对我来说太过分了,但您可能会找到方法将它用于您的服务。 – vaettchen

+0

'gvpr'很有意思,谢谢你的建议。我一直在考虑编写一个awk程序来预处理边界类型定义增加的点状文件,如果点本身不支持,但也许gvpr将是一个更强大的方法。我需要做更多的阅读...... –

1

我想我得到了您的解决方案,使用m4(感谢Simon)。利用和适应你的样品,我创建了一个名为gv.m4文件:

digraph { 
    define(`edge_x',`[label="type x", color=red, style=solid]') 
    define(`edge_y',`[label="type y", color=green, style=dashed]') 
    define(`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; 
    } 
} 

,并用简单的命令

m4 gv.m4 > gv.dot 

现在包含您所定义的边缘

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

,并产生了将其转换预计图表:

enter image description here

你可以用m4做更多 - graphViz中缺少的东西,比如维护和(甚至有条件地)包含子文件。例如,如果你把你的两个子图分为两个单独的文件gv1.txtgv2.txt,这将很好地工作:

digraph incl 
{ 
    define(`edge_x',`[label="type x", color=red, style=solid]') 
    define(`edge_y',`[label="type y", color=green, style=dashed]') 
    define(`edge_z',`[label="type z", color=blue, style=dotted]') 
    include(gv1.txt) 
    include(gv2.txt) 
    e -> d[ color = yellow, label = "this is new!"]; 
} 

enter image description here

+0

有趣,谢谢。在你的'define'行中,你使用反引号和撇号的混合(例如'\'edge_x'' =反引号边撇号) - 是否真的是需要使用的语法还是错字?我没有'm4'可用于测试... –

+0

这实际上是所需的语法。代码是从生成图形的实际测试中复制和粘贴的。 – vaettchen