Html Horizontal line error graphviz - graphviz

I'm needing to create subgraph cluster have a label with line separation from nodes.
subgraph cluster_0{
label=< <B>process #1</B> <HR/> >
node [shape=none]
t1 [label="label1"]
t2 [label="label2"]
t3 [label="label 3"]
node [shape=box group=a style=filled fillcolor="red;.5:white" height=.2 label = "" ]
A [ fillcolor="red;0.3:white" ]
B [fillcolor="red;.9:white"]
C
node [shape=none fillcolor=white]
t11 [label="label1"]
t21 [label="label2"]
t31 [label="label 3"]
edge[style=invis];
A->B->C
t1->t2->t3
t11->t21->t31
}
Then I get in error on Syntax.
error stack
pydot.InvocationException: Program terminated with status: 1. stderr follows: Error: syntax error in line 1
... <HR/> ...
in label of graph cluster_0
My graphviz version is
dot - graphviz version 2.36.0 (20140111.2315)

On the graphviz web site, the page called "Node Shapes" contains a grammar (about half-way down) for html-like labels:
For <HR/>, it says:
rows : row
| rows row
| rows <HR/> row
This means that <HR/> is only allowed in between two rows. And rows are only allowed within a <TABLE>, so you'll have to wrap everything in a table and then it may work.
Depending on what exactly you'd like to achieve, an other possible solution might be to simply underline the label using <U>text</U>.

Related

How do I make the arrow reach two tags in mermaid?

I have created this flowchart using mermaid.
flowchart TD
id1(( ))
id1-->Tag1
Tag1-->Tag2
subgraph Tag2
id2(( ))
id2-->Tag3
Tag3-->Tag4
subgraph Tag4
id3(( ))
id3-->Tag5
Tag5-->Tag6
Tag6-->Tag7
end
Tag7-->Tag8
end
Tag8-->Tag9
My problem is that the arrow from Tag1 to Tag2 isn't long enough. How do I go about with it? I tried the below, but the connection should be from Tag1 to Tag2, not to the beginning of the black circle after Tag2.
id1(( ))
id1-->Tag1
Tag1-->id2(( )) # Tag1-->Tag2 in original
subgraph Tag2
id2(( ))
id2-->Tag3
Tag3-->Tag4
subgraph Tag4
id3(( ))
id3-->Tag5
Tag5-->Tag6
Tag6-->Tag7
end
Tag7-->Tag8
end
Tag8-->Tag9
I tried you first following code on stackedit
```mermaid
flowchart TD
id1(( ))
id1-->Tag1
Tag1-->Tag2
subgraph Tag2
id2(( ))
id2-->Tag3
Tag3-->Tag4
subgraph Tag4
id3(( ))
id3-->Tag5
Tag5-->Tag6
Tag6-->Tag7
end
Tag7-->Tag8
end
Tag8-->Tag9
```
And its result as follows:
I think this is what you want, and it could be the problem of the mermaid viewer.

Set pre-defined node styles?

I've been googling around for the last 15 minutes trying to find an answer to this. But I can't seem to figure it out.
I was tasked with building some small flowcharts for some applications I've developed at work. They don't need anything fancy because they are going to convert it into their preferred format in vizio. They even said we could do it pen and paper. So I figured I would play around with graphviz/dot.
They have 6 pre-defined shapes/colors that they like to use, so I figured I would use them. I've already built them all in dot...but if I plan to re-use them many times, I'd like to find a way to save them as a sort of template.
Is that possible?
For example...These are the predefined shapes.
digraph G {
node [color="#4271C6"]
process [
shape=Mrecord,
style=filled, fillcolor="#E1F4FF",
label="{1. Process\l | Description}"];
subprocess [
shape=record,
style=filled, color="#FFFFFF", fillcolor="#A5A5A5",
label="| Sub-Process |"];
database [
shape=cylinder, color="#18589A",
label="Database"];
inputoutput [
shape=polygon,
style=filled, fontcolor=white,
fixedsize=true, skew=0.3, margin=0,
width=2, label="Input / Output"];
file [
shape=folder,
label="File"];
external [
shape=box3d,
label="External entity"];
}
unfortunately there is no way to define macros or objects and reuse - especially across multiple graphs. However there are ways using other tools. Some folks use m4 (the macro language) or cpp (the C pre-processor) Both work, but there are potential OS issues. Python, awk, ... would also work.
Here is a gvpr program (gvpr is part of the Graphviz package) that also does what you want (I think):
digraph pre{
a [_type=process label="{1. Process\l | Something}"]
b [_type=process label="{2. Process\l | Something else}"]
c [_type=subprocess label="do it"]
d [_type=database label="lots of data"]
e [_type=database label="a bit of data"]
f [_type=inputoutput label="inOut"]
g [_type=file label="nail file"]
h [_type=external label="outside"]
a->b->c->d->e->f->g->h
}
The gvpr program:
BEG_G{
$G.newrank="true";
}
N{
$.color="#4271C6"; // default
}
N[_type=="process"]{
$.shape="Mrecord";
$.style="filled";
$.fillcolor="#E1F4FF";
// maybe redo $.label
}
N[_type=="subprocess"]{
$.shape="record";
$.style="filled";
$.color="#FFFFFF";
$.fillcolor="#A5A5A5";
$.label=sprintf("|%s|", $.label); // embed in pipes
}
N[_type=="database"]{
$.shape="cylinder";
$.color="#18589A";
}
N[_type=="inputoutput"]{
$.shape="polygon";
$.style='filled';
$.fontcolor="white",
$.ixedsize="true";
$.skew="0.3";
$.margin="0";
$.width="2";
}
N[_type=="file"]{
$.shape="folder";
}
N[_type=="external"]{
$.shape="box3d";
}
Produces:
There may currently be problems with gvpr on Windows, but I know the development team is working on it
Here is the command line:
gvpr -c -f predefined.gvpr predefined2.gv | dot -Tpng > predefined2.png
Okay, so I figured it out. I didn't realize you could do this...but apparently you can break up a node definition into multiple parts...so this is what I came up with, which solves my problem...
I have a "Styles" section that goes at the top. Here I can define each node style. I use comments as a way of naming them. And I don't need to copy paste, because I can just define multiple nodes as a comma separated list.
I also found that you can put them into subgraphs as well, like subgraph style_file {...}. But it seemed simpler to just use a comment as a way to name the style.
digraph G {
newrank=true;
///////////////////////////////////////////////////////////
// Styles
///////////////////////////////////////////////////////////
node [color="#4271C6"];
edge [color="#4271C6"];
//process
createfile, uploadfile
[shape=Mrecord, style=filled, fillcolor="#E1F4FF"];
//subprocess
exportfile, wait
[shape=record, style=filled, color="#FFFFFF", fillcolor="#A5A5A5"];
//external
ftp
[shape=box3d];
//datastore
database
[shape=cylinder, color="#18589A"];
//io
exportproc
[shape=polygon, style=filled, fontcolor=white, margin=0, width=3.1, fixedsize=true, skew=0.3];
//file
workfile
[shape=folder];
///////////////////////////////////////////////////////////
// Clusters
///////////////////////////////////////////////////////////
subgraph cluster_0 {
createfile [label="{1. Process\l | Create file}"];
exportfile [label="|Export Data\nfrom DB|"];
database [label="Database"];
exportproc [label="Export Data"];
workfile [label="Generated file\n(Archived on server)"];
}
subgraph cluster_1 {
uploadfile [label="{2. Process\l | Upload file}"];
ftp [label="FTP Server"];
wait [label="|Wait for\nresponse file|"];
}
///////////////////////////////////////////////////////////
// Relationships
///////////////////////////////////////////////////////////
{
rank=same;
createfile;
uploadfile;
}
///////////////////////////////////////////////////////////
// Relationships
///////////////////////////////////////////////////////////
# cluster_0
createfile -> exportfile;
exportfile -> database;
database -> exportproc;
exportproc -> workfile [style=dashed];
workfile -> uploadfile;
# cluster_1
uploadfile -> ftp [style=dashed];
ftp -> wait;
}
Which produces this:
No affiliation, but the Excel to Graphviz application can create re-usable styles as can be seen in this screenshot:

Graphviz straight lines

I am trying to get straight line edges that exit a node on the right and enter on the left.
I have tried to use splines='line but it does not appear to create straight lines. Code below, as executed in jupyter notebook.
from graphviz import Digraph
g = Digraph('G', filename='cluster.gv')
with g.subgraph(name='cluster_0') as c:
c.attr(style='filled', color='lightgrey')
c.node_attr.update(style='filled', color='white')
c.edges([('a0', 'a1'), ('a1', 'a2'), ('a2', 'a3')])
c.attr(label='process #1')
with g.subgraph(name='cluster_1') as c:
c.attr(color='blue')
c.node_attr['style'] = 'filled'
c.edges([('b0', 'b1'), ('b1', 'b2'), ('b2', 'b3')])
c.attr(label='process #2')
g.edge('a1', 'b3',splines='line',tailport="e", headport="w", constraint='false')
g.edge('a2', 'b0',splines='line',tailport="e", headport="w", constraint='false')
g.view()
This is the graph that is produced by the code:
Graph
I have solved this. The placement of splines='line' was incorrect. Correct code below in case any future users have the same problem.
g = Digraph('G', filename='cluster.gv')
with g.subgraph(name='cluster_0') as c:
c.attr(style='filled', color='lightgrey')
c.node_attr.update(style='filled', color='white')
c.edges([('a0', 'a1'), ('a1', 'a2'), ('a2', 'a3')])
c.attr(label='process #1')
with g.subgraph(name='cluster_1') as c:
c.attr(color='blue')
c.node_attr['style'] = 'filled'
c.edges([('b0', 'b1'), ('b1', 'b2'), ('b2', 'b3')])
c.attr(label='process #2')
g.attr(splines='false')
g.edge('a1', 'b3',tailport="e", headport="w", constraint='false')
g.edge('a2', 'b0',tailport="e", headport="w", constraint='false')
g.view()

What does xpath expression '//ancestor::*[#id][1]' actually mean

Answering a question, I noticed strange libxml behavior on the following expression:
//ancestor::*[#id][1]
for a given context node. I am trying to understand what the expression actually means.
Here is a snippet in PHP and result of its invocation:
$html = <<<HTML
<div id="div1">
<div id="div2">
<p id="p1">Content</p>
</div>
<div id="div3">
<p id="p2">Content</p>
</div>
</div>
HTML;
$doc = new DOMDocument();
$doc->loadHTML($html);
$xpath = new DOMXpath($doc);
$contextNode = $doc->getElementById('p1');
$list = $xpath->query('//ancestor::*[#id][1]', $contextNode);
printf("NodeList length: %d\n", $list -> length);
foreach ($list as $node) {
printf ("item/#id -> %s\n", $node -> getAttribute('id'));
}
Result:
NodeList length: 5
item/#id -> div1
item/#id -> div2
item/#id -> p1
item/#id -> div3
item/#id -> p2
//ancestor::*[#id][1] is a short form for /descendant-or-self::node()/ancestor::*[#id][1] so the context node is only relevant for determining its root or document node /, then in the first step descendand-or-self::node() a node-set is formed of the document node and all its descendant nodes of all kinds (element nodes, text nodes, comment nodes, processing instruction nodes), then the next step for each of those nodes determines ancestor::*[#id][1], that is of all ancestor elements having an id attribute the first one.

how to avoid overlapping edge and node when using graphviz?

As title,I want to draw an image of ELF file format.The ELF Header has offset of program headers table and section headers table,so I want to use two arrows pointer to point out the relationship.But the edges overlap the node(record) even after I have overlap=false and splines=true set.I have search for a while,but my situation is that the arrows somewhat point to parts of itself.
Following is the dot file I am using to generate the png file.
digraph g {
//margin="1"
overlap='scale'
graph [rankdir="LR"]
"ELF File" [
label="<f0> ELF Header\n e_shoff=0x118| <f1> Program Headers Table | <f2> .text | <f3> .data | <f4> .rodata| <f5> .comment | <f6> .shstrtab | <f8> .symtab | <f9> .rel.text | <f7> Section Table"
shape="record"
];
"ELF File":f0 -> "ELF File":f1 [label="e_phoffset"]
"ELF File":f0 -> "ELF File":f7 [label="e_shoff"]
}
One possible solution is to use "east" node ports on one of the edges, so that this edge appears on opposite side of the record. You do this by appending :e to the node name. For example:
"ELF File":f0:e -> "ELF File":f7:e [label="e_shoff"]

Resources