Display nodes below parent without taking ranks to account - graphviz

I'm making sorta super simplified class diagram in dot language. The diagram contains only simple nodes with class names, inheritance and aggregation.
In order to have a specific style for inheritance edges, and to display children classes below their parent, I use this setup:
subgraph inheritance {
edge[dir="back"; arrowtail="empty"; arrowsize="1.75"];
color=white;
subgraph clusterExpression{
Expression -> VariableExpression;
Expression -> AssignmentExpression;
Everything works fine, but when I have a lot of subclasses my diagram becomes really wide. I don't care about subclasses being on the same level or not.
Is there a way to display all subclasses below superclass but in most compact way? Instead of this:
I want to get something like this:

You may try the graphviz tool called unflatten :
unflatten is a preprocessor to dot that is used to improve the aspect
ratio of graphs having many leaves or disconnected nodes. The usual
layout for such a graph is generally very wide or tall. unflatten
inserts invisible edges or adjusts the minlen on edges to improve
layout compaction.
You can pipe it into your command line - see these answers for examples.

Related

Creating a more compact layout in GraphViz using dot

I have a directed graph on 31 nodes for which Graphviz' dot layout engine produces the following layout:
I'm unhappy with the layout because there is too much space surrounding the four-node-cluster 8-10-20-21. What settings can I tweak to improve Graphviz' layout of graphs like these? Interestingly, if I change the direction of the 25-21 edge I get a much more compact layout:
I guess this is because Graphviz strongly believes that all edges should point downwards. Perhaps I tell Graphviz that it is ok for some edges to point upwards?
You can play with the graph here.
Yes, dot definitely strongly believes that all edges should point downwards! While you can indicate that specific edges can skip that rule (reversing edge direction, rank=same, and constraint=false), I can't think of any way to generally relax the rule. (for details, see https://graphviz.org/doc/info/attrs.html).
But if a hierarcical view is not important, try some of the other engines (neato, fdp, circo, twopi). This is an "eye-of-the-beholder" thing, but I liked neato -Nlen=1.8 -Gmode=hier -Goverlap=false
Giving:
You can annotate the offending edge as "21" -> "25" [dir = "back"]; to keep the original arrow while changing the sense of the hierarchy implicit in the dot layout.
using constraint = false can help in some circumstances, but it often results in the layout of the edge to be routed in an unexpected (read ugly) path.

GraphViz Dot. How to distribute elements around a boxed size?

I have a dot graphviz file that geneates the following output:
http://www.qlands.com/other_files/test.png
However the output is organized vertically. If I setup the size to be for example 8.27 inches; How can I distribute the elements around a box of 8.27 x 8.27 inches?
Your graph is a directed graph layed out with dot from left to right, and the first rank contains many nodes which results in a very high image.
The main tool to break up graphs with this problem is unflatten:
unflatten is a preprocessor to dot that is used to improve the aspect
ratio of graphs having many leaves or disconnected nodes. The usual
layout for such a graph is generally very wide or tall. unflatten
inserts invisible edges or adjusts the minlen on edges to improve
layout compaction.
You may combine this with other tools and techniques to get the result you want:
Use the unflatten utility - please see this answer for a detailed example using unflatten.
Use invisible edges to introduce new ranks (basically what unflatten does automatically, but with human inspiration... example also here)
If you need the output to be of this exact size, be sure to understand graphviz's various attributes which have an impact on it, such as size, margin, ratio... (see also this and yet another answer providing details)
Finally, you could simply use a different layout (neato for example)

Annotate DOT graphs with images

I'm using PyDot to generate Graphviz/dot graphs in python. I would like to annotate my nodes and edges with images read from files, I've found in the documentation how to put an image as a node, but not how to put an image under a node or even less an edge.
http://www.graphviz.org/doc/info/attrs.html
http://www.graphviz.org/doc/info/shapes.html
http://www.graphviz.org/Documentation/html/shapehowto.html
Does anybody know how to do that?
You can use HTML in the labels for nodes and edges. You can find details here: http://www.graphviz.org/doc/info/shapes.html#html
Basically you can say something
"a" -> "b" [label = <<TABLE><TR><TD><IMG SRC="path/to/picture"/></TD></TR></TABLE>>]
You can add as many rows and columns as you want in the html labels. It's a little more verbose than standard text labels, but you can do a bit more with them.
One method which can work in cases where edges will always be drawn in the same position is to create a PNG with a transparent background and position the icon in the same place that your edge will be drawn, or use the labeldistance/labelangle attributes to move. I'm not familiar with PyDot but using SQL I would create a case to determine whether or not the image is displayed on the node..
Problem with this method is that the graphs which I'm working with are always positioned differently and will never be the same, so in an ideal case I'd like to add the image to the edge label, or under/to the right of the edge label etc. Did you ever manage to find a workaround?

How does one originate multiple edges from a single Graphviz record field?

Having single edges originate from a Graphviz record field is very straightforward and easy to control via ports and compass points.
I have a need, though, to have multiple edges originate from a single record field. The syntax of the DOT language does not appear to support this. Subgraphs may work for me, but the depiction of records is really the best representation of the data records.
have multiple edges originate from a single record field
I'm not really sure why the syntax of the dot language would not allow it. For example:
digraph g{
r[label="<f0> left|<f1> middle|<f2> right", shape=record];
r:f0 -> {a;b;};
r:f2 -> c;
r:f2 -> d;
}
The fields f0 and f2 have both more than one outgoing edge.
By the way, though record shapes still work, it seems as if HTML-like labels are replacing them. From the graphivz web site:
The record-based shape has largely been superseded and greatly
generalized by HTML-like labels. That is, instead of using
shape=record, one might consider using shape=none and an HTML-like
label.

Prevent overlapping records using graphviz and neato

I am building a dot file to represent computer hardware and the physical connections to a network switch and displays. I have it looking ok when processed by the dot program but I think I really want it processed by neato to create a more "free form" picture as it starts to grom. Right now when I run my large file with neato, everything is overlapping.
I am trying to figure out the syntax on where to define the overlap attribute. Below is a subset of my dot file.
graph g {
node [shape=record,height=.1];
PC8[label="{{<GigE1>GigE1|<GigE2>GigE2}|{<name>PC8}|{<dvi1>dvi1|<dvi2>dvi2|<dvi3>dvi3|<dvi4>dvi4}}"];
PC9[label="{{<GigE1>GigE1|<GigE2>GigE2}|{<name>PC9}|{<dvi1>dvi1|<dvi2>dvi2|<dvi3>dvi3|<dvi4>dvi4}}"];
C1[label = "{{<dvi1>dvi1}|{<name>C1}}"];
C2[label = "{{<dvi1>dvi1}|{<name>C2}}"];
C3[label = "{{<dvi1>dvi1}|{<name>C3}}"];
C4[label = "{{<dvi1>dvi1}|{<name>C4}}"];
D1[label = "{{<dvi1>dvi1}|{<name>D1}}"];
D2[label = "{{<dvi1>dvi1}|{<name>D2}}"];
"PC8":dvi1 -- "C1":dvi1;
"PC8":dvi2 -- "C2":dvi1;
"PC8":dvi3 -- "C3":dvi1;
"PC8":dvi4 -- "C4":dvi1;
"PC9":dvi1 -- "D1":dvi1;
"PC9":dvi2 -- "D2":dvi1;
}
Well, as with most questions...soon after I posted the I figured out the answer. I needed to add graph [overlap=false]; at the top of the file.
Do it like this:
graph g {
overlap = false;
node [shape=record,height=.1];
/* ... */
}
Setting overlap to false will work for neato as the community wiki answer says; however, if the graph exhibits any kind of regularity or symmetry, [overlap=false] will often mess it up by jiggling the nodes around to make them not overlap.
Use [overlap=false] as a last resort.
All node overlaps that are outputted from neato can be viewed as occurring because the nodes are too big relative to the edges. You can make any overlaps go away by making the nodes smaller and preserve symmetry in the graph drawing by setting [overlap=scale]. Quoting the Neato user manual:
To improve clarity, it is sometimes helpful to eliminate overlapping
nodes or edges. One way to eliminate node overlaps is just to scale up
the layout (in terms of the center points of the nodes) as much as
needed. This is enabled by setting the graph attribute overlap=scale.
This transformation preserves the overall geometric relationships in
the layout, but in bad cases can require high scale factors
As the documentation says [overlap=scale] can result in graph drawings that are unacceptably large, but if it does not its output is generally going to be better looking than [overlap=false].

Resources