如何创建命名边缘"类型"在Graphviz / dot / neato?

时间:2017-10-05 21:31:49

标签: graphviz dot neato

我需要绘制一个带有graphviz / dot的图表,其中节点之间存在共同的边缘类型,并且我试图找到为每种类型的边缘定义标签的方法,然后在图中多次使用该标签。

例如,想象一下传统的吊扇FSM示例,它最初处于关闭状态,每当有人拉绳子时,它会根据风扇的速度变为新状态:

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

每个边缘都被命名为#34; Pull"我可以使用以下方法在点中定义:

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

但我不想每次都指定相同的文字标签,因为

  1. 我的标签可能会很长,因此容易出错,
  2. 除标签外,我的边缘还有其他属性,如颜色,
  3. 我选择了多种不同类型的边缘,所以我想确保边缘类型" A"在图中的不同上下文中使用的总是具有所有相同的属性。
  4. 我希望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 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];
        }
    }
    

    并且重新排列边缘类型I在双向边缘彼此相邻的代码中失去直接的视觉清晰度(a-> b和b-> a)和I' d必须明确列出每个子图中的节点,并且我必须将子图内部边缘定义拉到主图中:

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

2 个答案:

答案 0 :(得分:3)

我认为我使用m4得到了您的解决方案(感谢Simon)。使用和调整您的示例,我创建了一个名为/mtn/sda1/bla/bla的文件:

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

并产生预期的图表:

enter image description here

你可以用m4做更多的事情 - 在graphViz中缺少的东西,比如维护和(甚至有条件地)包括子文件。例如,如果您将两个子图放在两个单独的文件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]; } } gv1.txt中,这将很有效:

gv2.txt

enter image description here

答案 1 :(得分:2)

不是一个真正的答案,而是"思考的食物"因为我不认为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

我也尝试用

实现你的diagramm
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

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