I am trying to draw a longitudinal model as attached. I tried in many ways, but did not work. Could some one help.
Regards,
I am trying to draw a longitudinal model as attached. I tried in many ways, but did not work. Could some one help.
Regards,
Please attach your current “best try”. It will help with recreating all the edges.
Hi,
Thanks a lot for your help. I attached the file so far.
Regards,
Holendro
(Attachment med.R is missing)
Here is the code
med_data ←
data.frame(
lab_wd06 = “WD06”,
lab_wd08 = “WD08”,
lab_wd10 = “WD10”,
lab_wd12 = “WD12”,
lab_wd14 = “WD14”,
lab_wd16 = “WD16”,
lab_dp06 = “DP06”,
lab_dp08 = “DP08”,
lab_dp10 = “DP10”,
lab_dp12 = “DP12”,
lab_dp14 = “DP14”,
lab_dp16 = “DP16”
)
med_diagram ← function(data, height = .8, width = 0.8, graph_label = NA, node_text_size = 10, edge_text_size = 3, color = “black”, ranksep = .3, minlen = 2.8){
require(glue)
require(DiagrammeR)
data$height ← height # node height
data$width ← width # node width
data$color ← color # node + edge border color
data$ranksep ← ranksep # separation btwn mediator row and x->y row
data$minlen ← minlen # minimum edge length
data$node_text_size ← node_text_size
data$edge_text_size ← edge_text_size
data$graph_label ← ifelse(is.na(graph_label), “”, paste0(“label = '”, graph_label, “’”))
diagram_out ← glue::glue_data(data,
"digraph flowchart {
fontname = Helvetica
<<graph_label>>
graph [ranksep = <>, rankdir = LR]
# node definitions with substituted label text
node [fontname = Helvetica, shape = circle, fixedsize = TRUE, width = <<width>>, height = <<height>>, fontsize = <<node_text_size>>, color = <<color>>]
wd0606 [pos = '-1,1!', label = '<<lab_wd06>>']
wd0808 [pos = '1,1!', label = '<<lab_wd08>>']
wd1010 [pos = '3,1!', label = '<<lab_wd10>>']
wd1212 [pos = '5,1!', label = '<<lab_wd12>>']
wd1414 [pos = '7,1!', label = '<<lab_wd14>>']
wd1616 [pos = '9,1!', label = '<<lab_wd16>>']
dp0606 [pos = '-1,-1!', label = '<<lab_dp06>>']
dp0808 [pos = '1,-1!', label = '<<lab_dp08>>']
dp1010 [pos = '3,-1!', label = '<<lab_dp10>>']
dp1212 [pos = '5,-1!', label = '<<lab_dp12>>']
dp1414 [pos = '7,-1!', label = '<<lab_dp14>>']
dp1616 [pos = '9,-1!', label = '<<lab_dp16>>']
# edge definitions with the node IDs
edge [minlen = <<minlen>>, fontname = Helvetica, fontsize = <<edge_text_size>>, color = <<color>>, arrow = vee, arrowhead = vee, arrowtail = vee, arrowsize = 0.2]
wd0606 -> wd0808 [color = forestgreen, penwidth = 0.5];
wd0808 -> wd1010 [color = purple, penwidth = 0.5];
wd1010 -> wd1212 [color = purple, penwidth = 0.5];
wd1212 -> wd1414 [color = purple, penwidth = 0.5];
wd1616 -> wd1414 [color = purple, penwidth = 0.5];
dp0606 -> dp0808 [color = purple, penwidth = 0.5];
dp0808 -> dp1010 [color = purple, penwidth = 0.5];
dp1010 -> dp1212 [color = forestgreen, penwidth = 0.5];
dp1212 -> dp1414 [color = purple, penwidth = 0.5];
dp1414 -> dp1616 [color = forestgreen, penwidth = 0.5];
{rank = same; wd0606 -> dp0606[penwidth = 0.5]};
{rank = same; wd0808 -> dp0808[penwidth = 0.5]};
{rank = same; wd1010 -> dp1010[penwidth = 0.5]};
{rank = same; wd1212 -> dp1212[penwidth = 0.5]};
{rank = same; wd1414 -> dp1414[penwidth = 0.5]};
{rank = same; wd1616 -> dp1616[penwidth = 0.5]};
{wd0606 -> dp0808[penwidth = 0.5]};
{wd0606 -> dp1010[penwidth = 0.5]};
{wd0606 -> dp1212[penwidth = 0.5]};
{wd0606 -> dp1414[penwidth = 0.5]};
{wd0606 -> dp1616[penwidth = 0.5]};
{wd0808 -> dp1010[penwidth = 0.5]};
{wd0808 -> dp1212[penwidth = 0.5]};
{wd0808 -> dp1414[penwidth = 0.5]};
{wd0808 -> dp1616[penwidth = 0.5]};
{wd1010 -> dp1212[penwidth = 0.5]};
{wd1010 -> dp1414[penwidth = 0.5]};
{wd1010 -> dp1616[penwidth = 0.5]};
{wd1212 -> dp1414[penwidth = 0.5]};
{wd1212 -> dp1616[penwidth = 0.5]};
{wd1414 -> dp1616[penwidth = 0.5]};
{dp0606 -> wd0808[penwidth = 0.5]};
{dp0606 -> wd1010[penwidth = 0.5]};
{dp0606 -> wd1212[penwidth = 0.5]};
{dp0606 -> wd1414[penwidth = 0.5]};
{dp0808 -> wd1010[penwidth = 0.5]};
{dp0808 -> wd1212[penwidth = 0.5]};
{dp0808 -> wd1414[penwidth = 0.5]};
{dp1010 -> wd1212[penwidth = 0.5]};
{dp1010 -> wd1414[penwidth = 0.5]};
{dp1212 -> wd1414[penwidth = 0.5]};
{dp1212 -> wd1616[penwidth = 0.5]};
{wd0606 -> wd1010[penwidth = 0.5]};
{wd0606 -> wd1212[penwidth = 0.5]};
{wd0606 -> wd1414[penwidth = 0.5]};
{wd1616 -> wd1212[penwidth = 0.5]};
{wd1616 -> wd1010[penwidth = 0.5]};
{wd1616 -> wd0808[penwidth = 0.5]};
{wd1616 -> wd0606[penwidth = 0.5]};
{dp0606 -> dp1010[penwidth = 0.5]};
{dp0606 -> dp1212[penwidth = 0.5]};
{dp0606 -> dp1414[penwidth = 0.5]};
{dp0606 -> dp1616[penwidth = 0.5]};
{dp0808 -> dp1616[penwidth = 0.5]};
{dp1010 -> dp1616[penwidth = 0.5]};
{dp1212 -> dp1616[penwidth = 0.5]};
{ rank = same; wd0606; dp0606 }
{ rank = same; wd0808; dp0808 }
{ rank = same; wd1010; dp1010 }
{ rank = same; wd1212; dp1212 }
{ rank = same; wd1414; dp1414 }
{ rank = same; wd1616; dp1616 }
}
", .open = "<<", .close = ">>")
DiagrammeR::grViz(diagram_out)
}
med_diagram(med_data)
Regards
My monthly PSA: the forum supports code blocks with Graphviz syntax highlighting:
```dot
digraph {
like -> so[with="a label"];
}
```
which produces:
digraph {
like -> so[with="a label"];
}
Got the nodes positioned, but the edges are a challenge.
Hi,
Thanks a lot. Yes, this is for a longitudinal data i.e. over time. Here, I am just showing for 6 time points. It will be nice if somehow control for edges. Once again thanks a lot.
Basically I did in R using the package DiagrammeR which uses internally graphViz. If it is not required I guess it will be ok.
I tried a simplified version of your first picture.
I didn’t check deeply if all the edges are there in the right direction, but it will not be hard to rectify them, I think.
If someone could explain how to get better results with the splines, it would be great !
I am really new to Graphviz so I am not even sure if is the right strategy.
What I so far understood is that when you want a better control to splines trajectory the neato layout is better because you can edit the pos attribute that is valid on Edges and Nodes for positioning nodes, or spline control points.
Here an interesting post about splines on this forum by scnorth
It says about the spline fitter :
There’s a top level, that knows about the graph layout. It computes a “feasible region” or constraint polygon for the spline, which is a simple polygon that must contain the endpoints. In dot, the polygon is obtained by first computing a “box path” (a list of boxes that touch sequentially on sides but the direction can change) because it is easy to generate boxes from the levels of the ranked graph. Then there is a phase to walk the boxes and make them into a simple polygon
I am wondering if it’s possible to specify this polygon…
anyway here is the code :
digraph {
concentrate=true
ranksep =1.7 nodesep=2
edge[arrowsize=0.5]
node[shape=“circle”]
a b c d e f
g h i j k l
{a b c d e f rank=“same”}
{g h i j k l rank=“same”}
a → g
b → h
c → i
d → j
e → k
f → l
edge[constraint=false]
a → b → c → d → e
g → h → i → j → k → l
f → e
a → h
a → i
a → j
a → k
a → l
b → i
b → j
b → k
b → l
c → j
c → k
c → l
a → c
a → d
a → e
f → d
f → c
f → b
f → a
g → e
h → e
i → e
j → e
e → l
i → d
g → b
g → c
d → k
d → l
g → d
g:se → i:s
g:se → j:s
g:se → k:s
g:se → l:s
h → c
h → d
h:s → l:s
i:s → l:s
j → l:s
}
Best I could do with Graphviz. I use dot to position the nodes, then neato -n to place the edges. Dot on its own did a terrible job with the edges.
These edges are still too close to the nodes and to each other, but …
command: dot myfile -Tdot |neato -n -Tpng >myfile.png
digraph flowchart {
fontname = Helvetica
// graph [ rankdir = LR]
ranksep=1.5 // inches
nodesep=1
splines=true
# node definitions with substituted label text
node [fontname = Helvetica, shape = circle]
// remove pos attributes - dot ignores, anyway
{rank=same
wd0606 [ label = "lab_wd06" group=g1]
wd0808 [ label = "lab_wd08" group=g2]
wd1010 [ label = "lab_wd10" group=g3]
wd1212 [ label = "lab_wd12" group=g4]
wd1414 [ label = "lab_wd14" group=g5]
wd1616 [ label = "lab_wd16" group=g6]
}
{rank=same
dp0606 [label = "lab_dp06" group=g1]
dp0808 [label = "lab_dp08" group=g2]
dp1010 [label = "lab_dp10" group=g3]
dp1212 [label = "lab_dp12" group=g4]
dp1414 [label = "lab_dp14" group=g5]
dp1616 [label = "lab_dp16" group=g6]
}
// edge definitions with the node IDs
// edge [ fontname = Helvetica, arrow = vee, arrowhead = vee, arrowtail = vee, arrowsize = 0.2]
// penwidth is in points, .5 is too small??
wd0606 -> wd0808 [color = forestgreen, ]
wd0808 -> wd1010 [color = purple, ]
wd1010 -> wd1212 [color = purple, ]
wd1212 -> wd1414 [color = purple, ]
//wd1616 -> wd1414 [color = purple, ]
wd1414 -> wd1616 [color = purple, dir=back ]
dp0606 -> dp0808 [color = purple, ]
dp0808 -> dp1010 [color = purple, ]
dp1010 -> dp1212 [color = forestgreen, ]
dp1212 -> dp1414 [color = purple, ]
dp1414 -> dp1616 [color = forestgreen, ]
// curves, within same rank
// get dp-to-dp edges under the nodes - southern ports
dp0606:se -> dp1010:sw
dp0606:se -> dp1212:sw
dp0606:se -> dp1414:sw
dp0606:se -> dp1616:sw
dp0808:se -> dp1616:sw
dp1010:se -> dp1616:sw
dp1212:se -> dp1616:sw
wd0606 -> dp0606
wd0808 -> dp0808
wd1010 -> dp1010
wd1212 -> dp1212
wd1414 -> dp1414
wd1616 -> dp1616
wd0606 -> dp0808
wd0606 -> dp1010
wd0606 -> dp1212
wd0606 -> dp1414
wd0606 -> dp1616
wd0808 -> dp1010
wd0808 -> dp1212
wd0808 -> dp1414
wd0808 -> dp1616
wd1010 -> dp1212
wd1010 -> dp1414
wd1010 -> dp1616
wd1212 -> dp1414
wd1212 -> dp1616
wd1414 -> dp1616
dp0606 -> wd0808
dp0606 -> wd1010
dp0606 -> wd1212
dp0606 -> wd1414
dp0808 -> wd1010
dp0808 -> wd1212
dp0808 -> wd1414
dp1010 -> wd1212
dp1010 -> wd1414
dp1212 -> wd1414
dp1212 -> wd1616
wd0606 -> wd1010
wd0606 -> wd1212
wd0606 -> wd1414
/*
wd1616 -> wd1212
wd1616 -> wd1010
wd1616 -> wd0808
wd1616 -> wd0606
*/
// wd1616 was "incorrectly" positioned maybe because of backward edges
// so, rewrite as forward edges with backward arrows
wd1212 -> wd1616 [dir=back]
wd1010 -> wd1616 [dir=back]
wd0808 -> wd1616 [dir=back]
wd0606 -> wd1616 [dir=back]
}
Giving:
In comparison, here is an hour or two with the pikchr (Pikchr: Documentation) variant of the pic language:
## ``` pikchr
circlerad = .4
# first, position the nodes (and label and name them)
right
N_wd0606: circle "lab_wd06"
move right
N_wd0808: circle "lab_wd08"
move right
N_wd1010: circle "lab_wd10"
move right
N_wd1212: circle "lab_wd12"
move right
N_wd1414: circle "lab_wd14"
move right
N_wd1616: circle "lab_wd16"
move to N_wd0606.w
move down; move down; move down; move down
right
N_dp0606: circle "lab_dp06"
move right
N_dp0808: circle "lab_dp08"
move right
N_dp1010: circle "lab_dp10"
move right
N_dp1212: circle "lab_dp12"
move right
N_dp1414: circle "lab_dp14"
move right
N_dp1616: circle "lab_dp16"
# time to place edges
# chop is used to draw from edge-to-edge, not center-to-center
# straight edges are easy
# first straight, horizontal edges
arrow from N_wd0606 to N_wd0808 color forestgreen chop
arrow from N_wd0808 to N_wd1010 color purple chop
arrow from N_wd1010 to N_wd1212 color purple chop
arrow from N_wd1212 to N_wd1414 color purple chop
arrow from N_wd1616 to N_wd1414 color purple chop
arrow from N_dp0606 to N_dp0808 color purple chop
arrow from N_dp0808 to N_dp1010 color purple chop
arrow from N_dp1010 to N_dp1212 color forestgreen chop
arrow from N_dp1212 to N_dp1414 color purple chop
arrow from N_dp1414 to N_dp1616 color forestgreen chop
# now, straight, diagonal edges "rank-to-rank" (in dot-speak)
arrow from N_wd0606 to N_dp0606 chop
arrow from N_wd0808 to N_dp0808 chop
arrow from N_wd1010 to N_dp1010 chop
arrow from N_wd1212 to N_dp1212 chop
arrow from N_wd1414 to N_dp1414 chop
arrow from N_wd1616 to N_dp1616 chop
arrow from N_wd0606 to N_dp0808 chop
arrow from N_wd0606 to N_dp1010 chop
arrow from N_wd0606 to N_dp1212 chop
arrow from N_wd0606 to N_dp1414 chop
arrow from N_wd0606 to N_dp1616 chop
arrow from N_wd0808 to N_dp1010 chop
arrow from N_wd0808 to N_dp1212 chop
arrow from N_wd0808 to N_dp1414 chop
arrow from N_wd0808 to N_dp1616 chop
arrow from N_wd1010 to N_dp1212 chop
arrow from N_wd1010 to N_dp1414 chop
arrow from N_wd1010 to N_dp1616 chop
arrow from N_wd1212 to N_dp1414 chop
arrow from N_wd1212 to N_dp1616 chop
arrow from N_wd1414 to N_dp1616 chop
arrow from N_dp0606 to N_wd0808 chop
arrow from N_dp0606 to N_wd1010 chop
arrow from N_dp0606 to N_wd1212 chop
arrow from N_dp0606 to N_wd1414 chop
arrow from N_dp0808 to N_wd1010 chop
arrow from N_dp0808 to N_wd1212 chop
arrow from N_dp0808 to N_wd1414 chop
arrow from N_dp1010 to N_wd1212 chop
arrow from N_dp1010 to N_wd1414 chop
arrow from N_dp1212 to N_wd1414 chop
arrow from N_dp1212 to N_wd1616 chop
# arcs (splines with a single curve) are a bit harder
# in this case, we want them above the "wd" "rank"
# and below the "dp" "rank"
# so, we have to factor in which rank
# and which direction (left-to-right" or "right-to-left)
# cw means clockwise, ccw means counterclockwise (default(
# wd rank, arcs above
arcrad = 2 #.4
arc cw -> from N_wd0606.ne to N_wd1010.nw # chop
arc cw -> from N_wd0606.ne to N_wd1212.nw # chop
arc cw -> from N_wd0606.ne to N_wd1414.nw # chop
arc ccw -> from N_wd1616.nw to N_wd1212.ne # chop
arc ccw -> from N_wd1616.nw to N_wd1010.ne # chop
arc ccw -> from N_wd1616.nw to N_wd0808.ne # chop
arc ccw -> from N_wd1616.nw to N_wd0606.ne # chop
# dp rank, arcs below
arc ccw -> from N_dp0606.se to N_dp1010.sw # chop
arc ccw -> from N_dp0606.se to N_dp1212.sw # chop
arc ccw -> from N_dp0606.se to N_dp1414.sw # chop
arc ccw -> from N_dp0606.se to N_dp1616.sw # chop
arc ccw -> from N_dp0808.se to N_dp1616.sw # chop
arc ccw -> from N_dp1010.se to N_dp1616.sw # chop
arc ccw -> from N_dp1212.se to N_dp1616.sw # chop
##```