Wrapping wide ranks onto multiple rows

Hi! I have used the pydot library in a few different python based tools that I work on to create graphs of relationships between objects managed by those tools. In one case, the objects represent components inside a simulation of a computer system (CPUs, devices, interconnects, etc), and in another they represent steps in an automated process with various inputs and outputs.

In both, there are times when there are many inputs or peer components which all end up on the same rank in a graph. The resulting graphs may have a very wide aspect ratio which makes them hard to read for the people who are trying to use them to visualize what’s going on.

Is there a way where we can compress this excess width and put these peer components on multiple rows, even though they would have the same rank? A reasonable (if crude) heuristic might be to recognize when we’re creating a group of more than, say, 4 objects and start wrapping them into new rows, though keeping them conceptually within the same rank.

It would be extra great if we could get the software to do this, and have it shoot for, say, a 1:1 aspect ratio, or to stay within some width constraint so the graph could be printed without everything being tiny.

It’s been so many years, but I’m certain Emden Gansner knew about algorithmic solutions to this problem and possibly even implemented a prototype algorithmic in graphviz. I realize this isn’t much help because it involves plumbing the depths of the code for a poorly documented feature. I’m sure the problem has been addressed in the graph drawing literature.

Also this is asking for something is a little like the unflatten tool in graphviz but not quite the same.

Here are some ways to make your graphs skinnier, roughly ordered by effort needed.

  • use node shape rect instead of the default ellipse. For wider nodes this really makes a difference
  • set node margin smaller, try 0.05,0.05
  • set nodesep smaller, maybe .18 (note: units are inches)
  • use a narrower font, try arial, verdana, or Lato
  • use a smaller fontsize, maybe 12
  • the graph-level TBbalance attribute might help in occasional circumstances
  • add line breaks to long (wide) labels
    e.g. "label=“stuff, stuff,\nand more stuff”
  • consider other layout engines, especially osage, twopi, and circo. None are as “powerful” as dot, but each is useful in the right situation. See: Layout Engines | Graphviz. And: Creating heirarchical graphs w/clusters for more osage info.
  • try unflatten as @scnorth suggested. It seems to do some of what you suggested.

You can try any/all of the above today and make things better, but maybe not as much as you wanted. In particular, try unflatten.

That said, one can envision a unflatten+ that would add to the unflatten algorithms, taking the ranking that dot produces and splitting those ranks into subranks, somewhat as you described. Maybe easy in some cases and probably impossible in others. Clusters would seem to add difficulties.
Note that “count-off-by-4s” would seem to do fine if all the nodes were about the same size, but maybe not so well if some nodes were much wider than others.

Can you provide examples to experiment on?

For completeness, Emden mentions this was explored in a summer intern project, but the prototype wasn’t robust enough for general release.

Plus, I think this is still an active research area.

Also, I found An OverviewDetail Layout for Visualizing Compound Graphs 2024 so great to know there is still progress on related problems in drawing compound graphs.

Thanks! I gave unflatten a try, and it did make a significant difference. I think to use it we would need to switch from the pydot package to the graphviz one since unflatten doesn’t seem to be exposed by the former, but that’s probably not that much of a hurdle.

Unfortunately I probably can’t share the graphs due to their contents, but I think this gives me something to start with. Thanks again!

unflatten was exposed programmatically in response to a request from pygraphviz. This change was made in Graphviz commit 25520f348fb5218fc0ca1f346cfa4e74b6d0bc78 that landed in Graphviz 10.0.1. So you (or someone else) probably just need to implement the corresponding bridge in pydot.

  1. you are encouraged to create an enhancement request here
  2. here is a (partial) anonimizer for input graphs. command line is gvpr -cf anon myfile.gv