2010-11-22 57 views
10


我想绘制graphviz中使用圆形布局的128个节点(标记为1到128)的图形。 Circo是这样做的,但我希望节点按照其标签号码的顺序排列,而不是由circo创建的顺序(基于它们之间的边缘)。此外,可能有节点没有传入或传出边缘,但仍然必须按循环顺序放置。graphviz:圆形布局,同时保留节点顺序

我已经尝试摆弄边缘重量,但它并没有影响任何东西。我可以使用相邻节点之间的不可见边缘(例如1-> 2,2-> 3,...,128-> 1)使无边节点出现在圆环中。但订单仍然有欠缺。

有什么办法可以达到这个目的吗?我非常感谢在这方面的帮助。这里是我的代码:

digraph{ 
size="8,6" 
layout=circo 
node [shape=square,fontsize=300,penwidth=2] 
1->2 [style=invis] 
2->3 [style=invis] 
3->4 [style=invis] 
4->5 [style=invis] 
5->6 [style=invis] 
6->7 [style=invis] 
7->8 [style=invis] 
8->9 [style=invis] 
9->10 [style=invis] 
10->11 [style=invis] 
11->12 [style=invis] 
12->13 [style=invis] 
13->14 [style=invis] 
14->15 [style=invis] 
15->16 [style=invis] 
16->17 [style=invis] 
17->18 [style=invis] 
18->19 [style=invis] 
19->20 [style=invis] 
20->21 [style=invis] 
21->22 [style=invis] 
22->23 [style=invis] 
23->24 [style=invis] 
24->25 [style=invis] 
25->26 [style=invis] 
26->27 [style=invis] 
27->28 [style=invis] 
28->29 [style=invis] 
29->30 [style=invis] 
30->31 [style=invis] 
31->32 [style=invis] 
32->33 [style=invis] 
33->34 [style=invis] 
34->35 [style=invis] 
35->36 [style=invis] 
36->37 [style=invis] 
37->38 [style=invis] 
38->39 [style=invis] 
39->40 [style=invis] 
40->41 [style=invis] 
41->42 [style=invis] 
42->43 [style=invis] 
43->44 [style=invis] 
44->45 [style=invis] 
45->46 [style=invis] 
46->47 [style=invis] 
47->48 [style=invis] 
48->49 [style=invis] 
49->50 [style=invis] 
50->51 [style=invis] 
51->52 [style=invis] 
52->53 [style=invis] 
53->54 [style=invis] 
54->55 [style=invis] 
55->56 [style=invis] 
56->57 [style=invis] 
57->58 [style=invis] 
58->59 [style=invis] 
59->60 [style=invis] 
60->61 [style=invis] 
61->62 [style=invis] 
62->63 [style=invis] 
63->64 [style=invis] 
64->65 [style=invis] 
65->66 [style=invis] 
66->67 [style=invis] 
67->68 [style=invis] 
68->69 [style=invis] 
69->70 [style=invis] 
70->71 [style=invis] 
71->72 [style=invis] 
72->73 [style=invis] 
73->74 [style=invis] 
74->75 [style=invis] 
75->76 [style=invis] 
76->77 [style=invis] 
77->78 [style=invis] 
78->79 [style=invis] 
79->80 [style=invis] 
80->81 [style=invis] 
81->82 [style=invis] 
82->83 [style=invis] 
83->84 [style=invis] 
84->85 [style=invis] 
85->86 [style=invis] 
86->87 [style=invis] 
87->88 [style=invis] 
88->89 [style=invis] 
89->90 [style=invis] 
90->91 [style=invis] 
91->92 [style=invis] 
92->93 [style=invis] 
93->94 [style=invis] 
94->95 [style=invis] 
95->96 [style=invis] 
96->97 [style=invis] 
97->98 [style=invis] 
98->99 [style=invis] 
99->100 [style=invis] 
100->101 [style=invis] 
101->102 [style=invis] 
102->103 [style=invis] 
103->104 [style=invis] 
104->105 [style=invis] 
105->106 [style=invis] 
106->107 [style=invis] 
107->108 [style=invis] 
108->109 [style=invis] 
109->110 [style=invis] 
110->111 [style=invis] 
111->112 [style=invis] 
112->113 [style=invis] 
113->114 [style=invis] 
114->115 [style=invis] 
115->116 [style=invis] 
116->117 [style=invis] 
117->118 [style=invis] 
118->119 [style=invis] 
119->120 [style=invis] 
120->121 [style=invis] 
121->122 [style=invis] 
122->123 [style=invis] 
123->124 [style=invis] 
124->125 [style=invis] 
125->126 [style=invis] 
126->127 [style=invis] 
127->128 [style=invis] 
128->1 [style=invis] 
25->42 [penwidth=5] 
25->71 [penwidth=7] 
26->25 [penwidth=5] 
26->40 [penwidth=6] 
27->30 [penwidth=6] 
29->25 [penwidth=9] 
29->26 [penwidth=9] 
29->27 [penwidth=6] 
29->30 [penwidth=4] 
29->32 [penwidth=4] 
29->40 [penwidth=5] 
29->80 [penwidth=5] 
32->39 [penwidth=5] 
33->28 [penwidth=5] 
33->44 [penwidth=4] 
33->74 [penwidth=6] 
37->34 [penwidth=6] 
37->66 [penwidth=5] 
37->69 [penwidth=4] 
38->60 [penwidth=4] 
38->107 [penwidth=5] 
40->100 [penwidth=5] 
47->30 [penwidth=4] 
48->35 [penwidth=6] 
48->36 [penwidth=4] 
50->35 [penwidth=5] 
50->63 [penwidth=5] 
51->50 [penwidth=5] 
51->96 [penwidth=4] 
52->50 [penwidth=8] 
53->51 [penwidth=7] 
53->96 [penwidth=4] 
59->50 [penwidth=5] 
59->51 [penwidth=6] 
59->52 [penwidth=5] 
59->60 [penwidth=5] 
60->50 [penwidth=10] 
60->63 [penwidth=4] 
60->95 [penwidth=4] 
67->74 [penwidth=4] 
67->114 [penwidth=4] 
68->74 [penwidth=5] 
70->74 [penwidth=6] 
70->126 [penwidth=4] 
71->74 [penwidth=8] 
71->86 [penwidth=4] 
72->70 [penwidth=4] 
75->39 [penwidth=4] 
77->81 [penwidth=5] 
79->73 [penwidth=6] 
80->84 [penwidth=4] 
82->78 [penwidth=5] 
82->114 [penwidth=4] 
86->115 [penwidth=5] 
87->115 [penwidth=5] 
87->121 [penwidth=5] 
91->69 [penwidth=5] 
91->87 [penwidth=5] 
96->30 [penwidth=5] 
96->114 [penwidth=5] 
101->107 [penwidth=5] 
102->108 [penwidth=5] 
107->75 [penwidth=5] 
107->78 [penwidth=6] 
108->95 [penwidth=5] 
108->103 [penwidth=4] 
111->80 [penwidth=5] 
111->114 [penwidth=5] 
114->128 [penwidth=4] 
115->114 [penwidth=4] 
118->128 [penwidth=5] 
119->103 [penwidth=5] 
121->72 [penwidth=4] 
123->116 [penwidth=5] 
125->80 [penwidth=4] 
126->122 [penwidth=7] 
128->96 [penwidth=5] 
} 
+0

AFAIK所有的graphviz算法都是从随机放置形状开始的(由http://www.graphviz.org/doc/info/attrs.html#d:start重复),所以我不认为这可以做到 – smirkingman 2010-11-22 08:41:43

回答

8

我认为,唯一的解决方案是使用neato的布局和pos属性。

做你想要什么,我开始通过创建一个小的Ruby脚本来计算所有节点的位置:

radius = 20 

(1..128).each do |i| 
    x = Math.cos(((Math::PI*2)/128.0)*i.to_f)*radius 
    y = Math.sin(((Math::PI*2)/128.0)*i.to_f)*radius 
    puts " #{i}[label=\"#{i}\", pos=\"#{x},#{y}!\", shape = \"square\"];" 
end 

然后,我把结果在graphviz的脚本:

digraph G { 
    layout="neato" 
    1[label="1", pos="19.9759091241034,0.98135348654836!", shape = "square"]; 
    2[label="2", pos="19.9036945334439,1.96034280659121!", shape = "square"]; 
    3[label="3", pos="19.7835301992956,2.93460948910723!", shape = "square"]; 
    4[label="4", pos="19.6157056080646,3.90180644032256!", shape = "square"]; 
    5[label="5", pos="19.4006250638909,4.85960359806528!", shape = "square"]; 
    6[label="6", pos="19.1388067146442,5.80569354508925!", shape = "square"]; 
    7[label="7", pos="18.8308813036604,6.7377970678444!", shape = "square"]; 
    8[label="8", pos="18.4775906502257,7.6536686473018!", shape = "square"]; 
    9[label="9", pos="18.0797858624689,8.55110186860564!", shape = "square"]; 
    10[label="10", pos="17.6384252869671,9.42793473651995!", shape = "square"]; 
    11[label="11", pos="17.1545722000054,10.2820548838644!", shape = "square"]; 
    12[label="12", pos="16.6293922460509,11.111404660392!", shape = "square"]; 
    13[label="13", pos="16.0641506296129,11.9139860898487!", shape = "square"]; 
    14[label="14", pos="15.4602090672547,12.6878656832729!", shape = "square"]; 
    15[label="15", pos="14.8190225070992,13.4311790969404!", shape = "square"]; 
    16[label="16", pos="14.142135623731,14.1421356237309!", shape = "square"]; 
    17[label="17", pos="13.4311790969404,14.8190225070992!", shape = "square"]; 
    18[label="18", pos="12.6878656832729,15.4602090672547!", shape = "square"]; 
    19[label="19", pos="11.9139860898487,16.0641506296129!", shape = "square"]; 
    20[label="20", pos="11.111404660392,16.6293922460509!", shape = "square"]; 
    21[label="21", pos="10.2820548838644,17.1545722000054!", shape = "square"]; 
    22[label="22", pos="9.42793473651996,17.6384252869671!", shape = "square"]; 
    23[label="23", pos="8.55110186860564,18.0797858624689!", shape = "square"]; 
    24[label="24", pos="7.6536686473018,18.4775906502257!", shape = "square"]; 
    25[label="25", pos="6.7377970678444,18.8308813036604!", shape = "square"]; 
    26[label="26", pos="5.80569354508925,19.1388067146442!", shape = "square"]; 
    27[label="27", pos="4.85960359806528,19.4006250638909!", shape = "square"]; 
    28[label="28", pos="3.90180644032257,19.6157056080646!", shape = "square"]; 
    29[label="29", pos="2.93460948910723,19.7835301992956!", shape = "square"]; 
    30[label="30", pos="1.96034280659122,19.9036945334439!", shape = "square"]; 
    31[label="31", pos="0.981353486548363,19.9759091241034!", shape = "square"]; 
    32[label="32", pos="1.22464679914735e-15,20.0!", shape = "square"]; 
    33[label="33", pos="-0.98135348654836,19.9759091241034!", shape = "square"]; 
    34[label="34", pos="-1.96034280659121,19.9036945334439!", shape = "square"]; 
    35[label="35", pos="-2.93460948910723,19.7835301992956!", shape = "square"]; 
    36[label="36", pos="-3.90180644032256,19.6157056080646!", shape = "square"]; 
    37[label="37", pos="-4.85960359806528,19.4006250638909!", shape = "square"]; 
    38[label="38", pos="-5.80569354508924,19.1388067146442!", shape = "square"]; 
    39[label="39", pos="-6.7377970678444,18.8308813036604!", shape = "square"]; 
    40[label="40", pos="-7.65366864730179,18.4775906502257!", shape = "square"]; 
    41[label="41", pos="-8.55110186860564,18.0797858624689!", shape = "square"]; 
    42[label="42", pos="-9.42793473651995,17.6384252869671!", shape = "square"]; 
    43[label="43", pos="-10.2820548838644,17.1545722000054!", shape = "square"]; 
    44[label="44", pos="-11.111404660392,16.6293922460509!", shape = "square"]; 
    45[label="45", pos="-11.9139860898487,16.0641506296129!", shape = "square"]; 
    46[label="46", pos="-12.6878656832729,15.4602090672547!", shape = "square"]; 
    47[label="47", pos="-13.4311790969404,14.8190225070992!", shape = "square"]; 
    48[label="48", pos="-14.1421356237309,14.142135623731!", shape = "square"]; 
    49[label="49", pos="-14.8190225070992,13.4311790969404!", shape = "square"]; 
    50[label="50", pos="-15.4602090672547,12.6878656832729!", shape = "square"]; 
    51[label="51", pos="-16.0641506296129,11.9139860898487!", shape = "square"]; 
    52[label="52", pos="-16.6293922460509,11.111404660392!", shape = "square"]; 
    53[label="53", pos="-17.1545722000054,10.2820548838644!", shape = "square"]; 
    54[label="54", pos="-17.6384252869671,9.42793473651996!", shape = "square"]; 
    55[label="55", pos="-18.0797858624689,8.55110186860564!", shape = "square"]; 
    56[label="56", pos="-18.4775906502257,7.6536686473018!", shape = "square"]; 
    57[label="57", pos="-18.8308813036604,6.73779706784441!", shape = "square"]; 
    58[label="58", pos="-19.1388067146442,5.80569354508925!", shape = "square"]; 
    59[label="59", pos="-19.4006250638909,4.85960359806528!", shape = "square"]; 
    60[label="60", pos="-19.6157056080646,3.90180644032257!", shape = "square"]; 
    61[label="61", pos="-19.7835301992956,2.93460948910724!", shape = "square"]; 
    62[label="62", pos="-19.9036945334439,1.96034280659122!", shape = "square"]; 
    63[label="63", pos="-19.9759091241034,0.98135348654836!", shape = "square"]; 
    64[label="64", pos="-20.0,2.44929359829471e-15!", shape = "square"]; 
    65[label="65", pos="-19.9759091241034,-0.981353486548354!", shape = "square"]; 
    66[label="66", pos="-19.9036945334439,-1.96034280659121!", shape = "square"]; 
    67[label="67", pos="-19.7835301992956,-2.93460948910723!", shape = "square"]; 
    68[label="68", pos="-19.6157056080646,-3.90180644032257!", shape = "square"]; 
    69[label="69", pos="-19.4006250638909,-4.85960359806528!", shape = "square"]; 
    70[label="70", pos="-19.1388067146442,-5.80569354508924!", shape = "square"]; 
    71[label="71", pos="-18.8308813036604,-6.7377970678444!", shape = "square"]; 
    72[label="72", pos="-18.4775906502257,-7.65366864730179!", shape = "square"]; 
    73[label="73", pos="-18.0797858624689,-8.55110186860564!", shape = "square"]; 
    74[label="74", pos="-17.6384252869671,-9.42793473651995!", shape = "square"]; 
    75[label="75", pos="-17.1545722000054,-10.2820548838644!", shape = "square"]; 
    76[label="76", pos="-16.6293922460509,-11.111404660392!", shape = "square"]; 
    77[label="77", pos="-16.0641506296129,-11.9139860898487!", shape = "square"]; 
    78[label="78", pos="-15.4602090672547,-12.6878656832729!", shape = "square"]; 
    79[label="79", pos="-14.8190225070992,-13.4311790969404!", shape = "square"]; 
    80[label="80", pos="-14.142135623731,-14.1421356237309!", shape = "square"]; 
    81[label="81", pos="-13.4311790969404,-14.8190225070992!", shape = "square"]; 
    82[label="82", pos="-12.6878656832729,-15.4602090672547!", shape = "square"]; 
    83[label="83", pos="-11.9139860898487,-16.0641506296129!", shape = "square"]; 
    84[label="84", pos="-11.111404660392,-16.6293922460509!", shape = "square"]; 
    85[label="85", pos="-10.2820548838644,-17.1545722000054!", shape = "square"]; 
    86[label="86", pos="-9.42793473651996,-17.6384252869671!", shape = "square"]; 
    87[label="87", pos="-8.55110186860565,-18.0797858624689!", shape = "square"]; 
    88[label="88", pos="-7.65366864730181,-18.4775906502257!", shape = "square"]; 
    89[label="89", pos="-6.7377970678444,-18.8308813036604!", shape = "square"]; 
    90[label="90", pos="-5.80569354508925,-19.1388067146442!", shape = "square"]; 
    91[label="91", pos="-4.85960359806528,-19.4006250638909!", shape = "square"]; 
    92[label="92", pos="-3.90180644032257,-19.6157056080646!", shape = "square"]; 
    93[label="93", pos="-2.93460948910725,-19.7835301992956!", shape = "square"]; 
    94[label="94", pos="-1.96034280659121,-19.9036945334439!", shape = "square"]; 
    95[label="95", pos="-0.981353486548361,-19.9759091241034!", shape = "square"]; 
    96[label="96", pos="-3.67394039744206e-15,-20.0!", shape = "square"]; 
    97[label="97", pos="0.981353486548353,-19.9759091241034!", shape = "square"]; 
    98[label="98", pos="1.9603428065912,-19.9036945334439!", shape = "square"]; 
    99[label="99", pos="2.93460948910724,-19.7835301992956!", shape = "square"]; 
    100[label="100", pos="3.90180644032257,-19.6157056080646!", shape = "square"]; 
    101[label="101", pos="4.85960359806528,-19.4006250638909!", shape = "square"]; 
    102[label="102", pos="5.80569354508924,-19.1388067146442!", shape = "square"]; 
    103[label="103", pos="6.73779706784439,-18.8308813036604!", shape = "square"]; 
    104[label="104", pos="7.6536686473018,-18.4775906502257!", shape = "square"]; 
    105[label="105", pos="8.55110186860564,-18.0797858624689!", shape = "square"]; 
    106[label="106", pos="9.42793473651995,-17.6384252869671!", shape = "square"]; 
    107[label="107", pos="10.2820548838644,-17.1545722000054!", shape = "square"]; 
    108[label="108", pos="11.111404660392,-16.6293922460509!", shape = "square"]; 
    109[label="109", pos="11.9139860898487,-16.0641506296129!", shape = "square"]; 
    110[label="110", pos="12.6878656832729,-15.4602090672547!", shape = "square"]; 
    111[label="111", pos="13.4311790969404,-14.8190225070992!", shape = "square"]; 
    112[label="112", pos="14.1421356237309,-14.142135623731!", shape = "square"]; 
    113[label="113", pos="14.8190225070992,-13.4311790969404!", shape = "square"]; 
    114[label="114", pos="15.4602090672547,-12.6878656832729!", shape = "square"]; 
    115[label="115", pos="16.0641506296129,-11.9139860898487!", shape = "square"]; 
    116[label="116", pos="16.6293922460509,-11.111404660392!", shape = "square"]; 
    117[label="117", pos="17.1545722000054,-10.2820548838644!", shape = "square"]; 
    118[label="118", pos="17.6384252869671,-9.42793473651996!", shape = "square"]; 
    119[label="119", pos="18.0797858624689,-8.55110186860565!", shape = "square"]; 
    120[label="120", pos="18.4775906502257,-7.65366864730181!", shape = "square"]; 
    121[label="121", pos="18.8308813036604,-6.7377970678444!", shape = "square"]; 
    122[label="122", pos="19.1388067146442,-5.80569354508925!", shape = "square"]; 
    123[label="123", pos="19.4006250638909,-4.85960359806528!", shape = "square"]; 
    124[label="124", pos="19.6157056080646,-3.90180644032257!", shape = "square"]; 
    125[label="125", pos="19.7835301992956,-2.93460948910725!", shape = "square"]; 
    126[label="126", pos="19.9036945334439,-1.96034280659121!", shape = "square"]; 
    127[label="127", pos="19.9759091241034,-0.981353486548362!", shape = "square"]; 
    128[label="128", pos="20.0,-4.89858719658941e-15!", shape = "square"]; 

    25->42 
    25->71 
    26->25 
    26->40 
    27->30 
    29->25 
    29->26 
    29->27 
    29->30 
    29->32 
    29->40 
    29->80 
    32->39 
    33->28 
    33->44 
    33->74 
    37->34 
    37->66 
    37->69 
    38->60 
    38->107 
    40->100 
    47->30 
    48->35 
    48->36 
    50->35 
    50->63 
    51->50 
    51->96 
    52->50 
    53->51 
    53->96 
    59->50 
    59->51 
    59->52 
    59->60 
    60->50 
    60->63 
    60->95 
    67->74 
    67->114 
    68->74 
    70->74 
    70->126 
    71->74 
    71->86 
    72->70 
    75->39 
    77->81 
    79->73 
    80->84 
    82->78 
    82->114 
    86->115 
    87->115 
    87->121 
    91->69 
    91->87 
    96->30 
    96->114 
    101->107 
    102->108 
    107->75 
    107->78 
    108->95 
    108->103 
    111->80 
    111->114 
    114->128 
    115->114 
    118->128 
    119->103 
    121->72 
    123->116 
    125->80 
    126->122 
    128->96 
} 

这里是结果:http://dl.dropbox.com/u/72629/stackoverflow-4242949.png

+1

像魅力!我在我的MATLAB文件中添加了一个类似的代码,用于生成graphviz .dot文件,现在我可以看到我想要的东西:)非常感谢! – Puneet 2010-11-29 06:39:07

+0

我不得不将'layout =“neato”'更改为'layout = circo',否则它完美的工作! – 2016-08-04 00:16:15

+1

很好的答案,但Dropbox链接似乎已经死亡。顺便说一下,对于未来的读者,我修改了这个以使节点数目少得多的圆形布局。默认情况下,节点都很小,但可以通过减小半径参数来解决这个问题。 – RMurphy 2017-03-07 18:22:08

1

生成自己的节点位置是一个更好的算法或增加权重给circo之外的最佳解决方案改变graphviz源代码。

但是,它确实破坏了使用graphviz生成任意图的目的。该脚本将使用graphviz本身用户定义的格式生成任意大小的圆,对位置进行硬编码,然后在中心添加边。

#!/bin/bash 
# loopgen.sh- generates a plain graphviz loop then hardcodes it and adds to it 
# input file format - 
# num of nodes 
# prefixes for the generated file (format information, labels) 
# (blank) 
# postfixes for the final file (extra connections, inputscale) 
# output - graph with nodes0 to nodex 
file=$(<$1) 
# trim filename to function name 
fun=${1##*/} 
fun=${fun%%.*} 
# gen is generation function 
gen="digraph $fun 
{ 
    layout=circo;" 
# fin is final function 
fin="" 
# get the number of inputs 
num=$(head -n 1 <<< "$file") 
if [ $num -lt 2 ]; then 
    echo "Bad number of inputs." 
    exit -1 
fi 
# increment the lines of the file 
file=$(tail -n +2 <<< "$file") 
# add all lines up to the first blank line 
gen="$gen 
    $(printf "$file" | awk '!p;/^$/{p=1}')" 
# remove all lines before the first blank line 
file=$(printf "$file" | awk '/^$/{p=1}p') 
# begin producing character-based nodes 
i=1 
gen="$gen 
    node0 " 
while [ $i -lt $num ]; do 
    gen="$gen -> node$i" 
    let i=i+1 
done 
#finish the loop 
gen="$gen -> node0; 
}" 
# generate, replace circo layout reference, make positions absolute 
gen=$(printf "$gen" | dot | 
sed -e 's/layout=circo/layout=neato/' -e 's/\(pos=".*\)"/\1!"/g') 
# remove trailing brace 
gen=$(printf "$gen" | head -n -1) 

fin="/* generated with loopgen.sh */ 
    $gen 
    $file 
}" 

printf "$fin" 
exit 0 

这里是一个示例文件。

6 
node0 [label="bop it"]; 
node1 [label="twist it"]; 
node2 [label="pull it"]; 
node3 [label="flick it"]; 
node4 [label="spin it"]; 
node5 [label="throw it away"]; 

node2 -> node5 [constraint=false,weight=0]; 
// this keeps the program from running out of memory 
inputscale=72 

运行

loopgen.sh input | neato -Tpng > output.png 

结果

output.png

而正常情况下,相同的布局会导致

malformed.png

+0

对不起,为了解决这个问题,但它是谷歌对这个问题的热门搜索之一。对脚本的进一步编辑将在https://github.com/rbong/loopgen – rbong 2015-06-05 19:51:27