I'd like to generate the DOT code to draw the equivalent state machine diagram shown.
I going to be created programmatically, I've got the transitions between states and superstates done. ButI need a bit of help with this:
This gives me an initial transition, but the State1 should be the cluster:
digraph {
compound=true;
node [shape=Mrecord]
rankdir="LR"
subgraph clusterOpen
{
label = "State1"
State2
}
State1 -> State2 [style="solid"];
node [shape = point label="" ] i ->State1
}
Normally Graphviz programs try hard to avoid placing nodes on top of other nodes. But you can place nodes anywhere you like if you explicitly provide a pos attribute for each node (see https://graphviz.org/faq/#FaqDotWithNodeCoords).
The program that creates your input files should calculate a pos attribute for each node. (Remember that pos coordinates are in points, while node sizes are in inches!). You can probably skip calculating the splines for the edges and just let neato do that.
This program:
digraph {
graph [bb="0,0,482.8,337"];
node [label="\N"];
State1 [height=4.0139,
label="{State 1|\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n}",
pos="162,144.5",
shape=Mrecord,
width=4.5];
State2 [height=1.3333,
label="{State 2|\n\n\n\n}",
// pos="403,144.5",
pos="220,88",
shape=Mrecord,
width=1.6944];
xp3 [height=0.05,
label="",
// pos="429,331",
pos="0,194",
shape=point,
// style=dotted,
style=invis,
width=0.05];
r1 [height=0.16667,
label="",
// pos="455,331",
pos="154,194",
shape=square,
width=0.16667];
xp4 [height=0.05,
label="",
// pos="481,331",
pos="0,88",
shape=point,
// style=dotted,
style=invis,
width=0.05];
xp1 [height=0.16,
label="",
pos="162,331",
shape=point,
width=0.16];
xp1 -> State1:n [pos="e,162,288.5 162,325.23 162,319.09 162,308.89 162,298.63",
style=dashed];
xp2 [height=0.16,
label="",
// pos="403,331",
pos="220,194",
shape=point,
width=0.16];
xp2 -> State2:n [pos="e,403,192.5 403,325.19 403,307.39 403,251.8 403,202.57"];
// manually added:
xp3 -> r1 [label="Trigger 1" dir=none ]
xp4 -> State2 [label="Trigger 2" ]
}
Run with this command line:
neato -n -Tpng stateDiagram.dot >stateDiagram.png
Produces this graph:
Related
There is rankdir for the global graph which sets the orientation of the layout. What about subgraph or cluster - is there a way to have one subgraph in TD layout and another subgraph in BT?
How to achieve the graph in the attached image with following (incorrect) code?
digraph G {
subgraph cluster0 {
rankdir="TD";
A; B;
A -> B;
}
subgraph cluster1 {
rankdir="BT"; // this doesn't produce the desired output
C; D;
D -> C;
}
}
You cannot do that, rankdir is only allowed at top level (graph)
but in simple cases you can work around it by
to go in opposite direction:
C->D[dir=back]
to go in to the side:
{rank=same C D}
I have a two clusters that are connected but I can't seem to align the left most cluster (with node nd_6) with the center of the other node (cluster_circ). Here is an example:
digraph d1 {
# configs
rankdir = "LR";
compound=true;
node [shape = plaintext];
edge [arrowhead = "vee"];
nd_1 [group = g1]
nd_2 [group = g1]
# cluster for circular pattern
subgraph cluster_circ {
color=none;
node [shape = plaintext];
nd_3 [group = g1]
{rank=same nd_4[group = g2]; nd_5[group = g3]};
nd_3 -> nd_4:nw;
nd_4 -> nd_5:ne;
nd_5 -> nd_3:se;
}
# right-most cluster
subgraph cluster_r {
color=none;
node [shape = plaintext];
nd_6 [group = g1];
}
# edge connections
nd_1 -> nd_2;
nd_2 -> nd_3;
# connect clusters
nd_5 -> nd_6 [ltail=cluster_circ lhead=cluster_r]
}
Producing the following result:
What I am trying to achieve is to place the node nd_6 and its respective edge connecting to cluster_circ aligned with nd_3.
Thanks!
You need to do two things to achieve your goal:
match your compass points
have an invisible edge from nd_4 that that moves nd_6 up.
Both items are explained in the comments of the source code below. In the course of editing, I have removed a lot of stuff that were not material in the context, for easier reading.
digraph d1
{
// configs // comment characters changed to "standard"
rankdir = "LR";
node [ shape = plaintext ];
edge [ arrowhead = "vee" ];
// nodes
nd_1 nd_2 nd_3;
{ rank=same; nd_4 nd_5 }
nd_6
// edges / connections
nd_1 -> nd_2 -> nd_3;
nd_3 -> nd_4:nw; // matching :s and :n keeps the center:
nd_4:se -> nd_5:ne; // balance nd_4:n with nd_4:s
nd_3 -> nd_5:sw[ dir = back ]; // balance nd_5:n with nd_5:s
nd_4 -> nd_6[ style = invis ]; // this gives you a counterweight
nd_5 -> nd_6; // to nd_5 and thus "centers" nd_6
}
yields
E D I T to show the alternative with an empty node.
This is the result I like best, I have inserted some lines where you could play around with alternative settings. To the best of my knowledge, groups or subgraphs don't help, as edges only go between nodes, not between clusters.
digraph d1
{
// configs // comment characters changed to "standard"
rankdir = "LR";
node [ shape = plaintext ];
edge [ arrowhead = "vee" ];
// nodes
nd_1 nd_2 nd_3;
x[ shape = point, height = 0 ]; // "empty" node
// x[ shape = point, height = .25, color = white ]; // alternative
{ rank = same; nd_4 nd_5 }
// { rank = same; nd_4 x nd_5 } // try also with x in the same rank
nd_6
// edges / connections
nd_1 -> nd_2 -> nd_3;
nd_3 -> nd_4:nw;
nd_4:e -> x:n[ dir = none ]; // route edge via x
x:s -> nd_5:e; // you can try other compass points
nd_3 -> nd_5:sw[ dir = back ]; // balance nd_4:n with nd_5:s
x -> nd_6; // connect the empty node in the middle
}
which produces
I'm trying to use dot to layout several non-connected graphs at the same time using clusters for drawing and styling boxes around each.
The problem is that while on a rendering without clustering, the layout is very neat and separates out unconnected graphs within one cluster, but once I try to use clustering it squashes these together, using less space but rendering the output much less clearly understandable (especially once it starts packing together differently sized labels).
Here's the version without clustering:
And here's with:
And the source -- to get the version without clustering I just deleted the "r" off the end of "cluster".
digraph G {
node[shape="rectangle",fontname="Nimbus Sans"];
subgraph cluster_a {
style=filled;
bgcolor=lightgrey;
node [style=filled,color=white];
a_vq; a_lvt; a_wvw; a_yvy;
a_zgxl; a_hqz; a_yqq; a_zofv;
a_qvr; a_qlz; a_ycr; a_ilq;
a_ouw; a_ryq; a_lgl; a_qvr->a_lgl;
a_kwr; a_qlz->a_kwr; a_yl; a_ilq->a_yl;
a_kgyr; a_hqz->a_kgyr; a_llq; a_ryq->a_llq;
a_llo; a_ryq->a_llo; a_ll; a_ryq->a_ll;
a_ito; a_ll->a_ito; a_rql; a_lgl->a_rql;
a_ier; a_kwr->a_ier; a_lql; a_yl->a_lql;
a_vhgp; a_lql->a_vhgp;
a_vq->a_lvt;
a_lvt->a_wvw;
a_lvt->a_yvy;
a_vq->a_zgxl;
a_hqz->a_yqq;
a_lvt->a_zofv;
a_yvy->a_qvr;
a_zgxl->a_qlz;
a_zgxl->a_ycr;
a_ycr->a_ilq;
a_hqz->a_ouw;
a_yqq->a_ryq;
}
subgraph cluster_b {
style=filled;
bgcolor=lightgrey;
node [style=filled,color=white];
b_uel;
}
}
I tried fiddling with the packmode attribute in a few places, but it just seemed to break styling without fixing the problem and I wasn't entirely sure whether it would fix anything even if it worked properly.
I'd like to retain the neat, spatially separated graphs with clustering layouts -- does anyone know whether this can be done?
More of a hack than a real answer but it works for your sample - use invisible nodes and edges. I have also simplified your code, not sure whether this is suitable for your task but it makes looking at it easier.
digraph G
{
node[ shape = "rectangle", fontname = "Nimbus Sans", height = .5, width = 1 ];
subgraph cluster_a
{
style = filled;
bgcolor = lightgrey;
node[ style = invis ]; // create
inv_1; inv_2; // invisible nodes
node[ style = filled, color = white ];
// first unconnected graph
a_hqz -> { a_ouw a_yqq a_kgyr }
a_ouw -> { inv_1 } [ style = invis ] // insert invisible nodes
a_kgyr -> { inv_2 } [ style = invis ] // using invisible edges
a_yqq -> a_ryq;
a_ryq -> { a_llq a_llo a_ll }
a_ll -> a_ito;
// second unconnected graph
a_vq -> { a_lvt a_zgxl }
a_lvt -> { a_wvw a_yvy a_zofv }
a_zgxl -> { a_qlz a_ycr }
a_yvy -> a_qvr -> a_lgl -> a_rql;
a_qlz -> a_kwr -> a_ier;
a_ycr -> a_ilq -> a_yl -> a_lql -> a_vhgp;
}
subgraph cluster_b
{
style = filled;
bgcolor = lightgrey;
node[ style = filled, color = white ];
b_uel;
}
}
I want to draw a V-Modell for software development. I want to use graphviz to keep it more maintainable than in Visio.
How can I get the typical V-structure in Graphviz?
I think I need horizontal and vertical alignment.
I tried to work with dummy-nodes but the layout is still poor.
This code works for me. It has a bit of a workaround in it to create the V shape. I use an invisible node and invisible edges to create a wedge between the 2 sides of the V-model.
digraph Vmodel {
// Transparent background
graph [bgcolor=none]
// Node style
node [
shape=record
style="rounded, filled"
width=2.5
height=0.8
fillcolor=white
];
// Create the nodes
user_req_models [label="User\nRequirements\nModels"]
sys_req_models [label="System\nRequirements\Models"]
arch_models [label="Architectural\Models"]
comp_design_models [label="Component\Design\Models"]
unit_design_models [label="Unit\nDesign\nModels"]
units [label="Units\n(SW, HW and Data)"]
components [label="Components\n(SW, HW and Data)"]
subsystems [label="Subsystems"]
integrated_system [label="Integrated System"]
operational_system [label="Operational System"]
// Create a hidden node to form a V-shaped wedge
hidden [style="invis"]
// Create the basic layout of the V model
user_req_models->sys_req_models
sys_req_models->arch_models
arch_models->comp_design_models
comp_design_models->unit_design_models
unit_design_models->units
units->components
components->subsystems
subsystems->integrated_system
integrated_system->operational_system
// Create the dashed edges
user_req_models->operational_system [style="dashed", constraint=false]
sys_req_models->integrated_system [style="dashed", constraint=false]
arch_models->subsystems [style="dashed", constraint=false]
comp_design_models->components [style="dashed", constraint=false]
// Create a wedge between the two parts
hidden->user_req_models [style="invis"]
hidden->sys_req_models [style="invis"]
hidden->arch_models [style="invis"]
hidden->comp_design_models [style="invis"]
hidden->operational_system [style="invis"]
hidden->integrated_system [style="invis"]
hidden->subsystems [style="invis"]
hidden->components [style="invis"]
hidden->unit_design_models [style="invis"]
hidden->units [style="invis"]
// Ranking on the same level
{rank=same; user_req_models, operational_system}
{rank=same; sys_req_models, integrated_system}
{rank=same; arch_models, subsystems}
{rank=same; comp_design_models, components}
{rank=same; unit_design_models, units}
}
I have used the following graph for requirements and tests specified in DO-178C.
digraph V_Cycle {
ranksep=0.3;
graph [fontname = "Handlee"];
node [fontname = "Handlee"];
edge [fontname = "Handlee"];
bgcolor=transparent;
/* ==== NODES === */
// Create hidden nodes to lower derived req
hid_sys_hl [style="invis"];
hid_hl_ll [style="invis"];
hid_ll_code [style="invis"];
hid_sr_hsi[style="invis"];
hid_req_tests[style="invis"];
// Requirements
node [color="#FFB71B", shape=note];
sys_req[label="System Requirements"];
hlr[label="High-Level\nSW Requirements"];
d_hlr[label="Derived\nHigh-Level Req.", style="dashed"];
llr[label="Low-Level\nSW Requirements"];
d_llr[label="Derived\nLow-Level Req.", style="dashed"];
// Code
node [color="#FFB71B", shape=component];
code;
// Tests
node [color="#000000", shape=box];
hsi_tests[label="Hardware/Software\nIntegration Tests"];
si_tests[label="Software\nIntegration Tests"];
ll_tests[label="Low-Level\n(Unit) Tests"];
/* ==== EDEGES === */
// Hidden to create intermediate level for derived req
hlr:sw -> hid_hl_ll:ne -> llr:sw[style="invis"];
llr:sw -> hid_ll_code:ne -> code:w[style="invis"];
{rank=same; d_hlr, hid_hl_ll}
{rank=same; d_llr, hid_ll_code}
// Requirements
edge[splines="ortho"];
sys_req:s -> hlr:w[weight=10];
hlr:s -> llr:w[weight=10];
hlr:s -> d_hlr:w[splines="spline",style="dashed", weight=5];
llr:s -> code:w[weight=10];
llr:s -> d_llr:w[splines="spline",style="dashed", weight=5];
// Tests
hsi_tests:s -> si_tests:e[dir="back", weight=10];
si_tests:s -> ll_tests:e[dir="back", weight=10];
// REQ & CODE -- TESTS
edge[splines="spline",color="#C89211", dir="back"];
{rank=same; hid_sys_hl, hid_sr_hsi}
hid_sys_hl -> hid_sr_hsi -> hsi_tests[style="invis"];
{rank=same; d_hlr, hid_req_tests}
llr -> d_hlr -> hid_req_tests -> ll_tests[style="invis"];
{rank=same; sys_req, hsi_tests}
sys_req -> hsi_tests;
{rank=same; hlr, si_tests}
hlr -> si_tests;
d_hlr:ne -> si_tests:sw;
{rank=same; llr, ll_tests}
llr -> ll_tests;
d_llr:ne -> ll_tests:s;
}
When using https://sketchviz.com/, the rendering is the following:
I am trying to avoid the crossing of the lines between 20->40 and 30->70. Does anyone know how to do this? I am using single points to straighten out the edges but I would have expected the rendering engine to avoid these edges to overlap. Here is my dot code:
digraph {
graph [splines="ortho", nodesep = "1", overlap = false];
node [shape=rectangle, color=lightgrey, style=filled ];
10
20
30
40
50
60
70
80
90
node[shape=none, width=0, height=0 label=""];
edge[dir=none];
{rank=same;
p1->10
10->p2
}
p1->20
p2->30
{rank=same;
p3->40
40->p4
}
p3->50
p4->60
{rank=same;
p5->70
70->p6
}
p5->80
p6->90
20->40
30->70
}
I wanted to post an image, but stackoverflow does not allow me to do this... You can see what I mean when you copy the code into: http://stamm-wilbrandt.de/GraphvizFiddle/
I really appreciate your help on this!
You could give graphviz a hint by adding an invisible edge between p4 an dp5:
{
rank=same;
p3 -> 40;
40 -> p4;
p4 -> p5 [style=invis]; // new invisible edge
p5 -> 70;
70 -> p6;
}
If you are not able to add invisible edges (dynamic graph generation), make sure nodes which are part of a subgraph do appear first within the subgraph, and therefore avoid upfront node definitions.
In this example, I removed the node definitions in the beginning of the script and inlined the style of the elbow-joint nodes.
Here's the GraphvizFiddle
digraph {
graph [splines="ortho", nodesep = "1", overlap = false];
node [shape=rectangle, color=lightgrey, style=filled ];
//node[shape=none, width=0, height=0, label=""];
edge[dir=none];
{
rank=same;
p1[shape=none, width=0, height=0, label=""];
p2[shape=none, width=0, height=0, label=""];
p1->10
10->p2
}
p1->20
p2->30
{
rank=same;
p3[shape=none, width=0, height=0, label=""];
p4[shape=none, width=0, height=0, label=""];
p3->40
40->p4
}
p3->50
p4->60
{
rank=same;
p5[shape=none, width=0, height=0, label=""];
p6[shape=none, width=0, height=0, label=""];
p5->70
70->p6
}
p5->80
p6->90
20->40
30->70
}