在 graphviz 点有向图中,如何打破宽布局(rankdir LR)

问题描述 投票:0回答:2

使用 python,我试图生成一个长图,其中总是一个节点指向下一个节点。这最终会产生一条很长的节点蛇(rankdir LR)。然而我想在一定的宽度或数量或节点之后打破它。如何才能实现这一目标?

graph = gv.Digraph(format='svg')
graph.graph_attr.update({'rankdir': 'LR'})

graph.node('a', 'A')
graph.node('b', 'B')
graph.node('c', 'C')
graph.node('d', 'D')
graph.node('e', 'E')
graph.node('f', 'F')
...

graph.edges(['ab', 'bc', 'cd', 'de', 'ef', ...])

输出:

但是我想要(或类似):

我尝试使用size,但这只会缩放整个图表。

作为一种解决方法,我尝试减少ranksep,但这只会使更多项目变得更好。

我也搜索了很多,但找不到合适的答案。 一个未回答的类似方向的问题是: graphviz 绘图太宽。 对于其他相关问题建议的答案是使用不可见元素但这在这里也不起作用。


更新: 我根据@vaettchen的评论更改了边缘的代码:

graph.edge('a', 'b', None, {'weight':'5'})
graph.edge('b', 'c', None, {'weight':'5'})
graph.edge('d', 'e', None, {'weight':'5'})
graph.edge('e', 'f', None, {'weight':'5'})

graph.edge('c', 'd', None, {'weight':'1'})
graph.edge('a', 'd', None, {'style':'dashed', 'rank':'same'})

不幸的是,结果现在看起来像这样(样式为“dashed”而不是“invis”以获得更好的可见性):

'rank':'相同'似乎没有改变任何东西。也适用于节点 A 和 D。

graphviz dot
2个回答
2
投票

这应该是一个评论而不是一个答案,因为它没有解决 python 问题,我猜你也在寻找更“自动”的东西 - 但也许它给出了一些想法;由于没有其他人接受它,这里是一个纯粹的 graphviz 建议:

digraph so 
{
    // graph attributes
    rankdir = LR;       // horizontal graph
    splines = ortho     // edges with "corners"

    // default/initial node style
    node[ shape = box ];

    // nodes where the "new lines" begin
    // connected invisibly to keep them in order
    { rank = same; A ->  E ->  I[ style = invis ] }

    // nodes that are to be in one line
    // extra weight needed to keep the edges straight
    edge[ weight = 5 ];
    A -> B -> C -> D;
    E -> F -> G -> H;
    I -> J -> K -> etc;

    // edges connecting the graph elements over the lines
    edge[ weight = 1 ];
    D -> E;
    H -> I;
}

产量


0
投票

有几种方法可以制作这条“蛇”。
首先,要创建直角边缘弯曲,请应用于所有边缘属性

splines=ortho

变体 1
使用边缘属性,例如

constraint=false
weight=0
C -> D
边缘创建“软”边缘,使用
rank=same
A
D
节点创建“强”对齐。节点。
点脚本:

digraph {
    graph[rankdir=LR;splines=ortho]
    node[shape=box]
    A -> B -> C
    D -> E -> F
    C -> D [constraint=false]
    {rank=same;A;D}
}

变体2
使用

group
属性可在
A
B
C
节点之间以及
D
E
之间创建“强”对齐。
F
节点;和
rank=same
用于
A
D
节点,以在这些节点之间创建“强”对齐。
点脚本:

digraph {
    graph[rankdir=LR;splines=ortho]
    node[shape=box]
    A [group=g1]
    B [group=g1]
    C [group=g1]
    D [group=g2]
    E [group=g2]
    F [group=g2]
    A -> B -> C -> D -> E -> F
    {rank=same;A;D}
}

两种变体给出相同的结果,我想你也可以使用

neato
引擎来设置节点的精确坐标,但它看起来过于复杂。

最小代码示例(针对变体 1)以及注释:

import graphviz as gv

nodes = ['A','B','C','D','E','F']

# Count of nodes in row,
# can be changed for the desired graph width
columns = 3

graph = gv.Digraph(format='svg', filename = "output/mygraph.gv",
                   graph_attr=dict(rankdir='LR', splines='ortho'),
                   node_attr=dict(shape='box'))

# Set constraint=false only for desired edges, for example
# only for every 3rd edges, where `3` is set by `columns` variable
for i in range(1, len(nodes)):
    if i % columns == 0 :
        graph.edge(nodes[i-1], nodes[i], constraint='false')
    else:
        graph.edge(nodes[i-1], nodes[i])

# Add desired nodes to `rank=same` subgraph
with graph.subgraph() as s:
    s.attr(rank='same')
    for i in range(0, len(nodes)):
        if i % columns == 0 :
            s.node(nodes[i])

graph.view()

结果图:

结果

mygraph.gv
:

digraph {
    graph [rankdir=LR splines=ortho]
    node [shape=box]
    A -> B
    B -> C
    C -> D [constraint=false]
    D -> E
    E -> F
    {
        rank=same
        A
        D
    }
}

可能的改进
如果线上有一个节点,则创建一个不一致的最后一个箭头:

这可以通过在节点

inv2
F
之间创建不可见节点
G
来纠正:

digraph {
    graph [rankdir=LR splines=ortho nodesep=.2]
    node [shape=box]
    A -> B
    B -> C
    C -> inv1 [constraint=false arrowhead=none]
    inv1 -> D [constraint=false ]
    D -> E
    E -> F
    F -> inv2 [constraint=false arrowhead=none]
    inv2 -> G [constraint=false]
    {
        rank=same
        A
        inv1 [shape=point width=.01]
        D
        inv2 [shape=point width=.01]
        G
    }
}

结果:

© www.soinside.com 2019 - 2024. All rights reserved.