easybuilders / easybuild-framework

EasyBuild is a software installation framework in Python that allows you to install software in a structured and robust way.
https://easybuild.io
GNU General Public License v2.0
152 stars 204 forks source link

Better layout of --dep-graph output #2707

Open paulmelis opened 5 years ago

paulmelis commented 5 years ago

The current output of --dep-graph leads to very wide images as the nodes are layed out top-to-bottom, where several (wide) nodes get placed side-by-side. This is especially relevant when using --robot to include all deps when tracking dependency problems.

A simple improvement is to use rankdir="LR"; in the .dot file, as this will layout the nodes in left-to-right order. The resulting images from dot are usually less skewed in one direction and I personally find the overall graph easier to read as well.

I don't have a patch for this, as the tweak is quite simple: directly after the digraph graphname { line add a line containing rankdir="LR";, the dot tool will then take care of the rest. E.g.

digraph graphname {
rankdir="LR";
"Bison/3.0.4-GCCcore-6.4.0";
"pkg-config/0.29.2-GCCcore-6.4.0";
"M4/1.4.18";
"flex/2.6.3";
"zlib/1.2.11";
"OpenMPI/2.1.1-GCC-6.4.0-2.28";
...
boegel commented 5 years ago

@paulmelis Do you mind sharing an example of a particularly wide dep graph, and how it looks better when rankdir="LR" is used?

paulmelis commented 5 years ago

Sure, see the attached examples for ParaView-5.6.0-foss-2017b-mpi.eb, the first is using the default layout, the second uses LR layout.

doh

doh-lr

There are other improvements that could me be made, for example to add a newline between the package name and the version for a node and increase the package name label. Here's an example where I only adjusted the binutils label:

doh-lr-nl

The tweak to the dot file in this case is to use "binutils/2.28-GCCcore-6.4.0" [label=<<font point-size="50">binutils</font><br/>2.28-GCCcore-6.4.0>]; instead of "binutils/2.28-GCCcore-6.4.0"; (only for the declaration of the node, not when declaring the edges)

paulmelis commented 5 years ago

Of course these tweaks mostly matter for large graphs, but then, --dep-graph is probably only used for complex dependency situations anyway.

boegel commented 5 years ago

@paulmelis These tweaks make a lot of sense to me, indeed. The only thing I'm not sure of is the custom font size for the dependency name. How about using <strong>...</strong> instead?

Are you up for making a PR for this?

paulmelis commented 5 years ago

I don't have a development environment for EB set up and don't have the resources to do so (I don't maintain our EB installation, I'm merely an end-user). I did quickly check how much work the changes would be. The biggest issue is that the python module being used to set up the graph does not seem to support graph-level attributes. So here's an (untested) patch that works around this by inserting the rankdir attribute in the serialized .dot output just before it is written. That's all I can make of this, sorry.

paulm@int3 14:19 ~/c/easybuild-framework-git$ git diff
diff --git a/easybuild/framework/easyconfig/tools.py b/easybuild/framework/easyconfig/tools.py
index ba7b634..6ecbbf1 100644
--- a/easybuild/framework/easyconfig/tools.py
+++ b/easybuild/framework/easyconfig/tools.py
@@ -221,6 +221,13 @@ def _dep_graph_dump(dgr, filename):
     """Dump dependency graph to file, in specified format."""
     # write to file
     dottxt = dot.write(dgr)
+    # Set rankdir graph attribute. However the pygraph class
+    # used here, digraph, does not support setting graph attribute,
+    # so we hack it into the serialized .dot output
+    pat = re.compile('^digraph .* {')
+    m = pat.search(dottxt)
+    assert m
+    dottxt = m.group(0) + '\n rankdir="LR";' + dottxt[m.end(0):]
     if os.path.splitext(filename)[-1] == '.dot':
         # create .dot file
         write_file(filename, dottxt)