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.
Related
I have a simple fdp graph laid out in graphviz, with a bunch of nodes (rectangle and diamond shaped) having fixed positions, and some of those nodes have child nodes (oval shaped) that I want to be arranged around them automatically.
I want all edges in it to be straight, with no curves or polylines or anything (i.e. as given by splines=false), but I also want those child nodes to not overlap with edges between nodes with fixed positions. The fixed positions are used as I need edges between the fixed nodes to be fully vertical or horizontal. This is something that I probably can achieve by iterating over different start values and hoping that the next one will not have overlaps, but so far this is a bit tiresome.
digraph G {
###GRAPH
layout=fdp
overlap=false
dpi=150
splines=false
inputscale=0.4
# fdp specific:
K=0.50
maxiter=2000
start=1251
###OBJECTS
node[shape=rectangle width=1.0 height=0.4 fixedsize=true]
vendor[label="Поставщик" pos="3,1!"
]
item[label="Товар" pos="0,2!"
]
post[label="Поставка" pos="2,2!"
]
check[label="Чек" pos="1,1!"
]
prod[label="Продажа" pos="0,0!"
]
###SUBOBJECTS
node[shape=oval width=1.5 height=0.5]
edge[arrowhead=none]
{
vendork[label=<<u>ID поставщика</u>>] "Название\nпоставщика" "Контакт\nдля связи"
}->vendor
{
itemk[label=<<u>ID товара</u>>]
Название Тип Подтип Характеристики "Розничная цена"
}->item
{
postk[label=<<u>ID записи</u>>] post1[label="ID товара"]
post2[label="Кол-во"] post3[label="Цена поставки"]
post4[label="Дата"] post5[label="Квитанция"]
}->post
{
prodk[label=<<u>ID продажи</u>>] prod1[label="ID товара"]
prod2[label="Кол-во"] prod3[label="Цена\nпродажи"]
prod4[label="Чек"]
}->prod
{
checkk[label=<<u>ID чека</u>>] Дата Кассир "Сумма" "НДС" "Итого" "Вид оплаты"
}->check
###CONNECTIONS
node[shape=diamond]
edge[arrowhead=open]
vendorpost[label="Поставляет" pos="3,2!"
]
vendorpost->vendor
vendorpost->post[arrowhead=openopen]
postitem[label="Поставлен" pos="1,2!"
]
postitem->item
postitem->post[arrowhead=openopen]
itemprod[label="Продан" pos="0,1!"
]
itemprod->item
itemprod->prod[arrowhead=openopen]
prodcheck[label="Включает" pos="1,0!"
]
prodcheck->prod[arrowhead=openopen]
prodcheck->check
}
(forgive the cyrillics)
I am compiling with no additional parameters (i.e. dot -Tpng graph.gv > graph.png). So far, I get this.
I've tried using neato instead as well, but, in most cases, it gives a pretty weird result, where it seems like it completely ignores the fixed node positions, and draws the child nodes whereever it wants:
I went through the list of attributes in the documentation, and so far none seem to address node/edge overlapping besides splines (unless I've missed something). What should I do to achieve the result I'm looking for?
There are several issues:
layout=fdp causes the fdp layout engine to be used, no matter what the command line says
Use neato -n if you want to nail down the node position (see below)
by adding a ! to the position you are nailing down the pos (it won't change)
dot is not useful here, it is directional (top-down)
If you remove all the !, I think you will get what you want.
So far, one solution I've found is by adding invisible stretched out nodes that cover each edge that is fixed(i.e. between two nodes with fixed positions) by appending this to the graph:
###NO VERTICAL/HORIZONTAL EDGE/NODE INTERSECT HACK
node[style=invis]
node[width=0.1 height=2.0]
t1[label="" pos="0,1.5!"]
t2[label="" pos="0,0.5!"]
t3[label="" pos="1,0.5!"]
t4[label="" pos="3,1.5!"]
node[width=2.0 height=0.1]
t5[label="" pos="2.5,2!"]
t6[label="" pos="1.5,2!"]
t7[label="" pos="0.5,2!"]
t8[label="" pos="0.5,0!"]
node[style=normal]
And this does what I want, i.e. removes all overlaps with fixed edges:
However, this is limited only to edges that are perfectly vertical/horizontal(note that there is still at least 1 overlap in "child" nodes), and overall seems like a really hacky solution as I have to add/change those "support beams" every time I add/change any more nodes to my graph. Is there a better solution to this?
I have a graph laid out using D3 graphviz. It's laying out in a pretty dense way, and I'd like it to use more of the width of the screen.
I have tried adjusing the ranksep and the ratio, but neither seem to have any effect. I've also tried changing the node border, to no effect. Changing the edge minlength just makes the edges look floppy. I can try giving every node an invisible child, but that seems like a horrible hack.
For clarity, by rank, I mean the horizontal spacing between the columns of nodes. (The graph is laid out left to right.)
Ideally I'd be able to give it an aspect ratio and it'd make the most of that space to lay out the graph in a way that doesn't need too much acrobatics.
Am I missing something obvious?
I may well be using the options incorrectly
or the D3 graphviz implementation may not have those features?
Is there no good way to do this?
I have added :
size = "16.66,8.33!"; // 1200x600 at 72px/in, "!" to force
ratio = "fill"; // see https://graphviz.gitlab.io/_pages/doc/info/attrs.html#d:ratio
at the beginning of the graph declaration (just after digraph G {).
It renders a wider output.
Have a try and tell.
Ok, I know the question of ordering nodes in GraphViz has been hashed to near-death, but I haven't seen anyone address the question of ordering clusters. I tried all the tricks in the book:
The order of the nodes in the file is left-to-right. If I don't add clusters, dot simply does the right thing and shows them in the right order without any prompting. However, when clusters are added, dot shuffles (randomizes?) the order.
I added invisible edges to try and force the order between the sub-clusters; but it seems that as soon as sub-clusters are placed inside a cluster, dot decides on some specific order, and will not hesitate to have edges go all around the map to preserve it.
Since order-of-nodes and invisible edges failed me, I turned to trying to force the position of the nodes. This fails again, because only dot does clusters, and it ignores input positions. Running even the unmodified output of dot through fdp (with the generated positions) caused a crash, so I gave up on that direction as well.
Here is an example dot file which produces the image below. The green lines are the "invisible" edges I added unsuccessfully trying to force dot to order everything from left to right. If this was successful, the green lines would have gone from the anchor to the left through the nodes in order to the right, without crossing themselves. For example, each be.0 would be to the left of its sibling be.1, and similarly for tg-s). As you can see, dot shuffled the order of the sub-clusters (putting the .1 sibling to the left of the .0 one). It is as if it is doing it on purpose, due to some constraint, regardless of any edges. I can't find any way whatsoever to convince it to do otherwise. This is extremely frustrating because the generated diagrams are otherwise perfect for my needs.
(source: ben-kiki.org)
So. Is there any way at all to force dot to respect some order of clusters-within-a-cluster?
Edit: Looking further into this, it seems as though the default ordering for clusters is reversed from that of nodes. That is, normally (in a TB graph), a node that appears first in the text will tend to appear to the left of a node that appears later in the text; but it seems that a sub-cluster that appears first in the text will tend to appear to the right of a sub-cluster that appears later in the text. Now, if this was a hard-and-fast rule, life would be great; however, dot still sometimes (but less often) insist on rearranging the sub-clusters, regardless of any resulting crossed edges, seemingly "just because". So the question remains.
A bit late but here are some ideas for other that comes here:
(the example data is a bit to large to play around with)
anyway have you tried:
edge[constraint=false] on some of the black/red lines (constraint=false may course
some strange long edge routing though)
and/or edge[weight=1000] on the green lines (more difficult to get right),
you might also want to throw in a bit more scaffolding
you cant rank=same across clusters so if needed it must be on scaffolding nodes
here is a light example that successfully turns the order of half the nodes including clusters
digraph G {
subgraph cluster_sa{
edge[weight=1000]
subgraph cluster_s1a{ s1a1->s1a2 }
subgraph cluster_s2a{ s2a1->s2a2 }
subgraph cluster_s1a_{ s1a1_->s1a2_ }
subgraph cluster_s2a_{ s2a1_->s2a2_ }
s1a2->s1a1_
s2a2->s2a1_
}
{
edge[constraint=false]
subgraph cluster_ta{
subgraph cluster_t1a{ t1a1->t1a2 }
subgraph cluster_t2a{ t2a1->t2a2 }
subgraph cluster_t1a_{ t1a1_->t1a2_ }
subgraph cluster_t2a_{ t2a1_->t2a2_ }
t1a2->t1a1_
t2a2->t2a1_
}
edge[tailport=s headport=s]
s1a2_->t1a1
s2a2_->t2a1
}
edge[color=green]
node[color=green]
{rank=same s1a0->s2a0->t2a0->t1a0}
s1a0->s1a1
s2a0->s2a1
t1a0->t1a2_
t2a0->t2a2_
t1a2_->t1a1_->t1a2->t1a1
t2a2_->t2a1_->t2a2->t2a1
}
rendered on viz-js.com
some times it might also be usefull to connect node in reverese order (e.g. t2a2_->t2a1_[dir=back] instead of the above would actually be better as the green arrow could then be remove giving a straight black arrow) but I dont think that would help in your case
I have perfection paralysis when it comes to producing something graphic. If symmetries of the visual have not been fully explored, I have a harder time comprehending what is going on. I am a very visual learner as well, and I LOVE to simplify things that I just learned and draw them on paper.
Graphviz is a nice tool to draw thing automatically, but it could be better. Let's start with an example of a good graph )a state machine rather). Never mind the quality (it can be redrawn with a better tool) this one is almost perfect, except that I would turn it counter-clockwise 45 degrees to make the symmetry apparent. It should then take the reader less time to figure out how the states q1 and q2 are similar and how where they differ. I argue that there is a single best way to represent that diagram, given that there are no other pieces of graphic next to it.
(source: gallery.hd.org)
Now let's look at a less than perfect depiction:
(source: softpedia.com)
This looks like something a graphviz would generate. Yes, the edges are smooth but GAAAAWWWD this is unnecessary confusing! It looks like a mind map, not a finished diagram ready for consumption. I believe that human eyes CRAVE (no less) symmetry. Yes, hierarchy, etc. are also important factors.
I am surprised that there aren't better algorithms available. Some people are not visual learners at all; they can grasp abstract concepts by reading symbols. Not me!
So, what is my question? Well, is there better free software available for drawing small-to-medium graphs? Perhaps
Thank you!
Let me know how I can improve this post.
P.S. I took 10 minutes to draw out a similar enough clone in dia. It is still not perfect, but it was convenient to make because everything snaps to grid (and I missed a few little details but do not feel like re-uploading). The LR_0 needs a "Start--->" coming from above to let the user grasp the starting state sooner.
After several attempts at drawing your graph and failing to get a layout that you deem "best", you posed the question here: is there "[b]etter free software [for] drawing small-to-medium graphs." The sole criterion you've given for evaluating layout algorithms is how closely they come to the "[s]ingle best way to represent that diagram." "Best" of course, left for you to decide.
This is more or less the same as attempting to solve a problem using a given programming language, failing, and then asking for a better programming language.
At the heart of graph drawing algorithms are optimization routines that generate then evaluation solutions ('solution' here refers to the coordinates for each node which together comprise a layout). Those solutions are evaluated according to minimization of a single criterion or a series of ranked criteria--i.e., the minimization of one or more attributes of the graph--for instance, the total number of edges that cross, or the sum of the distances between nodes (or the combination of both, or some weighted combination of those two), or the closeness to a symmetrical configuration. Graphviz is comprised of six different layout algorithms (dot neato, fdp, sfdp, twopi, and circo). Of these, it appears you only used dot; however, twopi and circo might have been better options given their strict symmetry constraints which appear to match your own idea of a correctly drawn graph.
Second, the text of your question is directed to "graphs" and graph-drawing, After reading your full description, i don't think your question has anything to do with either concept.
Beyond the general graph drawing algorithms (like graphviz), there are a number of domain-specific layout algorithms, for instance, Hasse diagrams (to represent partially ordered sets in order theory), Barabasi-Albert graphs (scale-free networks), and Erdos-Renyi (random graphs). Each of those algorithms produces a graph layout based on criteria and constraints supplied by the domain--this ought to indicate to you that there is not a single "best" layout across all domains. Although you used the term "graph" in your question, your description indicates that your problem relates to drawing state machines--a highly idiosyncratic type of graph. General graph drawing algorithms are often poor at drawing specialized graphs of this sort because the algorithm knows nothing about domain. In fact, I'm not aware of any layout algorithm for state diagrams--just like there isn't one for flow diagrams (not the same, but similar). Workflow-wise, you might draw the graph in graphviz then import it to Omnigraffle for fine tuning--in Omnigraffle, you'll have fine-grained control over the node and edge placements.
Some softwares let users tweaking layout algorithms in real-time, as long as moving nodes with the mouse. This approach may greatly help you for larger graphs.
I mostly know Gephi (disclamer: I'm a dev).
There are a number of options i know of:
Prefuse - They have an older Java version. The newest version is in Flash and has some nice layouts. Its called Prefuse Flare. The demo page illustrates some of its layout capabilities.
JUNG includes a number of layout options, as well as its powerful graph analysis functions. There are some examples here.
Networkx also includes numerous layout capabilities. Some of them are listed here.
TikZ generates beautiful graph layouts. You can use a manual layout that lets you specify the minimum of hints, or you can ask for automatic layout. Defaults are good, and hooks exist to tweak to perfection.
With the semi-manual layout you don't have to declare every detail, because you can
declare nodes as being 'above of', 'below right of', etc. relative to other nodes.
place your nodes on a raster by entering them as a matrix: very convenient if you want to leave some positions empty.
easily specify in what direction edges should enter, leave, bend, or take corners
For automatic layout, TikZ's graphdrawing library has some pretty slick algorithms.
Here is an example of manual layout and the TeX code used to obtain it:
\usepackage{pgf}
\usepackage{tikz}
\usetikzlibrary{arrows,automata}
\usepackage[latin1]{inputenc}
\begin{document}
\begin{tikzpicture}[->,>=stealth',shorten >=1pt,auto,node distance=2.8cm,
semithick]
\tikzstyle{every state}=[fill=red,draw=none,text=white]
\node[initial,state] (A) {$q_a$};
\node[state] (B) [above right of=A] {$q_b$};
\node[state] (D) [below right of=A] {$q_d$};
\node[state] (C) [below right of=B] {$q_c$};
\node[state] (E) [below of=D] {$q_e$};
\path (A) edge node {0,1,L} (B)
edge node {1,1,R} (C)
(B) edge [loop above] node {1,1,L} (B)
edge node {0,1,L} (C)
(C) edge node {0,1,L} (D)
edge [bend left] node {1,0,R} (E)
(D) edge [loop below] node {1,1,R} (D)
edge node {0,1,R} (A)
(E) edge [bend left] node {1,0,R} (A);
\end{tikzpicture}
\end{document}
Graphviz can generate that diagram you specified.
Image:
Script:
digraph {
ranksep=1;
nodesep=0.5;
node [shape=circle]
Start [margin=0 width=0 shape=plaintext]
q0 [shape = doublecircle label=<<I>q</I><SUB>0</SUB>>]
q1 [label=<<I>q</I><SUB>1</SUB>>]
q2 [label=<<I>q</I><SUB>2</SUB>>]
q3 [label=<<I>q</I><SUB>3</SUB>>]
Start -> q0
q1 -> q0 [xlabel="1"]
q0 -> q1 [xlabel="0"]
q1 -> q3 [label=" 0"]
q3:se -> q3:e [label=" 0,1"]
q2 -> q0 [xlabel="0 "]
q0 -> q2 [xlabel="1 "]
q2 -> q3 [label="1"]
{rank=same; Start; q0; q1}
{rank=same; q2; q3}
}
Source answer
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].