Creating Straight Edges in Graphviz - graphviz

I want to create a flowchart (similar to Visio) using Graphviz. Here is a sample digraph.
digraph start_up {
node [style = rounded];
node [shape = rect] start end;
node [style = ""];
node [shape = diamond] "USB\nCommand\nArrived";
start -> "Initialize\nCode";
"Initialize\nCode" -> "USB\nCommand\nArrived";
"USB\nCommand\nArrived" -> "USB\nCommand\nArrived" [label="No" tailport=w headport=n];
"USB\nCommand\nArrived" -> "Has USB 3.0\nInterface Been\nSelected" [label = "Yes"];
"Has USB 3.0\nInterface Been\nSelected" -> end
}
The problem is when I render this in Graphviz the line created by "USB\nCommand\nArrived" -> "USB\nCommand\nArrived" [label="No" tailport=w headport=n];
looks pretty ugly. I wouldn't mind curved lines, but this line looks deformed. You can see what Graphviz creates here
Is there a way to make this look better?

I think it's best to learn dot by example. Just read my comments and I'll be glad to answer if anything is unclear.
As a side node:
While graphviz is great for generating graphs for large datasets, it is less awesome for creating things like ER diagrams, flow-chars and sequence diagrams. It's possible and relatively straight forward, but the amount of time you have to put down to make something come out right is often unjustified because you could achieve the same thing with a Wsywig-GUI modeling tool in a fraction of the time. However, the time you spend doing that will help you towards learning the syntax and properties of the language which really comes in handy when you need to visualize some large or complex problem (where GUI modeling tools would be useless).
digraph start_up {
{
/* fake levels (level0 -> level1) and support nodes
*
* graphviz to charts is what latex is to documents,
* sometimes you'll have to fight it.
* This is typically done by defining levels and connection points that
* don't really have anything to do with your graph, but are used to
* force the graph to appear in a certain way.
*/
node [shape=none, /*label="."*/]; l1a; l2a; l3a; l4a; l5a; l6a;
node [shape=square label="no"]; l20a;
}
{ /* connectiong point for the no arrow above "arrived" */
node [width=0 shape=point label=""];
d1; no;
}
node [style = rounded];
node [shape = rect] start end;
node [style = ""];
node [shape = diamond]; {
node [label="USB\nCommand\nArrived"]; arrived;
node [label="Has USB 3.0\nInterface Been\nSelected"]; selected;
node [label="Initialize\nCode"]; init;
}
start -> init;
/*init -> arrived; */
init -> d1 [arrowhead=none];
d1 -> arrived;
/*
* tricky part:
* since nodes in a digrap go either from top to bottom or left to right, we
* can usually not connect (->) two nodes and have them appear on the same
* level unless the connection is specified within a block that has the
* parameter `rank' set to `same'
*/
l20a->no [arrowhead=none];
{ rank=same; no -> arrived [dir=back arrowtail=none]; }
{ rank=same; l20a -> d1; }
/*arrived -> arrived;*/ /* [label="No" tailport=w headport=n]; */
arrived -> selected [label = "Yes"];
selected -> end
/* just to demonstrate */
l1a-> l2a-> l3a-> l4a-> l5a-> l6a;
}

Related

Graphviz not rendering labels nor encompassing rectangles

I recently started using Graphviz.
I'm working on a graph with labels, but they're not showing up. Neither are my sub-groups being surrounded by an encompassing rectangle.
Here's my code:
digraph system {
subgraph Machine_001 {
label = "Machine_001";
subgraph Machine_001_Service_001 {
label = "Service_001 on Machine_001";
node [shape=record];
Machine_001_PORT_10 [label = "Port 10"];
Machine_001_PORT_11 [label = "Port 11"];
Machine_001_PORT_12 [label = "Port 12"];
Machine_001_PORT_13 [label = "Port 13"];
{rank=same Machine_001_PORT_10 Machine_001_PORT_11 Machine_001_PORT_12 Machine_001_PORT_13}
Machine_001_PORT_10 -> Machine_001_PORT_11;
Machine_001_PORT_12;
Machine_001_PORT_13;
}
}
subgraph Machine_002 {
label = "Machine_002";
subgraph Machine_002_Service_001 {
label = "Service_001 on Machine_002";
node [shape=record];
Machine_002_PORT_50 [label = "Port 50"];
Machine_001_PORT_11 -> Machine_002_PORT_50;
}
}
}
Using http://www.webgraphviz.com/ to render it, I would expect labels, but those are not shown.
On the other hand, an example like this does show labels and an encompassing rectangle:
digraph D {
subgraph cluster_p {
label = "Parent";
subgraph cluster_c1 {
label = "Child one";
a;
subgraph cluster_gc_1 {
label = "Grand-Child one";
b;
}
subgraph cluster_gc_2 {
label = "Grand-Child two";
c;
d;
}
}
subgraph cluster_c2 {
label = "Child two";
e;
}
}
}
Frankly, I don't see what the problem is. I gave it a label, and I nested it. Which is exactly what the working example does.
What am I missing?
Looks like placing "cluster_" in front of the names in the subgraphs solves the problem, so the following is not 100% an answer as I think, my interpretation of the definitions, it should be possible.
In https://www.graphviz.org/doc/info/lang.html some definitions are given (left out some parts by me!):
subgraph : [ subgraph [ ID ] ] '{' stmt_list '}'
An ID is one of the following:
Any string of alphabetic ([a-zA-Z\200-\377]) characters, underscores ('_') or digits ([0-9]), not beginning with a digit;
The third role for subgraphs directly involves how the graph will be laid out by certain layout engines. If the name of the subgraph begins with cluster, Graphviz notes the subgraph as a special cluster subgraph. If supported, the layout engine will do the layout so that the nodes belonging to the cluster are drawn together, with the entire drawing of the cluster contained within a bounding rectangle. Note that, for good and bad, cluster subgraphs are not part of the DOT language, but solely a syntactic convention adhered to by certain of the layout engines.
So it looks like that the names of the subgraphs are a bit limited in this case.
Maybe that and issue at https://gitlab.com/graphviz/graphviz/issues can help

Align nodes in a Graphviz directed graph

I have the following Graphviz code:
digraph {
Technique [shape = box];
Path [shape = box];
KnowledgeObservation [shape = box, label = "Knowledge\nObservation"];
ManagementIntervention [shape = box, label = "Management\nIntervention"];
ResultsModification [shape = box, label = "Results\nModification"];
SharedCode [label = "Shared Code"];
MediatedRelationship [label = "Mediated Relationship"];
Art -> Technique;
Therapy -> Path;
{Technique Path} -> KnowledgeObservation -> ManagementIntervention -> ResultsModification;
{MediatedRelationship SharedCode} -> {KnowledgeObservation ResultsModification}
subgraph {
rank = same
Technique -> Path [dir = none]
}
subgraph {
rank = same
SharedCode
ManagementIntervention
MediatedRelationship
}
}
It currently produces the following output:
How can I vertically align "Management Intervention" with both "Knowledge Observation" and "Results Modification"?
"Shared Code" should be moved to the left of "Management Intervention".
"Mediated Relationship" should be moved to the right of "Management Intervention".
"Shared Code", "Management Intervention" and "Mediated Relationship" should stay horizontally aligned.
How can I accomplish this?
This can be achieved without subgraphs; the most important modification is the line
{ rank = same; SharedCode -> ManagementIntervention -> MediatedRelationship[ style = invis ] }
which keeps the three nodes not only on the right level, but also within the desired order.
Altogether, this code here
digraph
{
// node definition
Art Therapy;
Technique[ shape = box ];
Path[ shape = box ];
KnowledgeObservation[ shape = box, label = "Knowledge\nObservation" ];
ManagementIntervention[ shape = box, label = "Management\nIntervention" ];
ResultsModification[ shape = box, label = "Results\nModification" ];
SharedCode[ label = "Shared Code" ];
MediatedRelationship[ label = "Mediated Relationship" ];
// edges
Art -> Technique;
Therapy -> Path;
{ rank = same; Technique -> Path [dir = none] }
{ Technique Path} -> KnowledgeObservation -> ManagementIntervention -> ResultsModification;
{ rank = same; SharedCode -> ManagementIntervention -> MediatedRelationship[ style = invis ] }
{ MediatedRelationship SharedCode } -> { KnowledgeObservation ResultsModification }
}
gives you
which is, in my understanding, what you are looking for.
Still I would recommend to replace the last line of code with these three
KnowledgeObservation -> { SharedCode MediatedRelationship }[ dir = back ];
SharedCode -> ResultsModification;
MediatedRelationship -> ResultsModification;
Reason is that once your graph gets more complicated, graphviz will recognize and maintain the hierarchical relationships, rather than interpreting ambiguous instructions in surprising ways.
How can I vertically align "Management Intervention" with both "Knowledge Observation" and "Results Modification"?
This can be achieved with increasing the weight of the edge. Edges with higher weight tend to be straighter and shorter than with the lower.
"Mediated Relationship" should be moved to the right of "Management Intervention".
You can control this with the order in which the nodes are defined. If you define "Management Intervention" before the "Shared Code", it (MI) will be drawn first, i. e., to the left of the SI.
"Shared Code", "Management Intervention" and "Mediated Relationship" should stay horizontally aligned.
You did it right, using the rank=same subgraph attribute. Though I would put the subgraph already in the moment of node definitions. This will shorten the source size and limit the rank specification to the place where the nodes are defined, which is good for readability (everything stated in one place).
Your modified example:
digraph {
Technique [shape = box];
Path [shape = box];
KnowledgeObservation [shape = box, label = "Knowledge\nObservation"];
ResultsModification [shape = box, label = "Results\nModification"];
subgraph {
rank=same
ManagementIntervention [shape = box, label = "Management\nIntervention"];
MediatedRelationship [label = "Mediated Relationship"];
SharedCode [label = "Shared Code"];
}
Art -> Technique;
Therapy -> Path;
{Technique Path} -> KnowledgeObservation
KnowledgeObservation -> ManagementIntervention -> ResultsModification [weight=3]
{MediatedRelationship SharedCode} -> {KnowledgeObservation ResultsModification}
subgraph {
rank = same
Technique -> Path [dir = none]
}
}
Result:

Nested directed subgraphs

I'm trying to obtain nested subgraphs in graphviz.
Graphviz version is 2.38.0 (20140413.2041)
Here is the code:
digraph G {
subgraph cluster_win {
style=filled;
color=lightgrey;
label = "Windows"
subgraph extra_enabled {
fillcolor = "#EDF1F2";
color = "#028d35";
label="Subdirectory extra included";
node [style=filled,color=white];
config_debug1 [label = "Configure Debug"];
config_release1 [label = "Configure Release"];
build_debug1 [label = "Build"];
build_release1 [label = "Build"];
config_debug1 -> build_debug1;
config_release1 -> build_release1;
shape=rect;
style=rounded;
}
subgraph extra_disabled {
label = "Subdirectory extra excluded";
config_debug2 [label = "Configure Debug"];
config_release2 [label = "Configure Release"];
build_debug2 [label = "Build"];
build_release2 [label = "Build"];
config_debug2 -> build_debug2;
config_release2 -> build_release2;
}
checkout [style=filled, color=white];
checkout -> extra_enabled;
checkout -> extra_disabled;
}
start -> checkout;
start [label="git push"; shape=Mdiamond];
}
And this is the result.
Graphviz draws two ordinary nodes "extra_enabled" and "extra_disabled". However, I want them to be subgraphs, containing nodes "Configure Release", "Configure Debug", "Build" and another "Build".
How can I fix it?
You need to do two things:
Connect nodes only, you cannot connect to a cluster
Cluster names need to be prefixed by cluster_
Applying this to your code
digraph G {
subgraph cluster_win {
style=filled;
color=lightgrey;
label = "Windows "
subgraph cluster_extra_enabled {
fillcolor = "#EDF1F2";
color = "#028d35";
label="Subdirectory extra included";
node [style=filled,color=white];
config_debug1 [label = "Configure Debug"];
config_release1 [label = "Configure Release"];
build_debug1 [label = "Build"];
build_release1 [label = "Build"];
config_debug1 -> build_debug1;
config_release1 -> build_release1;
shape=rect;
style=rounded;
}
subgraph cluster_extra_disabled {
label = "Subdirectory extra excluded";
config_debug2 [label = "Configure Debug"];
config_release2 [label = "Configure Release"];
build_debug2 [label = "Build"];
build_release2 [label = "Build"];
config_debug2 -> build_debug2;
config_release2 -> build_release2;
}
checkout [style=filled, color=white];
checkout -> config_debug1;
checkout -> config_release2;
}
start -> checkout;
start [label="git push"; shape=Mdiamond];
}
I get
which is probably close to what you want. Note that I have added a few spaces to the label "Windows " to get it out of the way of the arrow. You could also use labeljust. There are also ways to make the edge end at the boundary of the cluster, but that would have needed a lot more editing on my part which I was not sure you want it.
I just wanted to append to the answer that vaettchen added. While it is correct that you cannot directly connect edges to clusters, edges must travel between nodes, there is a way to do so visually with lhead and ltail.
You can do the following:
node1 -> node2 [lhead=cluster_name_1, ltail=cluster_name_2]
Which will cut the connectors off at the limit of the cluster to connect clusters, this is just visual and is logged as a node connection, but it is a nicer way to visually display connections between whole clusters.

how do I add arbitrary, positioned, text/symbols to a graphviz diagram?

I would like to have an "implies" arrow between the two graphs here
digraph G {
subgraph case {
x;
left [shape=diamond];
right [shape=diamond];
left -> x;
right -> x;
}
subgraph case_ {
x_;
left_ [shape=diamond];
right_ [shape=diamond];
left_ -> x_;
right_ -> x_;
}
}
Trying to GraphViz - How to connect subgraphs? doesn't work because I'm using the dot algorithm. But I don't need anything too fancy since I have a bunch of diagrams like this where there is a "before" and "after" state and I want to put some visual indicator.

How do I stop GraphViz dot making my clusters more compact?

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;
}
}

Resources