Layout Graphviz和点文件——水平和垂直节点对齐;中间节点

Layout Graphviz和点文件——水平和垂直节点对齐;中间节点,layout,graphviz,Layout,Graphviz,我正在尝试显示“圆柱形”有向图(从左到右的格式),以便可以在圆柱体上绘制它们。这些图由连续的节点列组成。最右边的一列节点(用虚线表示)是最左边的一列节点的替代品,因此可以打印图形,将其卷成圆柱体,并且当虚线节点在第一列节点的“下方”精确对齐时,它将显示一个连续(圆柱形)循环图 我已经成功地使用“rank”来获得柱状节点对齐,使用“group”来建议第一列和最后一列之间的水平节点对齐。(这特别有帮助。) (我还没有代表在线发布一张照片,但这里有一张最新尝试的照片。) 问题是,我不希望第一列和最后一

我正在尝试显示“圆柱形”有向图(从左到右的格式),以便可以在圆柱体上绘制它们。这些图由连续的节点列组成。最右边的一列节点(用虚线表示)是最左边的一列节点的替代品,因此可以打印图形,将其卷成圆柱体,并且当虚线节点在第一列节点的“下方”精确对齐时,它将显示一个连续(圆柱形)循环图

我已经成功地使用“rank”来获得柱状节点对齐,使用“group”来建议第一列和最后一列之间的水平节点对齐。(这特别有帮助。)

(我还没有代表在线发布一张照片,但这里有一张最新尝试的照片。)

问题是,我不希望第一列和最后一列的节点都垂直展开(见图);第一列的节点之间的垂直间隔(最后一列的节点同上)不应大于任何其他节点列中的节点之间的垂直间隔。但相应的第一列/最后一列节点必须保持水平对齐。(我假设它试图使节点对1->15和13->16中的水平不可见边不受中间节点的阻碍;但我不需要它们不受阻碍。节点1和13(以及15和16)应该与(比如)节点5和14之间具有大致相同的垂直间隔。)

TL;DR版本

  • 图形以“节点列”的顺序从左到右“流动”(fwiw所有边都指向右侧,并且始终只进行一步,从列j到列j+1)
  • 最右边的列需要是最左边的列的“副本”(反映圆柱形环绕)——它应该看起来像最左边的列的复制和粘贴,在相同的垂直高度
  • 这也必须适用于更复杂的图形(例如,最左边和最右边的列的节点排列得相当好,但我担心异常值),并且必须来自一个自动化过程(无需手动微调)
(您的所有节点[label=”“];语句都是多余的)
如果删除组的属性,它将生成非常接近您所需的内容,但虚线节点并不完全对齐。
以下是对您的图表的不同理解:

digraph {
  node[label=""];
  {
    rank=same
    1 8 12 10 14 9 4 15 [style=dashed]
  }
  {
    rank=same
    13 5 2 16 [style=dashed]
  }

1->8[label="c"]
13->8[label="a"]
8->12[label="b"]
12->10[label="a"]
10->5[label="a"]
10->14[label="b"]
5->2[label="a"]
5->9[label="b"]
14->9[label="a"]
2->4[label="b"]
9->4[label="a"]

// "wraparound" nodes
node[style="dashed"];
4->15[label="a"] 
node[style="dashed"];
4->16[label="c"]

edge[style=invis weight=90];
1 ->13 
15->16
}
给予:
为了回答我自己的问题,可以在.dot/.gv文件上运行dot,并将输出保存为文本(其中包括关于节点和边缘位置的大量详细信息等)。这可以提供对节点放置的大量控制,同时允许一定程度的自动化——将其留给字符串操作例程(我使用的是Octave,它具有足够的功能)

因此,创建一个初步的点文件。它将拥有所有的节点列,包括右侧的“环绕”节点列(并且它将根据需要垂直对齐右侧列)

使用“dot-Tdot”选项编译它,该选项输出一个文本文件,其中列出了节点位置(x,y)坐标(pos=“,”格式)。这个带注释的文件,带有dot的优化位置数据,然后被刮取节点位置。然后调整最后一列节点的位置,使其高度与第一列中的互补节点匹配。然后将所有节点记录在一个新的点文件中,并强制其位置(使用[pos=“,!”]语法)

结果用neato编译(它尊重点文件中的pos=“,!”;AFAICT纯“点”不尊重)。(我认为Neato通常包括在graphviz软件包中。)Neato喜欢绘制直边,因此在以下选项上使用样条线选项会有所帮助: $dot-Kneato-Gsplines=true-Gsep=.3-Tps in_dot_文件-o out_graph.ps

但是,Neato可以在边缘线的顶部放置边缘符号。最繁琐的部分可能是从中间带注释的点文件中删除“pos=”数据。也许有更好的方法可以做到这一点。

不使用rankdir=“LR”,而使用“rank”强制/建议左侧和右侧列节点在相同高度成对排列效果更好。问题是,这会干扰中间节点列的结构--“{rank=same;5,14}”等行是有意的,用于垂直堆叠中间节点(图形是节点列的级数)。这些“圆柱体”图形也可能变得更加复杂,因此强制某些行上的“中间”节点(或通过组和不可见边强制它们在列中按特定的堆叠顺序)对于干净的布局来说可能限制太多。gvpr(也包括在Graphviz包中)将很容易“刮取”pos值。这里是一个用于打印节点名的单行程序&pos:gvpr'N{print($.name,“::”,$.pos)}'xxx.dot
digraph {
  node[label=""];
  {
    rank=same
    1 8 12 10 14 9 4 15 [style=dashed]
  }
  {
    rank=same
    13 5 2 16 [style=dashed]
  }

1->8[label="c"]
13->8[label="a"]
8->12[label="b"]
12->10[label="a"]
10->5[label="a"]
10->14[label="b"]
5->2[label="a"]
5->9[label="b"]
14->9[label="a"]
2->4[label="b"]
9->4[label="a"]

// "wraparound" nodes
node[style="dashed"];
4->15[label="a"] 
node[style="dashed"];
4->16[label="c"]

edge[style=invis weight=90];
1 ->13 
15->16
}
digraph {
rankdir="LR"
1 [label="1"]
4 [label="2"]
10 [label="3"]
12 [label="1", style="dashed"]
13 [label="2", style="dashed"]
14 [label="3", style="dashed"]
node[label=""];
1->2[label="b"]
4->2[label="a"]
4->6[label="b"]
4->9[label="c"]
10->6[label="a"]
2->5[label="c"]
6->11[label="c"]
9->5[label="a"]
9->11[label="b"]
5->7[label="b"]
11->7[label="a"]
7->3[label="a"]
7->8[label="b"]
3->12[label="a"]
3->13[label="b"]
8->13[label="a"]
8->14[label="b"]
{rank=same; 1, 4, 10}
{rank=same; 2, 6, 9}
{rank=same; 5, 11}
{rank=same; 7}
{rank=same; 3, 8}
{rank=same; 12, 13, 14}
}
// add this to file
inputscale=72 // this tells neato to use the proper scaling; lower=nodes farther apart
1[pos="27,170!", label="1"];
4[pos="27,94!", label="2"];
10[pos="27,18!", label="3"];
node[label=""];
2[pos="127,151!"];
6[pos="127,37!"];
9[pos="127,94!"];
5[pos="227,121!"];
11[pos="227,67!"];
7[pos="327,94!"];
3[pos="427,121!"];
8[pos="427,67!"];
12[pos="527,170!", label="1", style="dashed"] // aligned with node ID 1
13[pos="527,94!", label="2", style="dashed"] // aligned with node ID 4
14[pos="527,18!", label="3", style="dashed"] // aligned with node ID 10