Graphviz Dot,不同形状的自指向箭头
Graphviz Dot, different shaped self-pointing arrows
我正在尝试制作一个带有一些到某些节点的环回的最终状态机。
digraph g{
rankdir=TB;
forcelabels=true;
ranksep=1.5;
pad=0.5;
nodesep=2;
node[shape=circle];
A[label="Wait for call\n0 from above"];
B[label="Wait for\nACK 0 || ACK 1"];
E[label="Wait for call\n1 from above"];
F[label="Wait for\nACk 2 || ACK 3"];
C[label="Wait for ACK 0"];
D[label="Wait for ACK 1"];
G[label="Wait for ACK 2"];
H[label="Wait for ACk 3"];
A -> B[label=" rdt_send(data) \n sndpkt=make_pkt(0,data,checksum) \n udt_send(sndpkt) \n start_timer 1 and 2 \n"];
B -> D[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 1"];
B -> C[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 2"];
C -> E[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 2"];
D -> E[label= " rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 1"];
C:nw -> C:nw[constraint=none,xlabel="PLACEHOLDER"];
C:sw -> C:sw[constraint=none,xlabel="PLACEHOLDER"];
D:ne -> D:ne[constraint=none,xlabel="PLACEHOLDER"];
D:se -> D:se[constraint=none,xlabel="PLACEHOLDER"];
E -> F[constraint=none, xlabel=" \n rdt_send(data) \n sndpkt=make_pkt(1,data,checksum) \n udt_send(sndpkt)\n start_timer "];
F -> G[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
F -> H[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
H -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G:sw -> G:sw[constraint=none,xlabel="PLACEHOLDER"];
G:nw -> G:nw[constraint=none,xlabel="PLACEHOLDER"];
H:se -> H:se[constraint=none,xlabel="PLACEHOLDER"];
H:ne -> H:ne[constraint=none,xlabel="PLACEHOLDER"];
A:w -> A:w[label=" rdt_rcv(rcvpkt) \n ᐱ"];
B:n -> B:n[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,1) \n ᐱ "];
B:e -> B:e[label=" timeout \n udt_send(sndpkt) \n start_timer \n "];
E:e -> E:e[label=" rdt_rcv(rcvpkt)\nᐱ "];
F:s -> F:s[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,0) \n ᐱ "];
F:w -> F:w[label=" timeout \n udt_send(sndpkt) \n start_timer "];
{rank=same;A;B}
{rank=same;C,D,G,H}
{rank=same;E;F}
}
然后我使用命令
dot -Tsvg in.dot -o out.svg
这会生成以下图表
注意四个中间节点上的不同环回边缘及其标签位置。边缘似乎也被拉伸了,即使我增加了 nodesep 属性。我该如何有效地解决这个问题?
令人惊讶的是,增加 nodesep 也会增加循环大小。
下面减少nodesep,添加一个不可见节点(和2条边),并为(部分)边标签添加一些空格。
digraph g{
rankdir=TB;
forcelabels=true;
ranksep=1.5;
pad=0.5;
nodesep=1; // was 2
node[shape=circle];
A[label="Wait for call\n0 from above"];
B[label="Wait for\nACK 0 || ACK 1"];
E[label="Wait for call\n1 from above"];
F[label="Wait for\nACk 2 || ACK 3"];
C[label="Wait for ACK 0"];
D[label="Wait for ACK 1"];
G[label="Wait for ACK 2"];
H[label="Wait for ACk 3"];
A -> B[label=" rdt_send(data) \n sndpkt=make_pkt(0,data,checksum) \n udt_send(sndpkt) \n start_timer 1 and 2 \n"];
B -> D[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 1"];
B -> C[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 2"];
C -> E[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 2"];
D -> E[label= " rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 1"];
C:nw -> C:nw[constraint=none,xlabel="1PLACEHOLDER"];
C:sw -> C:sw[constraint=none,xlabel="2PLACEHOLDER "]; // spaces
D:ne -> D:ne[constraint=none,xlabel=" 3PLACEHOLDER"]; // spaces
D:se -> D:se[constraint=none,xlabel="4PLACEHOLDER"];
E -> F[constraint=none, xlabel=" \n rdt_send(data) \n sndpkt=make_pkt(1,data,checksum) \n udt_send(sndpkt)\n start_timer "];
F -> G[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
F -> H[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
H -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G:sw -> G:sw[constraint=none,xlabel="5PLACEHOLDER"];
G:nw -> G:nw[constraint=none,xlabel="6PLACEHOLDER"];
H:se -> H:se[constraint=none,xlabel=" 7PLACEHOLDER"]; // spaces
H:ne -> H:ne[constraint=none,xlabel="8PLACEHOLDER"];
A:w -> A:w[label=" rdt_rcv(rcvpkt) \n ᐱ"];
B:n -> B:n[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,1) \n ᐱ "];
B:e -> B:e[label=" timeout \n udt_send(sndpkt) \n start_timer \n "];
E:e -> E:e[label=" rdt_rcv(rcvpkt)\nᐱ "];
F:s -> F:s[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,0) \n ᐱ "];
F:w -> F:w[label=" timeout \n udt_send(sndpkt) \n start_timer "];
{rank=same;A;B}
{rank=same;C,D,G,H BOGUS[style=invis]}
{rank=same;E;F}
edge [style=invis]
H -> BOGUS -> C
}
给这个:
我正在尝试制作一个带有一些到某些节点的环回的最终状态机。
digraph g{
rankdir=TB;
forcelabels=true;
ranksep=1.5;
pad=0.5;
nodesep=2;
node[shape=circle];
A[label="Wait for call\n0 from above"];
B[label="Wait for\nACK 0 || ACK 1"];
E[label="Wait for call\n1 from above"];
F[label="Wait for\nACk 2 || ACK 3"];
C[label="Wait for ACK 0"];
D[label="Wait for ACK 1"];
G[label="Wait for ACK 2"];
H[label="Wait for ACk 3"];
A -> B[label=" rdt_send(data) \n sndpkt=make_pkt(0,data,checksum) \n udt_send(sndpkt) \n start_timer 1 and 2 \n"];
B -> D[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 1"];
B -> C[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 2"];
C -> E[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 2"];
D -> E[label= " rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 1"];
C:nw -> C:nw[constraint=none,xlabel="PLACEHOLDER"];
C:sw -> C:sw[constraint=none,xlabel="PLACEHOLDER"];
D:ne -> D:ne[constraint=none,xlabel="PLACEHOLDER"];
D:se -> D:se[constraint=none,xlabel="PLACEHOLDER"];
E -> F[constraint=none, xlabel=" \n rdt_send(data) \n sndpkt=make_pkt(1,data,checksum) \n udt_send(sndpkt)\n start_timer "];
F -> G[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
F -> H[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
H -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G:sw -> G:sw[constraint=none,xlabel="PLACEHOLDER"];
G:nw -> G:nw[constraint=none,xlabel="PLACEHOLDER"];
H:se -> H:se[constraint=none,xlabel="PLACEHOLDER"];
H:ne -> H:ne[constraint=none,xlabel="PLACEHOLDER"];
A:w -> A:w[label=" rdt_rcv(rcvpkt) \n ᐱ"];
B:n -> B:n[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,1) \n ᐱ "];
B:e -> B:e[label=" timeout \n udt_send(sndpkt) \n start_timer \n "];
E:e -> E:e[label=" rdt_rcv(rcvpkt)\nᐱ "];
F:s -> F:s[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,0) \n ᐱ "];
F:w -> F:w[label=" timeout \n udt_send(sndpkt) \n start_timer "];
{rank=same;A;B}
{rank=same;C,D,G,H}
{rank=same;E;F}
}
然后我使用命令
dot -Tsvg in.dot -o out.svg
这会生成以下图表
注意四个中间节点上的不同环回边缘及其标签位置。边缘似乎也被拉伸了,即使我增加了 nodesep 属性。我该如何有效地解决这个问题?
令人惊讶的是,增加 nodesep 也会增加循环大小。
下面减少nodesep,添加一个不可见节点(和2条边),并为(部分)边标签添加一些空格。
digraph g{
rankdir=TB;
forcelabels=true;
ranksep=1.5;
pad=0.5;
nodesep=1; // was 2
node[shape=circle];
A[label="Wait for call\n0 from above"];
B[label="Wait for\nACK 0 || ACK 1"];
E[label="Wait for call\n1 from above"];
F[label="Wait for\nACk 2 || ACK 3"];
C[label="Wait for ACK 0"];
D[label="Wait for ACK 1"];
G[label="Wait for ACK 2"];
H[label="Wait for ACk 3"];
A -> B[label=" rdt_send(data) \n sndpkt=make_pkt(0,data,checksum) \n udt_send(sndpkt) \n start_timer 1 and 2 \n"];
B -> D[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 1"];
B -> C[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 2"];
C -> E[xlabel=" rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0) \n stop_timer 2"];
D -> E[label= " rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1) \n stop_timer 1"];
C:nw -> C:nw[constraint=none,xlabel="1PLACEHOLDER"];
C:sw -> C:sw[constraint=none,xlabel="2PLACEHOLDER "]; // spaces
D:ne -> D:ne[constraint=none,xlabel=" 3PLACEHOLDER"]; // spaces
D:se -> D:se[constraint=none,xlabel="4PLACEHOLDER"];
E -> F[constraint=none, xlabel=" \n rdt_send(data) \n sndpkt=make_pkt(1,data,checksum) \n udt_send(sndpkt)\n start_timer "];
F -> G[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
F -> H[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,3) \n stop_timer "];
H -> A[xlabel=" rdt_rcv(rcvpkt) \n && notcorrupt(rcvpkt) \n && isAck(rcvpkt,2) \n stop_timer "];
G:sw -> G:sw[constraint=none,xlabel="5PLACEHOLDER"];
G:nw -> G:nw[constraint=none,xlabel="6PLACEHOLDER"];
H:se -> H:se[constraint=none,xlabel=" 7PLACEHOLDER"]; // spaces
H:ne -> H:ne[constraint=none,xlabel="8PLACEHOLDER"];
A:w -> A:w[label=" rdt_rcv(rcvpkt) \n ᐱ"];
B:n -> B:n[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,1) \n ᐱ "];
B:e -> B:e[label=" timeout \n udt_send(sndpkt) \n start_timer \n "];
E:e -> E:e[label=" rdt_rcv(rcvpkt)\nᐱ "];
F:s -> F:s[label=" rdt_rcv(rcvpkt) \n && corrupt(rcvpkt) \n || isAck(rcvpkt,0) \n ᐱ "];
F:w -> F:w[label=" timeout \n udt_send(sndpkt) \n start_timer "];
{rank=same;A;B}
{rank=same;C,D,G,H BOGUS[style=invis]}
{rank=same;E;F}
edge [style=invis]
H -> BOGUS -> C
}
给这个: