【问题标题】:Graphviz Dot, different shaped self-pointing arrowsGraphviz Dot,不同形状的自指向箭头
【发布时间】:2021-01-04 05:13:37
【问题描述】:

我正在尝试制作一个最终状态机,其中包含一些到某些节点的环回。

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

这会生成以下图表

注意四个中间节点上的不同环回边缘及其标签位置。即使我增加了 nodeep 属性,边缘也似乎被拉伸了。如何有效地解决这个问题?

【问题讨论】:

    标签: graphviz dot


    【解决方案1】:

    令人惊讶的是,增加 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
    

    }

    给出这个:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多