Ordering flowchart in graphviz - r

The graph I'd like to produce is a something like this a left-to-right flowchart with a main process at the top, and a series of groupings of stuff below that feed in and out at various points like this:
(though this is a dummy example and I want lots of stuff coming in and out from the top code box, which is why a horizontal layout works better than the default
The problem is that this is made in powerpoint...
I can get something close with this:
digraph example {
graph [
rankdir = LR
]
subgraph cluster_code {
label = "code";
A;
B;
C;
D;
}
subgraph cluster_data {
label = "data";
data_1;
data_2;
}
subgraph cluster_source {
label = "source"
source_1;
source_2
}
A -> B
B -> C
C -> D
data_1 -> A
data_2 -> B
A -> output_1
output_1 -> C
source_1 -> data_1
source_2 -> data_2
#{rank = same; source_2; data_2; A}
}
But if I try to bring the source and data clusters underneath the code cluster using {rank = same; source_2; data_2; A} (this is hashed out above, and I don't repeat the whole code for brevity of the post), I then A, data_2 and source_2 drop out of the box. I think this is something do do with rank and clusters not playing nicely together.
Any hints on getting something like the first graph above?
Am running graphviz via R/Rstudio and DiagrammeR.

It seems that you want to change "rankdir" in the middle of the graph. Quite reasonable, but Graphviz doesn't support it. Here is your graph, using default rankdir and the not-that-well-documented ability to effectively change rankdir by using rank=same in a subgraph. It also reverses edge arrowhead direction - a kludge, but it works.
digraph example {
node [width=1.5]
subgraph cluster_code {
label = "code";
{rank=same
A -> B -> C -> D
}
}
subgraph cluster_data {
label = "data";
data_1;
data_2;
}
subgraph cluster_source {
label = "source"
source_1;
source_2
}
A -> output_1
output_1 -> C
edge[dir=back minlen=2] // minlen makes (rank) space
A -> data_1 // -> A
A -> data_2 // -> A
edge[dir=back minlen=1]
data_1 -> source_1 // -> data_1
data_2 -> source_2 // -> data_2
}
Giving this:

Related

create fixed edge directional graphs in dot format with graphviz

Is there anyway to create defined fixed edges directional graphs using dot notation? the following dot notation (fig 2) generates an automated edges that are curved. It doesnt have notations which will generate directions with straight edges (fig 1). Been on hours trying to find anything close, any hints will be great. thank you.
# fig 1
box A --- box B
|. \
|. \
box C. \
box D
# fig 2
digraph G {
node [shape=record];
rankdir="BT"
a -> b [color = red][arrowhead = diamond][taillabel = "tail"]
b -> c [shape = box]
c -> a
}
Not sure what a fixed edge is, but if you don't want splines for edges, look at the splines attribute (https://graphviz.org/docs/attrs/splines/).
Here is you graph with splines=false. You can also try splines=polyline.
You might also connect the edges to specific ports on one or both of the nodes (https://graphviz.org/docs/attr-types/portPos/).
# fig 2
digraph G {
node [shape=record];
// see https://graphviz.org/docs/attrs/splines/
// also look at ports https://graphviz.org/docs/attr-types/portPos/
splines=false // or try splines=polyline
rankdir="BT"
a -> b [color = red][arrowhead = diamond][taillabel = "tail"]
b -> c [shape = box]
c -> a
}
Giving:

R DiagrammeR Mermaid for Function Maps

How do you produce the following plot using the R function mermaid from the package DiagrammeR?
EDIT:
Let's just say we drop the labels "Input" and "Output" along with the red circles. The following is a minimal code for a start in R.
DiagrammeR::mermaid("
graph LR
a --> x
b --> y
c --> y
d --> z
classDef firstSet fill:#F8CECC
class a,b,c,d firstSet
")
whose output looks like this:
mermaid-mapping
Specific questions:
How does one make the edges straight and not folded?
How does one include the red circles?
Try this code below.
It's not perfect (today is the 3rd day that I started learning Mermaid.js) but it has similar elements like your example:
library(DiagrammeR)
grViz("
digraph {
graph[rankdir = LR, fontsize = 30]
edge [color = 'blue', penwidth = 3.5]
node[color = 'white', fontsize = 25]
subgraph cluster_1 {
label = 'Input'
color = 'red'
node [shape = circle]
a; b; c; d}
subgraph cluster_2 {
label = 'Output'
color = 'red'
node [shape = circle]
x; y; z}
a -> x
b -> y
c -> y
d -> z
}
")
The final outcome looks like this. I may revisit this answer later once I am more proficient.

Add round feedback arrow to horizontal graph in Graphviz / DiagrammR

I like to add a feedback arrow to a Graphviz graph, where the ordinary "flow" remains horizontal, but the feedback should be round, like the manually added blue arrow below.
Here is what I tried so far. I use the DiagrammR package for the R language but a suggestion for plain or python Graphviz or would of course also be helpful.
library("DiagrammeR")
grViz("digraph feedback {
graph [rankdir = 'LR']
node [shape = box]
Population
node [shape = circle]
Source Sink
node [shape = none]
Source -> Growth -> Population -> Death -> Sink
Population -> Growth [constraint = false]
Death -> Population [constraint = false]
}")
You can try using the headport and tailport options and indicate "north" for both of these (for Population and Growth).
The headport is the cardinal direction for where the arrowhead meets the node.
The tailport is the cardinal direction for where the tail is emitted from the node.
library("DiagrammeR")
grViz("digraph feedback {
graph [rankdir = 'LR']
node [shape = box]
Population
node [shape = circle]
Source Sink
node [shape = none]
Source -> Growth -> Population -> Death -> Sink
Population -> Growth [tailport = 'n', headport = 'n', constraint = false]
}")
Output

Detect cycle in undirected graph in Ocaml

Does someone has idea how to detect if there is a cycle in undirected graph in OCaml?
Here's the type I'm using for graph:
type 'a graph = { nodes : 'a list; edges : ('a * 'a * int) list }
And for example, I would like to check if this graph contains cycles:
let graph = { nodes = ['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'j';];
edges = [('c', 'j', 9); ('d', 'e', 8); ('a', 'b', 8); ('b', 'c', 7); ('f', 'g', 6); ('b', 'h', 4); ('a', 'd', 4); ('g', 'h', 2); ('b', 'f', 2); ('e', 'g', 1)]}
In both directed and undirected graphs, the presence of a cycle is detected using depth first search. Roughly, you traverse a graph and if a walk contains repetitive nodes, then there is a cycle.
Commonly, an additional data structure is employed for labeling already visited nodes. For example, we can employ a set data structure (using vanilla OCaml),
module Nodes = Set.Make(struct
type t = int
let compare = compare
end)
let dfs {edges} f x =
let rec loop visited x = function
| [] -> x
| (src,dst,data) :: rest ->
let x = f src data in
let visited = Nodes.add src visited in
if Nodes.mem dst visited
then loop visited x rest
else ... in
loop Nodes.empty x edges
You can also use an imperative hash table instead of a pure functional set. There is also an algorithm, called Iterative Deepening DFS, that can traverse cyclic graphs without labeling all visited nodes, which is useful when your graph is huge (and won't fit into the memory).
Unless you're doing this for an exercise, I would suggest you using some existing Graph library in OCaml, e.g., OCamlgraph (docs) or Graphlib (docs).
It is also possible to avoid visiting the same edge twice by removing it from the list of available edges; assuming order does not matter in among edges, you can remove an edge as follows:
let edges_remove_edge edges edge =
let (src, dst, _) = edge in
let rec iter edges res = match edges with
| [] -> res
| ((s, d, _) as e)::edges ->
if (s = src && d = dst) then
res # edges
else
iter edges (e::res)
in iter edges []
Removing an edge from a graph is then done by building a new graph that shares data with the previous graph, but with a modified list of edges:
let graph_remove_edge graph edge =
{ nodes = graph.nodes;
edges = edges_remove_edge graph.edges edge }
You can then transform the graph along the recursive calls of your graph traversal; the example does nothing interesting here, it is just to demonstrate the structure:
let choose_edge graph = match graph.edges with
| [] -> None
| e::_ -> Some e;;
let rec visit graph = match (choose_edge graph) with
| None -> graph
| Some e -> visit (graph_remove_edge graph e);;
# visit graph;;
- : char graph =
{nodes = ['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'j']; edges = []}
Or, you keep track of the current graph with a ref:
let visit2 graph =
let g = ref graph in
let rec v () = match (choose_edge !g) with
| None -> ()
| Some e -> begin g := graph_remove_edge !g e; v () end
in v(); !g
I managed to detect cycle by using union-find data structure.
A structure to represent a subset for union-find:
let create n =
{parent = Array.init n (fun i -> i);
rank = Array.init n (fun i -> 0)}
A utility function to find set of an element. It uses path compression technique:
let rec find uf i =
let pi = uf.parent.(i) in
if pi == i then
i
else begin
let ci = find uf pi in
uf.parent.(i) <- ci;
ci
end
A function that does union of two sets of x and y. It uses union by rank:
let union ({ parent = p; rank = r } as uf) x y =
let cx = find uf x in
let cy = find uf y in
if cx == cy then raise (Failure "Cycle detected") else begin
if r.(cx) > r.(cy) then
p.(cy) <- cx
else if r.(cx) < r.(cy) then
p.(cx) <- cy
else begin
r.(cx) <- r.(cx) + 1;
p.(cy) <- cx
end
end
I created function for checking if there is a cycle.
let thereIsCycle c1 c2 g subset =
let isCycle = try Some (union subset (findIndex c1 g.nodes) (findIndex c2 g.nodes)) with _ -> None in
match isCycle with
| Some isCycle -> false
| None -> true
let rec findIndex x lst =
match lst with
| [] -> raise (Failure "Not Found")
| h :: t -> if x = h then 0 else 1 + findIndex x t

How to specify in DOT file that edges go upwards

I want to render a directed graph like:
A
^ ^
/ \
/ \
B C
But no matter what order I put the statements in, dot insists on generating an image that looks like:
B C
\ /
\ /
v v
A
I've tried specifying the port, but then the edges just wrap around. It doesn't change the position of the nodes.
The solution is rankdir
digraph G {
rankdir="BT"
B->A
C->A
}
rankdir is the solution if you want to build your whole graph from bottom to top. A more flexible approach is to just tell the edges to point backward:
digraph G
{
A -> B[ dir = back ];
A -> C[ dir = back ];
}
yields
You could also write
A -> { B C }[ dir = back ];
Or you could give the general instructions for all edges defined after this instruction to point backward:
edge[ dir = back ];
This can be undone by
edge[ dir = forw ];
Hence,
digraph G
{
edge[ dir = back ];
A -> B;
A -> C;
edge[ dir = forw ];
{ B C } -> D;
}
yields

Resources