Fine tuning edge and label placement in dot - graphviz

I'm plotting a graph in dot. In order to make it legible I need to fine-tune the placement of the edge labels, as well as (if possible) making certain edges straight while others are curved. I would appreciate general advice on how to accomplish these things in dot, but for the sake of concreteness I include my specific problem below.
Here is the code, followed by what it currently looks like:
digraph myGraph {
rankdir=BT;
splines=line;
"AB.BC" -> "AB.AC.BC" [weight=4]
"AB.BC" -> "ABC" [color=red,style=dashed,label="I(A;C|B)"]
"A.B.C" -> "A.BC" [color=red, label="I(B;C)"]
"A.B.C" -> "AC.B" [color=red, label="I(A;C)"]
"A.B.C" -> "AB.C" [color=red, label="I(A;B)"]
"A.BC" -> "AB.BC" [color=red, label="I(A;B)"]
"A.BC" -> "AC.BC" [color=red, label="I(A;C)"]
"AB.AC.BC" -> "ABC" [weight=4]
"AC.B" -> "AC.BC" [color=red, label="I(B;C)"]
"AC.B" -> "AB.AC" [color=red, label="I(A;B)"]
"AC.BC" -> "AB.AC.BC" [weight=4]
"AC.BC" -> "ABC" [color=red,style=dashed, label="I(A;B|C)"]
"AB.AC" -> "AB.AC.BC" [weight=4]
"AB.AC" -> "ABC" [color=red,style=dashed, label="I(B;C|A)"]
"AB.C" -> "AB.BC" [color=red, label="I(A;B)"]
"AB.C" -> "AB.AC" [color=red, label="I(A;C)"]
}
This is close to what I want, but it has a few problems:
The labels are placed in such a way that you can't easily see which one is associated with which edge
For some reason, some of the edges have a bend in them at the label. (They came out as straight lines before I added the labels.)
I've tried playing with the rowsep and nodesep attributes but wasn't able to improve it. If I remove the splines=line line it becomes legible but isn't really what I want:
It's fine for the dotted edges to be curved -- it's actually good, because it will prevent them from overlapping the second node from the top -- but the solid ones really should be straight.
I'd like any advice on how to fine tune node, edge and label placement (as the documentation is really unhelpful and good examples are hard to find), but specifically, my questions are:
Can I tell dot to make specific edges curved while keeping others straight? (I know there is a splineType edge attribute, but the documentation doesn't give me a clue how to use it and I'm not even sure this is what it does.)
If the above is not possible, how can I tell dot to make the straight lines dead straight, rather than bending at the label?
For straight edges, how can I fine tune the placement of the labels? I don't mind doing it by hand, and there seem to be several edge attributes that should help me do that, but none of them seem to have any effect whatsoever, so I must be doing something wrong.
As a bonus question: is there a way that I can give the nodes a more grid-like layout, so that they're nicely vertically aligned?
Any answer is appreciated, but most especially helpful would be answers that explain how to handle these issues more generally, for the sake of future visitors, rather than just fixing my code.

If you use the neato layout engine, you can set the nodes explicit coordinates with attribute pos="x,y". In dot layout engine this is possible by using {rank=same; node1; node2; ...} for vertical alignment and group attribute (node1[group=g1]; node3[group=g1];) for horizontal alignment.
The position of the labels can be changed using the attributes headlabel and taillabel.
Image:
Script:
digraph myGraph {
layout=neato
splines=true
rankdir=BT
node [pin=true]
"A.B.C" [pos="0,0"]
"AC.B" [pos="0,2"]
"A.BC" [pos="-2,2"]
"AB.C" [pos="2,2"]
"AC.BC" [pos="-2,4"]
"AB.BC" [pos="0,4"]
"AB.AC" [pos="2,4"]
"AB.AC.BC" [pos="0,6"]
"ABC" [pos="0,8"]
"AB.BC" -> "AB.AC.BC"
"AB.BC" -> "ABC" [color=red,style=dashed,taillabel="I(A;C|B)"]
"A.B.C" -> "A.BC" [color=red, label="I(B;C)"]
"A.B.C" -> "AC.B" [color=red, label="I(A;C)"]
"A.B.C" -> "AB.C" [color=red, label="I(A;B)"]
"A.BC" -> "AB.BC" [color=red, taillabel="I(A;B)"]
"A.BC" -> "AC.BC" [color=red, taillabel="I(A;C)"]
"AB.AC.BC" -> "ABC"
"AC.B" -> "AC.BC" [color=red, taillabel="I(B;C)"]
"AC.B" -> "AB.AC" [color=red, taillabel="I(A;B)"]
"AC.BC" -> "AB.AC.BC"
"AC.BC" -> "ABC" [color=red,style=dashed, label="I(A;B|C)"]
"AB.AC" -> "AB.AC.BC"
"AB.AC" -> "ABC" [color=red,style=dashed, label="I(B;C|A)"]
"AB.C" -> "AB.BC" [color=red, taillabel="I(A;B)"]
"AB.C" -> "AB.AC" [color=red, taillabel="I(A;C)"]
}

Related

How to change font size of a single record item in Graphviz

I'm trying to create a state chart from Graphviz of type record. Please check the reference here.
So here is the basic code:
digraph lamp {
node [shape=point,label=""]ENTRY
node [style=rounded shape=record ]
ON [label="{On| Some code here}"];
OFF [label="{Off| Some code here}"];
ENTRY -> ON[label="Initialization"]
ON -> OFF[label="|toggle|"]
OFF -> ON[label="|toggle|"]
}
In above code, I need to add some code below the state name like On and Off where I put the line Some code here. Since there will be a code and it can be any number of lines, I like to change the font size of this single record block where I will put the code (Not the state name record).
So in this line of code:
ON [label="{On| Some code here}"];
I like to change the font size of Some code here only not of On.
So, How can I get the control to independently change styling like font size or font name etc of the entered code here?
You can use html-like text, without building tables. (https://www.graphviz.org/doc/info/shapes.html#html). Like so:
digraph lamp {
node [shape=point,label=""]ENTRY
node [style=rounded shape=record ]
ON [label=<{<FONT COLOR="RED" POINT-SIZE="24.0">On</FONT>|<FONT COLOR="darkgreen" POINT-SIZE="10.0"> Some code here</FONT>}>];
OFF [label=<{<FONT COLOR="black" POINT-SIZE="24.0">Off</FONT>|<FONT COLOR="darkred" POINT-SIZE="10.0"> Some code here</FONT>}>];
ENTRY -> ON[label="Initialization"]
ON -> OFF[label=" |toggle| "]
OFF -> ON[label=" |toggle| "]
}
Giving:

Better layout of nodes for block diagrams in dot

After a previous question (Block diagram layout with dot/Graphviz) I have further questions. The following is compiled like so:
dot -Gsplines=none test.gv | neato -n -Gsplines=ortho -Tpng -otest.png
digraph G {
graph [rankdir = LR];
node[shape=record, style=filled];
bar[label="Bar", height=1.3636363636363635];
tea[label="Tea", height=1.3636363636363635];
brew[label="Brew", height=3.6363636363636362];
bar1[label="Bar1", height=2.2727272727272725];
baz[label="Baz", height=1];
foo[label="Foo", height=5.0];
darjeeling[label="Darjeeling", height=3.1818181818181817];
example[label="Example", height=17.727272727272727];
bar -> example [label="bar_clk"];
bar -> example [label="bar_bar"];
example -> tea [label="bli1"];
example -> tea [label="blo2"];
example -> tea [label="blo3"];
example -> brew [label="bli"];
example -> brew [label="blo"];
example -> brew [label="blo"];
example -> brew [label="blo"];
example -> brew [label="blo"];
example -> brew [label="blo"];
example -> brew [label="blo"];
example -> brew [label="blo"];
bar1 -> example [label="bar1_foo"];
bar1 -> example [label="bar1_bar"];
bar1 -> example [label="bar1_baz"];
bar1 -> example [label="bar1_baz1"];
bar1 -> example [label="bar1_bar2"];
baz -> example [label="baz_foo"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> foo [label="bla"];
example -> bar [label="blu"];
example -> baz [label="ble"];
darjeeling -> example [label="darjeeling_bli1"];
darjeeling -> example [label="darjeeling_blo2"];
darjeeling -> example [label="darjeeling_blo3"];
darjeeling -> example [label="darjeeling_bli1"];
darjeeling -> example [label="darjeeling_blo2"];
example -> darjeeling [label="bla"];
darjeeling -> example [label="darjeeling_blo3"];
}
My question is how I could take the, say, Baz and Darjeeling nodes and move them to the left side to decrease the height of the middle node. I don't know what determines this. I understand this is a directional graph, so the general "flow" of the diagram is left to right, I'd just like more control.
These diagrams will be generated automatically, so an explanation on how to lay it out as I wish and why, as opposed to a code snippet that makes it work for this particular example, is preferred.
A couple of points:
how I could take the, say, Baz and Darjeeling nodes and move them to the left side
By setting constraint=false for the edges going from Example to Baz and Darjeeling, or by grouping all the nodes to appear left of Example in a subgraph with rank=min.
You may say that this is not a suitable solution (at least not the one with constraint=false) because
These diagrams will be generated automatically
and I completely understand (been there many times) - but at the same time, you wish
to decrease the height of the middle node
which is set manually, so the graph still is not fully auto-generated (how do you calculate the height needed for Example?).
I don't know what determines this
I'm not completely sure neither - Baz could might as well be on the left.
Surprisingly, the order of appearance of the nodes changes the layout in some cases. For example, if you move up the definition of the Darjeeling node, it will appear on the left side (and Bar gets to be at the right side).
Edit: Here comes the code snippet...
A third possibility is to define all edges in the right order (top-down/left-right) and decorate the edges going back with dir=back.
If you change these 3 lines
example -> bar [label="blu"];
example -> baz [label="ble"];
example -> darjeeling [label="bla"];
into
bar -> example [label="blu", dir=back];
baz -> example [label="ble", dir=back];
darjeeling -> example [label="bla", dir=back];
or into
example -> bar [label="blu", constraint=false];
example -> baz [label="ble", constraint=false];
example -> darjeeling [label="bla", constraint=false];
(and change the height of example)
You'll get

How to modify OUTPUT font type?

Is it possible to change the OUTPUT font type instead of the default one? How?
This is my default stylesheet: http://filefactory.com/file/cfc2cb0/n/blueOutput.nb
Thanks!
The problem lies in StandardForm not respecting the FontFamily option, although it does seem to respect most other font options. Sjoerd's answer used TraditionalForm output and thus worked. You can see this problem if you run
SetOptions[EvaluationNotebook[], StyleDefinitions -> Notebook[{
Cell[StyleData[StyleDefinitions -> "Default.nb"]],
Cell[StyleData["Output"],
FontColor -> RGBColor[0, 0, .5], FontSize -> 14,
FontFamily -> "Symbol", FontWeight -> "Bold"]}]]
Then compare
{1 + 1, "abc", Sin[x]} (* This is by default in StandardForm *)
{1 + 1, "abc", Sin[x]} // StandardForm
{1 + 1, "abc", Sin[x]} // OutputForm
{1 + 1, "abc", Sin[x]} // TraditionalForm
You can also look at
Dynamic[CurrentValue/#{FontFamily, FontWeight, FontSize}]
Dynamic[CurrentValue/#{FontFamily, FontWeight, FontSize}] // TraditionalForm
which shows that the CurrentValue of FontFamily "seen" in the output depends on the output format.
Unfortunately, I don't see how to get around this issue...
Just go to the Format > Edit Stylesheet... menu. Then in the private style definitions sheet that pops-up choose 'Output' from the pull-down menu and change the looks of the resulting Output cell. This stylesheet will be stored with your open notebook.
In light of Simon's answer, you could force output printing in a certain style using $PrePrint.
$PrePrint = Style[#, FontFamily -> "Symbol"] &;
{1 + 1, "abc", Sin[x]}
You can do this by redefining the StandardForm style which is used for Output style by default (see the DefaultFormatType option in the Output style):
SetOptions[EvaluationNotebook[],
StyleDefinitions ->
Notebook[{Cell[StyleData[StyleDefinitions -> "Default.nb"]],
Cell[StyleData["StandardForm"],
FontFamily -> "Palatino Linotype"]},
StyleDefinitions -> "PrivateStylesheetFormatting.nb"]]
But Input style in this case is also affected because it is based on the StandardForm style too...
You could try wrapping your inputs using the Style[] command. For example:
test="This is a test string.";
Style[test,{Red,"Title"}]
This generates the string in my style sheet's 'title' settings in the colour red. The solution of changing your Stylesheets is obviously preferable to this, but this might be a quick and dirty temporary workaround.

Getting CellDingbat to remember its state between Mathematica sessions

I have modified my notebook's stylesheet to include a StyleData["Todo"] that inherits from StyleData["Item"]. It changes the cell dingbat to a checkbox. In the stylesheet editor:
Cell[StyleData["ToDo", StyleDefinitions -> StyleData["Item"]],
CellDingbat->DynamicModuleBox[{$CellContext`color$$},
CheckboxBox[
Dynamic[$CellContext`color$$], {RGBColor[1, 0.5, 0],RGBColor[0,Rational[2, 3], 0]},
Background -> Dynamic[$CellContext`color$$]],
DynamicModuleValues :> {}
],
]
The problem is that the state of the checkbox, when used in a notebook, is not saved between Mathematica sessions. I thought the DynamicModule[] would do the trick. How do I get the checkbox to remember its state?
EDIT
Simon's solution does save the state of the checkbox, but the checkbox is clipped when used as a CellDingbat (MacOS X). Putting Simon's code in a CellFrameLabels options does the trick, and also keeps the default "Item" CellDingbat. Here is what I've gone with:
Cell[StyleData["ToDo", StyleDefinitions -> StyleData["Item"]],
CellFrameLabels->{{
ButtonBox[
CheckboxBox[False], ButtonFunction :> (SelectionMove[
ButtonNotebook[], All, ButtonCell];
With[{$CellContext`new = ReplaceAll[
Options[
NotebookSelection[
ButtonNotebook[]], CellFrameLabels], CheckboxBox[
Pattern[$CellContext`x,
Alternatives[True, False]]] :> CheckboxBox[
Not[$CellContext`x]]]},
SetOptions[
NotebookSelection[
ButtonNotebook[]], $CellContext`new]]; SelectionMove[
ButtonNotebook[], After, CellContents]), Appearance -> None,
Method -> "Preemptive", Evaluator -> Automatic], None}, {
None, None}},
MenuSortingValue->1621]
The problem with your code (I think) is that a new DynamicModule does not get created each time you create a new "ToDo" cell. So there is nowhere that the state of each Checkbox can get saved.
The simplest solution I could think of for storing the state of the Checkbox for each "ToDo" cell is to overwrite the CellDingbat the first time that the Checkbox is activated.
(Other options I played with were using TaggingRules,
toggling between "ToDo" and "ToDone" styles, etc...)
However, even a plain Checkbox in a CellDingbat does not store its state - try running the following then cycle the output through a Show Expression cycle.
CellPrint[Cell["test", "Text", CellDingbat -> ToBoxes[Checkbox[]]]]
To get around this, I used Checkbox with the definite argument True or False wrapped up in a button that changes the state. This is stupid and inefficient, but it works!
So, my code for the cell style
Cell[StyleData["ToDo", StyleDefinitions -> StyleData["Item"]],
CellDingbat -> ButtonBox[CheckboxBox[False],
ButtonFunction :> (SelectionMove[ButtonNotebook[], All, ButtonCell];
With[{$CellContext`new = ReplaceAll[
Options[NotebookSelection[ButtonNotebook[]], CellDingbat],
CheckboxBox[Pattern[$CellContext`x, Alternatives[True, False]]] :> CheckboxBox[Not[$CellContext`x]]]},
SetOptions[NotebookSelection[ButtonNotebook[]], $CellContext`new]];
SelectionMove[ButtonNotebook[], After, CellContents]),
Appearance -> None, Method -> "Preemptive", Evaluator -> Automatic]]
I'm not happy with this solution, but it's the best I've come up with. An improvement would be to move the button function code out of the cell so that it is not repeated for every checked ToDo cell. Also to make it run without a ReplaceAll so that the kernel is not needed and the function can be run using just the frontend.

How to delete unnecessary options from Notebook[]?

By default Notebook[] has a small set of Options:
In[4]:= Options[EvaluationNotebook[]]
Out[4]= {FrontEndVersion ->
"7.0 for Microsoft Windows (32-bit) (February 18, 2009)",
StyleDefinitions -> "Default.nb",
WindowMargins -> {{0, Automatic}, {Automatic, 0}},
WindowSize -> {616, 537}}
Sometimes I wish to modify Notebook appearance and set additional Options. For example I like to have comments to be Plain rather than Bold:
SetOptions[EvaluationNotebook[],
AutoStyleOptions -> {"CommentStyle" -> {FontWeight -> Plain,
FontColor -> GrayLevel[0.6`], ShowAutoStyles -> False,
ShowSyntaxStyles -> False, AutoNumberFormatting -> False}}]
Now Options[EvaluationNotebook[]] will return also new option I have set.
But sometimes I wish to restore default behavior and delete additional Options. How can I do that?
Igor's answer is almost right. To remove the options set by
SetOptions[EvaluationNotebook[],
AutoStyleOptions -> {"CommentStyle" -> {FontWeight -> Plain,
FontColor -> GrayLevel[0.6`], ShowAutoStyles -> False,
ShowSyntaxStyles -> False, AutoNumberFormatting -> False}}]
You need to run
SetOptions[EvaluationNotebook[],
AutoStyleOptions -> {"CommentStyle" -> Inherited}]
But this only works for options that are standard and have a default to inherit (if it's a cell then from the enclosing section or notebook, if it's a notebook then from the stylesheet). What if you make up your own option, e.g.
Protect[HiddenData];
SetOptions[EvaluationNotebook[], HiddenData -> {"here's a string"}]
I don't know how to programmatically remove this option.
Edit:
Actually, to remove the HiddenData option created above, I can use something like
NotebookPut[DeleteCases[NotebookGet[EvaluationNotebook[]],
$CellContext`HiddenData -> _],
EvaluationNotebook[]]
Edit 2:
Mr Wizard asked how to remove all user-set notebook options. Assuming that this means all options that can't be inherited, then I believe that the following should work:
NotebookPut[
With[{nb = NotebookGet[EvaluationNotebook[]], opts = Options[Notebook][[All, 1]]},
Prepend[Select[Rest#nb, MemberQ[opts, First[#]] &], First#nb]],
EvaluationNotebook[]]
But maybe there are options associated with the StyleSheet that I've ignored...
If he meant how do you get back to your system's default notebook options - then you can just delete all notebook options:
NotebookPut[Notebook[First#NotebookGet[EvaluationNotebook[]]],
EvaluationNotebook[]]
(1) Select Format -> Options Inspector (or Shift+Ctrl+O on Windows)
(2) For the two fields next to "Show option values" select Notebook and as text
(3) Select and delete all text in the box below
(4) Click Apply
After understanding NotebookGet, I believe this works for full options reset.
NotebookPut[
Notebook#First#NotebookGet[EvaluationNotebook[]],
EvaluationNotebook[]]
Use:
SetOptions[EvaluationNotebook[], Background -> Inherited]
Igor

Resources