I have a very long linear (not many branches) flowchart that shows up in graphviz as either too tall to fit on a single page, or too wide (if direction was left to right)
Is there an easy way to have graphviz lay out the graph in such a way that it goes Left to right, then down, then right to left, then down? (I hope this explains it well).
Something like this (drawn in visio)
It's actually quite easy to get exactly what you want:
digraph so
{
node[ shape = square ];
{ rank = same; 1 2 3 }
{ rank = same; 6 5 4 }
{ rank = same; 7 8 }
1 -> 2 -> 3;
3 -> 4;
6 -> 5 -> 4 [ dir = back ];
6 -> 7;
7 -> 8;
}
yields
rank = same makes sure that the boxes defined here stay side by side; without that they would be aligned vertically.
Since the boxes are drawn left to right in the order they are defined, it's necessary to define them the way done above for the 2nd row.
That's also the reason for having the arrows in the middle row pointing backward - in reality the edge goes from 6 to 5 and from 5 to 4.
From here you can start fine tuning - labels in the boxes instead of the numbers, longer edges, colors...
Related
I'm attempting to draw some CFGs showing the internal node structure as well as the control edges between subgraphs.
In the image you can see how the thick back-edge that goes from JUMP to ENTRY takes a very sharp turn and goes through the subgraph itself. Likewise you can see back-edges from t19 snake itself through the basic block (subgraph) itself, rather than going on the outside.
The problem I'm trying to solve is to make the back-edges go on the outside of the subgraphs, but my immediate concern is finding a way to enforce a lower turn-rate which allows me to make edges that can't "turn on a dime".
The code generating the edges:
g0op14->g1op0[color=black, weight = 5, penwidth=5, tailport=s, headport=n];
g0op14->g2op0[color=black, weight = 5, penwidth=5, tailport=s, headport=n];
g1op8->g3op0[color=black, weight = 5, penwidth=5, tailport=s, headport=n];
g3op15->g2op0[color=black, weight = 5, penwidth=5, tailport=s, headport=n];
// Misbehaving edge below.
g3op15->g3op0[color=black, weight = 5, penwidth=5, tailport=s, headport=n, constraint = false];
g0op8->g1op1[color=black, tailport=s, headport=n];
On a meta-level, I'm not sure how to input images in my question. The way they're laid out now make them take up way too much space, I'd like to display them as clickable thumbnails instead of as enormous images inline.
This is my first real question, so feedback on how to make it more useful is appreciated.
The full CFG:
I'm looking to have a series of nodes in a row, joined by an edge. This works fine when the graph's rankdir is set to TB or BT, but it rearranges the nodes when I set it to LR or RL so they're no longer next to each other. Example images are included.
I've taken my code and stripped it down to it's minimum point for demonstration. The code is the same for both of the following graphs, aside from line 2 (which specifies rankdir):
digraph{
rankdir=LR;
node[shape=box,fontcolor=white,color=black,fillcolor=black,style=filled];
edge[dir=none,color=black];
Josh -> JoshParent;
JoshParent -> Hero;
JoshParent[shape=circle,label="",height=0.0001,width=0.0001];
{
rank=same;
Kae[label="Kae"];
Hero[label="Hero"];
Kae -> Hero;
}
Kae -> KaeParent;
Hero -> HeroParent;
KaeParent -> Liz;
KaeParent[shape=circle,label="",height=0.0001,width=0.0001];
HeroParent -> George;
HeroParent[shape=circle,label="",height=0.0001,width=0.0001];
{
rank=same;
George[label="George"];
Liz[label="Liz"];
Ocean[label="Ocean"];
Egg[label="Egg"];
Liz -> Ocean -> Egg;
}
}
This is what's shown with rankdir=TB:
This is what's shown with rankdir=LR:
As you can see, from the LR image, the nodes have been drawn in the order "Ocean, George, Egg", rather than "Ocean, Egg, George" as it is with the TB image.
You can force the order by adding an explicit but invisible edge from Egg to George:
Liz -> Ocean -> Egg; // last line of your code
Egg -> George[ style = invis ]; // additional edge
This produces
I don't have an explanation for the different behaviour between TB and LR, though.
Given the position of a Bishop on an 8 * 8 chessboard, the task is to count the total number of squares that can be visited by the Bishop in one move. The position of the Bishop is denoted using row and column number of the chessboard.
Examples:
Input: Row = 4, Column = 4
Output: 13
Input: Row = 1, Column = 1
Output: 7
Approach: In the game of chess, a Bishop can only move diagonally and there is no restriction in distance for each move.
So, We can also say that Bishop can move in four ways i.e. diagonally top left, top right, bottom left and bottom right from current position.
We can calculate the numbers of squares visited in each move by:
Total squares visited in Top Left move = Math.min(r, c) – 1
Total squares visited in Top Right move = Math.min(r, 9 – c) – 1
Total squares visited in Bottom Left move = 8 – Math.max(r, 9 – c)
Total squares visited in Bottom Right move = 8 – Math.max(r, c)
where, r and c are the coordinates of the current position of the Bishop on the chessboard.
Guys I cannot figure out the logic behind the above diagonal calculations. Please help me find out that by what logic the diagonals are calculated above ??? I JUST NEED THE LOGIC. No code required.
( Also If you can help with the basic behind logic of similar kinds of chess problems or matrix it would be fantastic)
Chessboard image for reference
The top-left distance to the edge of the board is indeed min(r, c) - 1. Given that the bishop starts on rank r, it can move up no more than r - 1 ranks before landing on the first rank. It may hit the first file before that if c < r, in which case it will only be able to move c - 1 squares. For example if the bishop starts at r = 5 and c = 4, it will be able to move three squares, not four. Thus the top-left formula is min(r - 1, c - 1), which can be refactored to min(r, c) - 1.
Similarly, when heading towards the bottom-left corner, the rank increases while the file decreases. The bishop can move at most 8 - r ranks and at most c - 1 files, so the bottom-left formula is min(8 - r, c - 1). That can be refactored to 8 – max(r, 9 – c), although this expression seems more convoluted.
To count elements in the left-top and right-bottom sides of the diagonal (in which Bishop is placed), the following formula is enough:
n-abs(r-c)-1, where n is the size of the board e.g. n=8 in the above case.
So three (instead of four) formulae can give all the cells that Bishop can visit diagonally:
[8-abs(r-c)-1] + [Math.min(r, 9 – c) – 1] + [8 – Math.max(r, 9 – c)]
simply apply this formula for any directions: distance = max(abs(x1 - x2), abs(y1 - y2))
I have a strange result trying to make a simple graph using graphviz. Two arrows are drawn between 3 and 4 instead of one. I can't figure out why, if it is a bug or if I've done something wrong. Here is a minimal example, anything I remove makes the problem dissapear:
digraph dia {
newrank=true;
1 -> 2;
subgraph cluster_1 {
label = "1";
3 -> 5;
3 -> 6;
5 -> 6
}
subgraph cluster_2 {
label = "2";
4;
}
3 -> 4;
{rank="same"; 2; 5; 6;}
{rank="same"; 3; 4}
}
It produces the following output:
My actual graph is larger than that, and I need newrank property.
I think I have the lastest version of graphviz...
dot - graphviz version 2.40.1 (20161225.0304)
Thanks for any help !
I also noticed some strange things going on in graphviz when clusters are being used (especially in combination with rank=same. So probably a bug, yes.
In your situation simply adding a port to one of the problematic nodes fixes the problem:
3:e -> 4;
I understand the dynamic programming solution to the Box Stacking problem, which tries to find the maximum possible length of a stack that can be formed by a given set of boxes, that can be rotated in any direction, such that the lower box is always lesser in width and length as compared to a box that is higher in the stack.
However, I haven't been able to understand why only 3 orientations are required for every box. According to me, the number of orientations should be 6. That is, for each of the three dimensions taken as height, you should have two combinations.
An online resource shows the following as the method to create the three orientations(2 rotations) of the original box.
/* Create an array of all rotations of given boxes
For example, for a box {1, 2, 3}, we consider three
instances{{1, 2, 3}, {2, 1, 3}, {3, 1, 2}} */
Box rot[3*n];
int index = 0;
for (int i = 0; i < n; i++)
{
// Copy the original box
rot[index] = arr[i];
index++;
// First rotation of box
rot[index].h = arr[i].w;
rot[index].d = max(arr[i].h, arr[i].d);
rot[index].w = min(arr[i].h, arr[i].d);
index++;
// Second rotation of box
rot[index].h = arr[i].d;
rot[index].d = max(arr[i].h, arr[i].w);
rot[index].w = min(arr[i].h, arr[i].w);
index++;
}
So, For example, for a box {1, 2, 3}, the three orientations would be
1 2 3
2 1 3
3 1 2
But according to me, the orientations should be
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
I understand that my extra three combinations are due to alternating length and width between them keeping the height same. So, whereas I conside 1 2 3 and 1 3 2 to be different, the original algorithm considers them to be the sam.
However, I feel that, in this problem h,l,w and h,w,l, should be treated as two separate orientations since a box say, l=3,w=4,h=5 could be stacked above a box say, l=4,w=5,h=6, but not above a box l=5,w=4,h=6
What you said is absolutely right we could take 6 orientations of the box, but the thing is we can make do with just 3 orientations of the box.
This is so because we impose the rule that given the height,width and length of a box, we shall treat the smaller of the two base dimensions as the width.
In other words, given a box with dimensions x > y > z, we'll consider orientations:
h=x, l=y, w=z
h=y, l=x, w=z
h=z, l=x, w=y
But not orientations such as:
h=x, l=z, w=y
h=y, l=z, w=x
h=z, l=y, w=x
This is merely to simplify the representation of the boxes.
Even in the link you have specified they have written,
for simplicity of solution, always keep w<=d:
struct Box
{
// h –> height, w –> width, d –> depth
int h, w, d; // for simplicity of solution, always keep w <= d
};
Now that we have imposed this constraint on the data we can see that your original problem has been resolved i.e.
However, I feel that, in this problem h,l,w and h,w,l, should be treated as two separate orientations since a box say, l=3,w=4,h=5 could be stacked above a box say, l=4,w=5,h=6, but not above a box l=5,w=4,h=6
For example, if there were two boxes
h1,w1,l1 (Box1)
and
h2,w2,l2 (Box2)
we know w1<l1(because we have imposed that restriction) so if by chance w1>w2 we know automatically l1> w2,and thus the other box configuration(where you said w and l should be swapped and considered as a separate configuration) is not required.
Just think about it, i am sure you'll understand why we use just 3 configurations.