2

This answer describes how to connect GraphViz clusters to nodes and to other clusters.

I want to connect a cluster to itself, so the arrow exits the cluster boundary and re-enters (think of a state machine that has a transition to itself).

Below is an example:

digraph example {                                                               
    compound=true;                                                              
    "B" -> "C" [ltail="cluster_s0", lhead="cluster_s1", minlen=2];              
    "D" -> "C" [ltail="cluster_s1", lhead="cluster_s1", minlen=2];              
    subgraph cluster_s0 {                                                       
        "A" -> "B";                                                             
    }                                                                           
    subgraph cluster_s1 {                                                       
        "C" -> "D";                                                             
    }                                                                           
}

This throws warnings and draws the arrow inside the cluster instead of outside:

Arrow is drawn inside the cluster

Here's a (very rough) sketch of what I want:

Desired graph

Is there a way to make GraphViz draw an arrow from D to C that exits and re-enters the cluster boundary like in the above example?

definelicht
  • 428
  • 2
  • 14
  • I think the only solution to this would be to have the D->C edge go through an intermediate, invisible node that's outside the cluster - but I've had no luck in getting it to position that node reasonably, so you end up with lines that snake all over the place rather than forming a simple arc. You can get a bit better result by specifying the edge as `"D":n -> "C":n` - the port directions turns the line into an arc that does go outside the cluster, but it still doesn't clip correctly. – jasonharper Oct 09 '17 at 14:49

2 Answers2

1

I don't think that this is possible (and would eagerly wait for a fellow enthusiast to prove the contrary). In the meantime, would you consider a workaround using shape = record? My MWE

digraph example 
{                                                               
    rankdir = LR;

    node[ shape = record ];
    x   [ label = " { <a>A | <b>B } " ];
    y   [ label = " { <c>C | <d>D } " ];

    // edge
    x -> y;
    y:d:n -> y:c:n;
}

yields

enter image description here

Some work could be done to make it look a little more like your requirement but after all, it's a different animal.

vaettchen
  • 7,299
  • 22
  • 41
  • Unfortunately I need a solution that scales, as I will use it in complex scenarios with large graphs and many different node types and cluster sizes. – definelicht Oct 10 '17 at 11:28
1

Here is another workaround it's a bit ugly though, basically you put some additional point nodes outside the subgraph and connect with edges without arrow head, also you probably want to connect them in reverse order to avoid strange impact on layout:

digraph example {      
    rankdir=LR                                                         
    compound=true;                                                              
    "B" -> "C" [ltail="cluster_s0", lhead="cluster_s1"];              
    "C" -> "DC1" [ltail="cluster_s1", dir=none];     
    DC1[shape=point]
    DC2[shape=point]
    DC1 -> DC2 [dir=none]
    "DC2" -> "D" [lhead="cluster_s1"];              
    subgraph cluster_s0 {                                                       
        "A" -> "B";                                                             
    }                                                                           
    subgraph cluster_s1 {                                                       
        "C" -> "D";         
    }                                                                           
}

enter image description here

You can improve the layout a bit by adding an invisible dummy node, but that probable don't scale (my guess is you will have difficulty determin when to add dummy nodes)

digraph example {      
    rankdir=LR                                                         
    compound=true;                                                              
    "B" -> "C" [ltail="cluster_s0", lhead="cluster_s1"];              
    "C" -> "DC1" [ltail="cluster_s1", dir=back];     
    DC1[shape=point]
    "DC2" -> "D" [lhead="cluster_s1"];              
    subgraph cluster_s0 {                                                       
        "A" -> "B";                                                             
    }                                                                           
    subgraph cluster_s1 {                                                       
        "C" -> "D";         
    }    
    DD[shape=point color=none]
    {D DC2}->DD[color=none]                                                                
}           

enter image description here

Jens
  • 2,327
  • 25
  • 34