I have seen some posts talking about this sort of thing, like here, and here, but I've recreated that graphviz spec and it's not rendering the same. In particular, where an arrow should be starting from a cluster edge and pointing at a node, it instead disappears at that edge and only the head appears at the node.
Here's the code:
G = nx.DiGraph(name='G')
G.add_nodes_from(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
A = to_agraph(G, compound=True)
cluster0 = A.add_subgraph(['a', 'b', 'c', 'd'], name='cluster0')
cluster1 = A.add_subgraph(['e', 'f', 'g'], name='cluster1')
cluster0.add_edges_from([('a', 'b'), ('a', 'c'), ('b', 'd'), ('c', 'd')])
cluster1.add_edges_from([('e', 'g'), ('e', 'f')])
A.add_edges_from([('c', 'e'), ('b', 'f'), ('c', 'g'), ('d', 'h')])#, ('d', 'e'), ])
A.get_edge('c', 'e').attr.update({'ltail': 'cluster0'})
Which produces:
strict digraph G {
graph [compound=True,
name=G
];
subgraph cluster1 {
e -> f;
e -> g;
}
subgraph cluster0 {
a -> b;
a -> c;
b -> d;
c -> d;
}
b -> f;
c -> e [ltail=cluster0];
c -> g;
d -> h;
}
And to render the AGraph, I do:
A.layout(prog='dot')
png_str = A.draw(format='png', prog='dot', args=f"-Gdpi={DPI}")
sio = BytesIO(png_str)
img = mpimg.imread(sio)
plt.imshow(img)
plt.axis('off')
plt.show()
Which renders as:
Knocking out the ltail=cluster0 attribute (#A.get_edge('c', 'e').attr.update({'ltail': 'cluster0'})
), the image comes out to:
What am I doing wrong? (Huge bonus points if in showing me what I've done wrong, you also show an arrow whose tail starts on the border of the interior of two nested clusters and points outside of the outermost one.)
Good news, bad news and (maybe) good news.
Good news: Nothing wrong with the produced dot input.
Bad news: You are encountering this bug (https://gitlab.com/graphviz/graphviz/-/issues/2447)
Good news: It seems to be fixed in the latest release(s). This version (dot - graphviz version 10.0.0~dev.20240113.0503 (20240113.0503)) produced:
(sorry, don't quite understand you "bonus points" question)