grViz diagrammeR: justifying rows of nodes - r

I am using diagrammeR with grViz to generate a flow chart with multiple rows. The rows are grouped together properly, and the vertical order works well. Is there a way to specify justification of full rows (ranks)? I would like them to be centered. Below is code and an image of the example I am working with. I would like rows 3 and 4 to be centered.
Any input would be greatly appreciated.
Thanks.
library("DiagrammeR")
grViz("
digraph CFA {
# Multiple level nodes
node [shape = rectangle, color=CornflowerBlue]
a [label = <<FONT COLOR='blue' POINT-SIZE='18'><b>Surveillance 2017 </b> <br/>Urban Mixtures</FONT>> ];
# http://www.graphviz.org/doc/info/shapes.html#html
#Tiers
node [shape = ellipse, color=CornflowerBlue]
T1 [label = <<u><b><font color = 'forestgreen' point-size = '16'>Tier 1</font></b></u><br/>Water Quality <br/> 16 Watersheds <br/> Quarterly sampling>];
T2 [label = <<u><b><font color = 'forestgreen' point-size = '16'>Tier 2</font></b></u> <br/> Sediment and Passive sampling <br/> 72 Sites>];
#Media assays and ancillary
chem [label = 'Water \\nChemistry'];
bio [label = 'Bio-effects'];
Anc [label = 'Ancillary \\ndata']
sed [label = 'Sediment \\nChemistry'];
pass [label = 'Passive Sampler \\nChemistry'];
# Analyses
node [shape = box, color = Crimson]
owc [label = 'Waste Indicators'];
PFAS [label = 'PFAS: 30 sites']
PAH [label = 'PAHs'];
Att [label = 'Attagene'];
Met [label = 'Metabolomics'];
Tr [label = 'Transcriptomics'];
Hyd [label = 'Hydrology'];
WA [label = 'Watershed \\nAttributes']
# Synthesis
node [shape = 'egg',color = ' forestgreen']
Syn [label = 'Synthesis'];
Tx [label = 'ToxEval\\nHTS/AOP analysis']
{rank = same; T1 T2}
{rank = same; chem bio pass sed Anc}
# {rank = same; PFAS; PAH; WA; Hyd; owc;Att;Met;Tr}
{rank = same; PFAS; PAH; Hyd; owc;WA; Hyd}
{rank = same; Att;Met;Tr}
{rank = same; Tx; Syn}
# Connect nodes with edges and labels
T1 -> a[dir=back]
a -> T2#[dir=back]
T1 -> {bio chem Anc}
T2 -> {bio sed Anc pass chem}
Anc -> {Hyd WA}
chem -> {owc}
chem -> PFAS [label = 'Tier 2']
sed -> {owc PAH}
pass -> PAH
bio -> {Met Tr} [label = 'Tier 1']
bio -> {Att} [label = 'Tier 2']
{owc Att Met Tr Hyd WA PAH PFAS} -> Syn
{owc PAH PFAS} -> Tx
Tx -> Syn
}
")
example flow chart

Related

Suggested Tools for Visualizing a Subgraph DAG

I am writing a program which basically processes a subgraph DAG, i.e., the graph is a directed acyclic graph and each node of the graph is a subgraph. For example, for an edge A->B in the DAG, node A is a subgraph of a triangle and node B is a subgraph of a four clique. The edge A->B indicates an extension from a triangle to a four clique by adding one subgraph vertex and three subgraph edges.
+=======+ +=======+
| a---b | | a---b |
| | / | | |\ /| |
| | / | =====> | | X | |
| |/ | | |/ \| |
| c | | c---d |
+=======+ +=======+
A B
For many purposes, I want to visualize this subgraph DAG, i.e., the visualization can show the entire structure of the DAG and show the subgraph of all the nodes at the same time. Also it would be better if it can also show properties of vertices and edges.
I am able to list all the nodes and edges of the DAG and the subgraphs of all the nodes in any format. But what I don't know is what tool is the best for such visualization. I tried graphviz by exporting the subgraph DAG into dot format and use graphviz to convert the dot file to a png. The problem of graphviz is it can show the subgraph of nodes very well but it fails to show the structure of the DAG in a human-readable way. It would be good if
for a DAG edge A->B, node A is placed above node B. (graphviz now puts all the DAG nodes in the same row)
the nodes are placed properly such that the intersection among the DAG edges is minimized.
Are there any other alternatives? Thanks in advance!
If I understand your requirements, I think this dot program comes pretty close:
digraph dag {
compound=true // needed for A->B edge (kludge, but documented)
edge [dir=none] // no arrowheads
subgraph clusterA{
labelloc=b
label="A"
Aa -> Ab // [constraint=false] // keep on same rank
Ab -> Ac
Aa -> Ac
{
rank=same
Aa [label="a"]
Ab [label="b"]
}
Ac [label="c"]
}
subgraph clusterB{
labelloc=b
label="B"
Ba -> Bb // [constraint=false] // keep on same rank
Bc -> Bd // [constraint=false] // keep on same rank
Bb -> Bc
Ba -> Bc
Bb -> Bd
Ba -> Bd
{
rank=same
Ba [label="a"]
Bb [label="b"]
}
{
rank=same
Bc [label="c"]
Bd [label="d"]
}
}
Ac -> Ba [dir=forward ltail=clusterA lhead=clusterB minlen=2]
}
Here is the output:

R diagrammeR using html for formatting while reading text from r variable

I'm creating a flow chart with the R package diagrammer. To get desired formatting (bold, bullet, left-justify) I can write node label in html. However, I also want to populate some of the text by calling variables in R, and I can't figure out how to do both (html formatting + call R variables) at the same time.
In this code snippet, the html formatting works but instead of printing the string assigned to the variable 'text_var', it prints the string 'text_var'.
library(DiagrammeR)
text_var = 'Some text'
grViz("digraph flowchart {
# Node definitions
node [fontname = Helvetica, shape = box]
tab1 [label = <<b> Node 1 </b> <br ALIGN = 'LEFT' /> • text_var <br ALIGN = 'LEFT' />
>]
tab2 [label = 'Node 2']
# Edge definitions
tab1 -> tab2
}")
In this code snippet, I am print the string assigned to the variable 'text_var', but there's no html.
library(DiagrammeR)
text_var = 'Some text'
grViz("digraph flowchart {
# Node definitions
node [fontname = Helvetica, shape = box]
tab1 [label = '##1']
tab2 [label = 'Node 2']
# Edge definitions
tab1 -> tab2
}
[1]: paste0('Node 1 \\n ', text_var)
")
Desired result is the text from the second example with the formatting from the first. Thank you!
Although the solution by Allan Cameron works, it is also possible to use
Graphviz Substitution.
I found the implementation rather buggy however, although ##1 should work in the below example, I found that it took over 3 minutes of full CPU usage before I shut it off. ##1-1 seems to work.
text_var = 'Some text'
grViz("
digraph flowchart {
# Node definitions
node [fontname = Helvetica, shape = box]
tab1 [label = <
<b>Node 1</b>
<br ALIGN = 'LEFT' />
• ##1-1
<br ALIGN = 'LEFT' />
>]
tab2 [label = 'Node 2']
# Edge definitions
tab1 -> tab2
}
[1]: text_var"
)
R doesn't know that you want the string "text_var" inside the string you are passing to grViz to be replaced by the actual variable text_var containing your string. Try this instead:
grViz(gsub("text_var", text_var, "digraph flowchart {
# Node definitions
node [fontname = Helvetica, shape = box]
tab1 [label = <<b> Node 1 </b> <br ALIGN = 'LEFT' /> • text_var <br ALIGN = 'LEFT' />
>]
tab2 [label = 'Node 2']
# Edge definitions
tab1 -> tab2
}"))
```

Sorting the data in a loop using ASP Classic?

I want to sort the data by the SuppCodeArry in a loop. This is my code:
<%
SuppCodeArry="SA^SA^SB^SA^SC^SB^SA^"
ITEMArry="A^B^C^D^E^F^G^"
str_SuppCode = Split(SuppCodeArry,"^")
str_ItemCode = Split(ITEMArry,"^")
SUPPCODE = ""
str_SuppCode_NEW = ""
str_ItemCode_NEW = ""
For a=0 To UBound(str_SuppCode)-1
Response.Write str_SuppCode(a) & " ["&str_ItemCode(a)&"] <br>"
str_SuppCode_NEW = str_SuppCode_NEW & str_SuppCode(a) &"^"
str_ItemCode_NEW = str_ItemCode_NEW & str_ItemCode(a) &"^"
Next
%>
The result I get with this code is:
SA [A]
SA [B]
SB [C]
SA [D]
SC [E]
SB [F]
SA [G]
I would like to have the result by grouping by the SuppCodeArry as below. How do I do this?
SA [A]
SA [B]
SA [D]
SA [G]
SB [C]
SB [F]
SC [E]
Thanks for any info on this.

diagrammeR specifying node order and formatting text

I am using diagrammeR grViz to construct a flow chart. I would like to specify the order of some of the nodes that have the same rank. In the following chart, I would like to have Node 1 in the center rather than on the left. In addition, I would like to have "Node 2" underlined, but not "extra detail". Here is the code:
library("DiagrammeR")
grViz("
digraph CFA {
# Multiple level nodes
node [shape = rectangle, color=CornflowerBlue]
a [label = 'Node 1' ];
node [shape = ellipse, color=CornflowerBlue]
T1 [label = 'Node 2\\nextra detail'];
T2 [label = 'Node 3'];
{rank = same; a T1 T2}
# Connect nodes with edges and labels
a -> T1
a -> T2
}
")
Any help would be much appreciated. Also, if there are resources to help me along with these customization issues in diagrammeR, please include a link.
there are several ways to order the nodes. The easiest here is perhaps to have the edge T2 -> a in this order (rather than a -> T2), so node T2 is first and then use dir=back to reverse the arrow. You can use html to underline the node label. (also have to use break, <br/>, instead of newline,\n)
grViz("
digraph CFA {
a [label = 'Node 1', shape = rectangle, color=CornflowerBlue ];
node [shape = ellipse, color=CornflowerBlue]
T1 [label = <Node 2 <br/> <u>extra detail</u>>];
T2 [label = 'Node 3'];
{rank = same; a T1 T2}
# Connect nodes with edges and labels
a -> T1
T2 -> a[dir=back]
}
")
From comment: Is there a way to make a portion of the text in a node a different color (e.g. just the "extra detail", but not "Node 2")?
Yes, from the html link above you can "sets the color of the font within the scope of FONT.../FONT". So for example, change the label of T1 to
label = <Node 2 <br/> <font color='red'> <u>extra detail</u> </font> >

Positionating and arrow direction in GraphViz

I'm trying to migrate some realy old documentation to our internal wiki using GraphViz.
I'm not used to the Dot language, and needs some help
See following example:
I have experiment a lot, but the best I have come up to so far is this:
digraph CentralPmr {
fontname="Helvetica";
shape=box;
node[shape=box];
graph [splines=ortho]
sg [label="TTD storage group for\nthe logged values"]
vc [label="Value catalogue"]
tc1 [label="Time catalogoue (1)"]
tc2 [label="Time catalogoue (2)"]
sv_ [shape=point,width=0.01,height=0.01];
sv [label=""]
ie [shape=none, label="Initiating event"]
c1 [shape=none, label="The set of values, defined\nby the value catalogue, which\nare freezed out of the TTD\nstorage group of the actual log."]
c2 [shape=none, label="Time catalogue defining\nat what time around the\ninitiating event values\nshould be collected."]
sgf [shape=record, label="{<f0> 1|2|3|4|..}|{ | | | | }"]
sg -> sv_ [penwidth=4, dir=none];
sv_ -> sv -> tc2 [penwidth=4]
sv -> sgf:f0 [penwidth=4]
{vc, tc1} -> sg
c1 -> sv [style=dashed, arrowhead="open"];
{rank=min; ie}
{rank=same; sg c1}
{rank=same; vc sgf}
{rank=max; rc2}
}
It don't have to be exactly the same as the source, but I want it to be understandable.
The problems is:
How do I place the text between "Value catalogue" and "Time catalogue (1)"?
[Edit] How do I force the arrow to "TTD storage group for PMR-freezed value" to go from the side, and not from the above? It is a virtualization of a memory area, and the arrow are pointing to a specific memory post. In other images, it can point to a other memory post in the memory area (eg. 2 , 3, 4..).
Is it possible to create a zigzag line from the "Initiating event"?
How do I place the legends in the bottom that explains the different types of lines?
[edit] How do I add the comments above, under and to the right of the "TTD storage group for PMR-freezed values"?
[Edit] How do I make the "TTD storage group for PMR-freezed value" wider?
This is on top of my first answer in a way that editing that one would create too much confusion. I have tried to take all your needs into consideration and it only works (I believe) if you give up the splines=ortho requirement. Pls refer to the comments below my first answer. Here we go:
digraph CentralPmr {
fontname="Helvetica";
shape=box;
node[shape=box];
// graph [splines=ortho]
sg [label="TTD storage group for\nthe logged values", width = 2.5]
sv[ label="", width = 2]
ie [ shape=none, label="Initiating event", fontsize = 18 ]
c1 [ shape=none, label="The set of values, defined\nby the value catalogue, which\nare freezed out of the TTD\nstorage group of the actual log." ]
sgf[shape=box, margin=0, label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD BORDER="0" COLSPAN="2">TTD storage group for<BR/>PMR freezed values</TD>
</TR>
<TR>
<TD PORT="f1">1</TD>
<TD BORDER="0" ROWSPAN="6">The set of<BR/>values is<BR/>stored in<BR/>the TTD<BR/>storage<BR/>group</TD>
</TR>
<TR>
<TD>2</TD>
</TR>
<TR>
<TD>3</TD>
</TR>
<TR>
<TD>4</TD>
</TR>
<TR>
<TD>-</TD>
</TR>
<TR>
<TD>-</TD>
</TR>
<TR>
<TD BORDER="0" COLSPAN="2">Up to nine freezing areas<BR/>for defined central PMR</TD>
</TR>
</TABLE>>];
TTD [shape=none, margin=0, label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="12">
<TR>
<TD PORT="f1">Value catalogue</TD>
</TR>
<TR>
<TD BORDER="0"></TD>
</TR>
<TR>
<TD PORT="f2">Time catalogue (1)</TD>
</TR>
<TR>
<TD BORDER="0">Time catalogue defining<BR/>at what time around the<BR/>initiating event values<BR/>should be collected</TD>
</TR>
<TR>
<TD PORT="f3">Time catalogue (2)</TD>
</TR>
</TABLE>>];
connector_1[ shape = point height = 0 width = 0 margin = 0 ]
ie -> connector_1[ style = dotted, arrowhead = none ];
{ rank = same; connector_1 c1 }
connector_1 -> c1[ style = invis, minlen = 4 ];
c1 -> sv[ style = dashed, arrowhead = open ];
connector_2[ shape = point height = 0 width = 0 margin = 0 ]
connector_1 -> connector_2[ style = dotted ];
{ rank = same; sg connector_2 sv }
sg -> connector_2[ minlen = 3, penwidth = 4, arrowhead = none ];
connector_2 -> sv[ minlen = 3, penwidth = 4 ];
sg:sw -> TTD:f1:nw[ weight = 5 ];
sg:w -> TTD:f2:w;
sv:sw -> TTD:f3:e[ penwidth = 4 ];
sv:sw -> sgf:f1:w[ penwidth = 4 ];
node[ shape = plaintext ];
leg2[ label = "Data flow" ];
leg4[ label = "Reference" ];
leg6[ label = "Comment" ];
node [ shape = point height = 0 width = 0 margin = 0 ];
leg1 leg3 leg5
TTD:sw -> leg1[ style = invis ];
{ rank = same; leg1 leg2 leg3 leg4 leg5 leg6 }
edge[ minlen = 2 ];
leg1 -> leg2[ penwidth = 4 ];
leg3 -> leg4[ style = dotted ];
leg5 -> leg6[ style = dashed, arrowhead = open ];
}
yields
Not sure whether I understand completely what you want but below my take on it. This is just a first attempt, much more fine-tunig can be done. I would probably use HTML-like nodes where text and "box" need to be closer, in particular for that "TTD Storage Group for PMR freezed values" in the original graph.
My answers to your questions would be:
How do I place the text between "Value catalogue" and "Time catalogue (1)"?
--- See below. I have put it between the two time catalogues as in the original graph but easy to move around.
How do I force the arrow to the record go from the side, and not from the above?
--- See below. You could also use rankdir = LR; to change the orientation if that is your question.
Is it possible to create a zigzag line from the "Initiating event"?
--- There are ways, but a lot of effort (like creating a custom shape). Nothing "out of the box", to the best of my knowledge.
How do I place the legends in the bottom?
I don't really understand, but in general, the answer would be HTML-like labels when we talk about nodes.
Her is what I have done:
digraph CentralPmr
{
fontname="Helvetica";
shape=box;
node[shape=box];
graph [splines=ortho]
sg [label="TTD storage group for\nthe logged values"]
vc [label="Value catalogue"]
tc1 [label="Time catalogoue (1)"]
tc2 [label="Time catalogoue (2)"]
sv_ [shape=point,width=0.01,height=0.01];
sv [label="", width = 2]
ie [shape=none, label="Initiating event"]
c1 [shape=none, label="The set of values, defined\nby the value catalogue, which\nare freezed out of the TTD\nstorage group of the actual log."]
c2 [shape=none, label="Time catalogue defining\nat what time around the\ninitiating event values\nshould be collected."]
sgf [shape=record, label="{<f0> 1|2|3|4|..}|{ | | | | }"]
connector_1[ shape = point height = 0 width = 0 margin = 0 ]
ie -> connector_1[ style = dotted, arrowhead = none ];
{ rank = same; connector_1 c1 }
connector_1 -> c1[ style = invis ];
c1 -> sv[ style = dashed, arrowhead = open ];
connector_2[ shape = point height = 0 width = 0 margin = 0 ]
connector_1 -> connector_2[ style = dotted ];
{ rank = same; sg connector_2 sv }
sg -> connector_2[ minlen = 3, penwidth = 4, arrowhead = none ];
connector_2 -> sv[ minlen = 3, penwidth = 4 ];
vc -> tc1 -> c2 -> tc2[ style = invis, weight = 10 ];
sg -> vc;
sg -> tc1;
sv -> tc2[ penwidth = 4 ];
sv -> sgf;
}
yields

Resources