click/selection event callbacks from GraphViz/DOT SVGs?

Hi folks. I have only recently appreciated how clever Observable is, so I may be missing some basics.

I am working with graph data models that are very nicely visualizable using graphviz/dot. However it would be so much richer if the nodes in the dot diagram could be made to interact with the rest of the notebook. For example, to show more details, state or offer interaction opportunities contextualized to one of the possibly very many nodes in a graph.

I searched the forum and couldn’t see any discussion of this. The closest was Hyperlink in Graphviz node doesn't work which is concerned with URLs being clickable.

What I have tried to do is tweak a notebook I found, such that if you click a node it will call a nominated callback. It isn’t working, but realistically I’m not going to have time to figure this out for a while so I thought I’d share the half-baked idea in case it’s interesting for others here.

My rough experiments are here: Can GraphViz dot be made more interactive? fork: with click/selection handling? / Dan Brickley / Observable

Note that I forked from a notebook which depends on the hpcc-js-wasm re-packaging of graphviz, rather than the Observable built-in. The notebook I forked from already toggles the styling of nodes, so I think it establishes the principle that such things can be exposed fully to scripting, … it’s just a matter of working out the details (and thinking about mobile/desktop/accessibility UX-level concerns).

1 Like

If you inspect the graph using your web browser’s inspector, you should notice that the nodes and edges all have associated ids. That means you can use d3 to select them and attach any behavior you like. Here’s an example:

If you check out the notebook, you should notice that the graph and text live in two different cells. Clicking on node c should change the text in the cell to yield of click count. Exiting the node reverts back to the original text.


Sometimes it seems to take a few seconds after you reload the page for the events to start being recognized. I’m not sure why.

1 Like

d3-graphviz renders asynchronously, but you can specify a callback to be invoked when the render is finished:

const div = d3.create("div");
// ...

await new Promise(resolve => {
  d3.graphviz(div.node()).engine("circo").renderDot(source, resolve);
});

div.selectAll("title").remove();
// ...
1 Like

Thank you both!