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:
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.
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
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
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