Graphviz Composite Structure Diagram - graph

Is it possible to generate with Graphviz / dot a UML composite structure diagram like the one below?

By using (open) box arrowheads https://graphviz.gitlab.io/doc/info/arrows.html, this gets pretty close:
digraph boxed {
graph [splines=ortho nodesep =.75]
node [shape=box]
edge [dir=both arrowtail=obox arrowhead=obox]
{ rank=same
x1 -> x2 -> x3
}
x1:s -> y1:n
}

Related

How to show arrows symmetrically for self-loops in a dot graph

I am working with a DFA which I have described in the dot file format. One of the nodes in my DFA has two self-loops, which I originally described with the following way
digraph {
rankdir=LR;
a -> a [color=blue]
a -> a [color=green]
}
Which produces this output when I run dot graph.gv -Tpng
For symmetry reasons, I'd like to have the blue and the green arrows on opposite sides of the node. I can modify the headport and tailport of the green arrow to force it to start from the bottom of the node as follows:
digraph {
rankdir=LR;
a -> a [color=blue]
a:sw -> a:se [color=green]
}
Unfortunately, that produces an absolutely wonky output:
What's the correct way of getting the two arrows to be symmetrically opposite each other on the node?
I doubt you have a lot of control over the edge layout. But you can experiment with the headport attribute values. Here are some examples.
Example 1
digraph {
rankdir=LR;
a:n -> a [color=blue]
a:s -> a [color=green headport=center]
}
View in editor
Example 2
digraph {
rankdir=LR;
a:ne -> a [color=blue]
a:sw -> a [color=green headport=center]
}
View in editor
Other layouts
You can also experiment with different layouts. Here are some options for the circo layout.
Example 3
digraph {
rankdir=LR;
layout="circo"
a:n -> a:_ [color=blue headport=n]
a:s -> a:_ [color=green headport=s dir=back]
}
View in editor
Example 4
digraph {
rankdir=LR;
layout="circo"
a:nw -> a:w [color=blue headport=_]
a:se -> a:e [color=green headport=_]
}
View in editor

Update a field in an Elm-lang record via dot function?

Is it possible to update a field in an Elm record via a function (or some other way) without explicitly specifying the precise field name?
Example:
> fields = { a = 1, b = 2, c = 3 }
> updateField fields newVal fieldToUpdate = { fields | fieldToUpdate <- newVal }
> updateField fields 5 .a -- does not work
UPDATE:
To add some context, I'm trying to DRY up the following code:
UpdatePhraseInput contents ->
let currentInputFields = model.inputFields
in { model | inputFields <- { currentInputFields | phrase <- contents }}
UpdatePointsInput contents ->
let currentInputFields = model.inputFields
in { model | inputFields <- { currentInputFields | points <- contents }}
Would be really nice if I could call a mythical updateInput function like this:
UpdatePhraseInput contents -> updateInput model contents .phrase
UpdatePointsInput contents -> updateInput model contents .points
Rolling your own update function
Yes, though perhaps not as nicely as getting from a field. But the idea is the same, you write a function that simply uses the record update syntax:
setPhrase r v = { r | phrase <- v }
setPoints r v = { r | points <- v }
updInputFields r f = { r | inputFields <- f r.inputFields }
Then you can write:
UpdatePhraseInput contents -> updInputFields model (flip setPhrase contents)
UpdatePointsInput contents -> updInputFields model (flip setPoints contents)
The Focus library
When you combine field and fieldSet, you get something like a Focus. Although that library works for more things than just records. Here's an example of what this would look like using Focus:
phrase = Focus.create .phrase (\upd r -> { r | phrase <- upd r.phrase })
points = Focus.create .points (\upd r -> { r | points <- upd r.points })
inputFields = Focus.create .inputFields (\upd r -> { r | inputFields <- upd r.inputFields})
Then you can write:
UpdatePhraseInput contents -> Focus.set (inputFields => phrase) contents model
UpdatePointsInput contents -> Focus.set (inputFields => points) contents model
Ideally you could define a function which could select which field gets updated, but you cannot.
See This article, which explains why it's not currently possible to functionally update fields in a record in elm:
"Seasoned functional programmers will surely have noticed that many of these concepts sound a lot like lenses, and Elm actually already has a lens-like library authored by Evan himself, called Focus. This, however, does not actually solve the problem: it requires manual description of setters just like the purely function based approach does."
...and the following comment from the the creator of Elm explaining why proposed support for this wasn't added with the recent changes to records:
"I considered that and decided against it. I know that proposal. It's a language feature proposal, not a simple syntax thing"

Graphviz / dot label overlap with edge

I have a label that barely touch the edge, but there were plenty of space round it, is there anyway to make it not touching the edge in Graphiz? This is minor issue, but I have to redraw in powerpoint if cannot resolve by coding as my collaborator is very unhappy about this.. (Or I may export to JPEG and make changing in paintbrush)...
And we have to do this in black and white only so changing color would not help :(
minimal example: (the whole diagram is much more complex, and I have to put A E B in the same rank)
digraph "md" {
rankdir=TB;
size="8,8";
node [fontname="Helvetica" fontsize=10 shape=box];
edge [fontname="Helvetica" fontsize=10];
center=1;
{rank=min "A"}
{rank=min "B"}
{rank=min "E"}
"A" -> "B" [label="0.55***", dir=both];
"E" -> "B" [label="0.22" labeldistance="2"];
}
For the records - making the example minimal
digraph {
{ rank=same A -> B -> C }
A -> C [label=AC]
}
gives
using xlabel instead of label may help (but seems to have side effects)
digraph {
{ rank=same A -> B -> C }
A -> C [xlabel=AC]
}
gives

graphviz dot to pdf: distance from graph to title

in graphviz dot, generating pdf output.
how do I increase the distance between the title and the graph?
digraph "test" {
graph [ label="need more distance to below" ];
A -> B;
}
advice appreciated.
Not preferable solution but Append "\n" at the end of label. If you need more space add more "\n".

how to optimize layout in graphviz to remove unecessary edges intersections (crossings)?

I am preparing the automaitc documentation of DB relations. The tool is graphviz. Problem I have is that the placement of nodes on the output image is not opptimal and there are many unecessary intersection of edges.
Is there any method to perform optimazation of the graph so the result will have minumum edges intersetction (crossing)?
digraph structs {
node [shape=Mrecord];
overlap="false";
splines="true";
layout=sfdp;
rankdir=LR;
ttype[label="::: ttype :::|<id>id|<table_name>table_name|<type_name>type_name|<synopsis>synopsis"];
tevents[label="::: tevents :::|<id>id|<id_tcases>id_tcases|<id_ttype>id_ttype|<synopsis>synopsis|<expiredate>expiredate|<open>open"];
toperationlog[label="::: toperationlog :::|<id>id|<executiondate>executiondate|<executiontime>executiontime|<query>query|<id_tusers>id_tusers"];
tdocuments[label="::: tdocuments :::|<id>id|<id_tcases>id_tcases|<id_ttype>id_ttype|<path>path|<creationdate>creationdate"];
tcustomers_cases[label="::: tcustomers_cases :::|<id_tcustomers>id_tcustomers|<id_tcases>id_tcases"];
tcases[label="::: tcases :::|<id>id|<creationdate>creationdate|<incomingdate>incomingdate|<clousuredate>clousuredate|<synopsis>synopsis|<notes>notes|<id_ttype>id_ttype|<id_tusers>id_tusers"];
tusers[label="::: tusers :::|<id>id|<username>username|<password>password|<firstname>firstname|<lastname>lastname|<role_id>role_id"];
tcustomers[label="::: tcustomers :::|<id>id|<firstname>firstname|<lastname>lastname|<email>email|<phone>phone|<mobile>mobile|<address>address"];
tevents:id_tcases -> tcases:id [arrowhead="none"];
tevents:id_ttype -> ttype:id [arrowhead="none"];
toperationlog:id_tusers -> tusers:id [arrowhead="none"];
tdocuments:id_tcases -> tcases:id [arrowhead="none"];
tdocuments:id_ttype -> ttype:id [arrowhead="none"];
tcustomers_cases:id_tcustomers -> tcustomers:id [arrowhead="none"];
tcustomers_cases:id_tcases -> tcases:id [arrowhead="none"];
tcases:id_ttype -> ttype:id [arrowhead="none"];
tcases:id_tusers -> tusers:id [arrowhead="none"];
}
Setting remincross to true will cause cross minimization to run a second time, which should improve the look of the graph by reducing the number of edge crosses.

Resources