Reputation: 144
I am trying to make a finate state machine with a few loopbacks to certain nodes.
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}
}
I then use the command
dot -Tsvg in.dot -o out.svg
This generates following graph
Note the different loopback edges on the four middle nodes and their label placements. The edges also seems stretched, even if I increase the nodesep attribute. How do I solve this efficiently?
Upvotes: 0
Views: 294
Reputation: 6773
Surprisingly, increasing nodesep also increases the loop size.
The following reduces nodesep, adds an invisible node (and 2 edges), and adds some spaces to (some of) the edge labels.
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
}
Upvotes: 1