How position elements with dot for a control system diagram? - graphviz

I want control over the positioning of some elements in the following sample:
digraph {
graph [splines=ortho];
/* Node customization. */
node [shape=box];
join [shape=point];
set [label="set\npoint"];
/* Define node levels; driving elements on top, feed back below. */
{ rank = min; set; PID; P1; P2; join; OUT;}
{ rank = max; M1;}
/* Edges */
set -> PID -> P1 -> P2;
P2-> join [arrowhead=none];
join -> {OUT; M1};
PID -> M1 [dir=back];
}
If I add more elements to the M1 rank the edges connect to random points (north/top side). I would like to keep them connect horizontally. Can this be done?
How can I increase spacing (edge length) between PID/P1/P2?
It would be nice to align P1/M1 vertically. Can this be done?
Traditional control system diagrams don't have the join node and an edge just comes out of another edge. Is this possible? I removed the arrow head for this.
Maybe some of the questions are extraneous as proper positioning of one will make the others happen naturally.

Generally you can control the point where the arrow enters node with headport attribute. But with ortho splines this rarely works. Ortho splines live their own life and can cause a variety of different problems, including disappearing edge labels. So there's no definite answer to your first question, each situation has to be handled specifically.
You can increase distance between all nodes by setting a nodesep graph attribute. But if you need to increase distance only between specific nodes, you can use a trick: Add a label with big number of spaces for value.
You can accomplish it with invisible edges.
Points 2 and 3 illustrated in edited example below:
digraph {
graph [splines=ortho];
/* Node customization. */
node [shape=box];
join [shape=point];
set [label="set\npoint"];
/* Define node levels; driving elements on top, feed back below. */
{ rank = min; set; PID; P1; P2; join; OUT;}
{ rank = max; M1;}
/* Edges */
set -> PID;
P2-> join [arrowhead=none];
join -> {OUT; M1}
PID -> M1 [dir=back];
PID -> P1 -> P2 [label=" "] /* #2 increase space between specific nodes */
P1 -> M1 [style=invis] /* #3 align P1 an M1 */
}
result:

Related

How do I force nodes to be drawn next to each other with Graphviz dot?

I'm looking to have a series of nodes in a row, joined by an edge. This works fine when the graph's rankdir is set to TB or BT, but it rearranges the nodes when I set it to LR or RL so they're no longer next to each other. Example images are included.
I've taken my code and stripped it down to it's minimum point for demonstration. The code is the same for both of the following graphs, aside from line 2 (which specifies rankdir):
digraph{
rankdir=LR;
node[shape=box,fontcolor=white,color=black,fillcolor=black,style=filled];
edge[dir=none,color=black];
Josh -> JoshParent;
JoshParent -> Hero;
JoshParent[shape=circle,label="",height=0.0001,width=0.0001];
{
rank=same;
Kae[label="Kae"];
Hero[label="Hero"];
Kae -> Hero;
}
Kae -> KaeParent;
Hero -> HeroParent;
KaeParent -> Liz;
KaeParent[shape=circle,label="",height=0.0001,width=0.0001];
HeroParent -> George;
HeroParent[shape=circle,label="",height=0.0001,width=0.0001];
{
rank=same;
George[label="George"];
Liz[label="Liz"];
Ocean[label="Ocean"];
Egg[label="Egg"];
Liz -> Ocean -> Egg;
}
}
This is what's shown with rankdir=TB:
This is what's shown with rankdir=LR:
As you can see, from the LR image, the nodes have been drawn in the order "Ocean, George, Egg", rather than "Ocean, Egg, George" as it is with the TB image.
You can force the order by adding an explicit but invisible edge from Egg to George:
Liz -> Ocean -> Egg; // last line of your code
Egg -> George[ style = invis ]; // additional edge
This produces
I don't have an explanation for the different behaviour between TB and LR, though.

Graphviz: How to place nodes only in lower semi-circle using circo layout?

In the attached figure, the nodes are arranged in a circle around the node. Is there a (possibly generic) way to arrange the nodes only in the lower semi-circle, without having to provide fixed coordinates for the nodes?
Edit: Would like to achieve something like shown in the image attached below. As one can see - all the nodes are arranged in the lower semi-circular region (this figure was made using CMap Tools).
The code is trivial, but pasting it anyway.
digraph semicircle {
rankdir="TD"
graph [nodesep="0.1", ranksep="0.3", center=true]
mindist="0.4"
S [label="Root", style="filled", fillcolor="greenyellow", shape="box"]
subgraph cluster1 {
rank="same"
A; B; C; D;
S -> {A, B, C, D};
} }
using dot/circo : graphviz version 2.40.1
I noted that circo placed nodes counter-clockwise, starting at 3 o'clock.
I added enough invisible nodes to fill the 2 through 10 o'clock positions.
To make the inter-nodal distances even more uniform I added:
node [shape=square style=rounded]
The result I got is this:
Try this:
digraph semicircle {
rankdir="TD"
graph [nodesep="0.1", ranksep="0.3", center=true, root=S]
mindist="0.4"
S [label="Root", style="filled", fillcolor="greenyellow", shape="box"]
subgraph cluster1 {
rank="same"
A
z1[style=invis label=""]
z2[style=invis label=""]
B; C; D;
S -> A
S -> z1,z2 [style=invis]
S -> { B, C, D};
}
}

GraphViz dot Circular Node Alignment

How to use Graphviz to align nodes circular in clusters with additional text? Optionally with identical node positions (always 8 nodes per cluster)?
I tried circo, however, faced some shortcomings:
No clustering
No comments
Problems with margins for larger labels (10+ char)
Alignment varies with label size
This (Graphviz Online), nothing spectacular, was the closest I could get. Any hints to other layouts (or even tools) appreciated.
graph {
layout = circo;
node [shape = circle,
fontname = Helvetica,
margin = 0]
edge [style=invis]
subgraph 1 {
a1 -- b1 -- c1 -- d1 -- e1 -- f1 -- g1 -- h1 -- a1
}
subgraph 2 {
a -- b -- c -- d -- e -- f -- g -- h -- a
}
}
Not exactly the answer as I was asking for (Graphviz), but I found a much nicer solution with MATLAB. It was about plotting a seating plan for an event.
What I did broken down:
imread() image of the floor plan
Roughly determined pixel spacing, used as x & y vector for image() so that tables are in scale with the room.
Manually defined centers for the clusters (here tables) with the help of ginput() (or imellipse())
Plotted circles with plot() and added text with text()

Why does shape=record not draw the arrow?

Note that I set the rank to same.
The code is:
digraph R {
rankdir = LR
node [shape=record];
{rank = same; rA sA}
rA -> sA;
}
The output is:
When I run this on a Mac with the same version I see the following error:
Warning: flat edge between adjacent nodes one of which has a record shape - replace records with HTML-like labels
Edge sA -> rA
Error: lost rA sA edge
I'm not sure why you don't see this error message. But based on the date of the code commit, it was added after 2.38.0 and is part of 2.40.1. The code change adds a return which is why you don't see an arrow.

Graphviz: Horizontal alignment not working with backwards arrow

I made the following graphic:
I would like to add an additional arrow, pointing back from "remote repo" all the way to "working copy" (labelled with "git pull") and I would like to have that arrow ideally first going slightly down, then left, then up.
When I simply add an arrow to the code, the graphic ends up looking like this:
And this is the code:
digraph G {
/* set direction of graph to be left-->right */
rankdir="LR";
/* make boxes instead of ellipses */
node [shape=box];
/* should enforce nodes to be horizontally aligned */
/* is not working, though... */
rank=same;
/* assign labels to nodes */
wc [label="working copy"];
id [label="index"];
lr [label="local repo"];
rr [label="remote repo"];
wc -> id [label="git add"];
id -> lr [label="git commit"];
lr -> rr [label="git push"];
rr -> wc [label="git pull"];
}
Question: Why is the horizontal alignment broken and how to fix this ?
Follow-up question: How to make an arrow pointing down, then left, then up ? (Or is the only way to do this using somehow invisible/fake nodes?)
You may modify problematic edge with constraint=false attribute. Then you receive below diagram.
If you prefer much more angular edges you can also splines=ortho for the graph.
Please check http://graphviz.it/#/mqNwRgzu with working example. Below I've pasted source code.
digraph G {
/* set direction of graph to be left-->right */
rankdir="LR";
splines=ortho;
/* make boxes instead of ellipses */
node [shape=box];
/* should enforce nodes to be horizontally aligned */
/* is not working, though... */
rank=same;
/* assign labels to nodes */
wc [label="working copy"];
id [label="index"];
lr [label="local repo"];
rr [label="remote repo"];
wc -> id [label="git add"];
id -> lr [label="git commit"];
lr -> rr [label="git push"];
rr -> wc [label="git pull", constraint=false];
}
You can fix it, replacing this line
rr -> wc [label="git pull"];
with
rr -> wc [label="git pull" weight=0];
Result

Resources