How to create an edge from a node to a subgraph in Graphviz Dot?
Asked Answered
T

2

7

I want to create a graph that looks like this, i. e. where an edge goes from the node Manufacturer of means of production to the subgraph with the same name.

Expected result

I wrote the following code for this:

digraph G {
    rankdir=LR;
    compound=true;

    graph [fontname="Liberation Mono"];
    node [fontname="Liberation Mono"];
    edge [fontname="Liberation Mono"];

    subgraph cluster0 {
        label="System components";
        mmp [label="Manufacturer of means of production", shape=box];
    }

    subgraph cluster1 {
        t1start [label="Start of tact 1", shape=point]
        t1end [label="End of tact 1", shape=point ]
        subgraph cluster1_mmp {
            label="Manufacturer of means of production"

            cluster1_1 [label="Node 1", color=white]


            subgraph cluster1_1_1 {
                label="Technological cycle 1"

                cluster1_1_1 [label="Node 2", color=white]
            }
            subgraph cluster1_1_2 {
                label="Technological cycle 2"

                cluster1_1_2 [label="Node 2", color=white]
            }
        }
    }

    subgraph cluster2 {
        label="Такт 2"
        t2start [label="Start of tact 2", shape=point]
        t2end [label="End of tact 2", shape=point]

    }
    t1end -> t2start
    mmp -> cluster1_1 [ltail=cluster1_mmp]; 
}

If I try to compile this code ("C:\Program Files (x86)\Graphviz2.38\bin\"dot.exe -Tpng -ograph.png graph.dot ), I get the warning Warning: mmp -> cluster1_1: tail not inside tail cluster cluster1_mmp.

How can I fix it and make the edge go to the subgraph?

Update 1:

Below you can find the image of the expected result -- an edge that goes from a node to a subgraph (subgraph, not a node inside the subgraph). This edge is red in the image below.

Expected result

Update 2: Changed the code like shown below.

digraph G {
    rankdir=LR;
    compound=true;

    graph [fontname="Liberation Mono"];
    node [fontname="Liberation Mono"];
    edge [fontname="Liberation Mono"];

    subgraph cluster0 {
        label="System components";
        mmp [label="Manufacturer of means of production", shape=box];
    }

    subgraph cluster1 {
        t1start [label="Start of tact 1", shape=point]
        t1end [label="End of tact 1", shape=point ]
        subgraph cluster1_mmp {
            label="Manufacturer of means of production"

            testNode [label="Node 1", color=white]

            subgraph cluster1_1_1 {
                label="Technological cycle 1"

                cluster1_1_1 [label="Node 2", color=white]
            }
            subgraph cluster1_1_2 {
                label="Technological cycle 2"

                cluster1_1_2 [label="Node 2", color=white]
            }
        }
    }

    subgraph cluster2 {
        label="Такт 2"
        t2start [label="Start of tact 2", shape=point]
        t2end [label="End of tact 2", shape=point]

    }
    t1end -> t2start
    mmp -> cluster1 [ltail=cluster0, lhead=cluster1, label="           "];

}

Second attempt

Trottier answered 13/4, 2018 at 9:33 Comment(4)
Can you please show with a red colored line what you expect? Its a bit unclear to meBagwell
See update 1. I want an edge to go from a node to a subgraph.Trottier
Have you tried with mmp -> cluster1_1_2 [lhead=cluster1] instead of mmp -> cluster1_1 [ltail=cluster1_mmp];? It should do the job I believeBagwell
Won't work if you forget (like me) compound=true;Bystander
B
6

You need to change your last line

mmp -> cluster1_1 [ltail=cluster1_mmp];

to

mmp -> cluster1_1 [lhead=cluster1 label="           "]

And then the graph comes as expected

Issue fixed

Also if you want the edge to start from outside the box then you would do

mmp -> cluster1_1 [ltail=cluster0 lhead=cluster1 label="           "];

Box outside

Edit

The final code used

digraph G {
    rankdir=LR;
    compound=true;

    graph [fontname="Liberation Mono"];
    node [fontname="Liberation Mono"];
    edge [fontname="Liberation Mono"];

    subgraph cluster0 {
        label="System components";
        mmp [label="Manufacturer of means of production", shape=box];
    }

    subgraph cluster1 {
        t1start [label="Start of tact 1", shape=point]
        t1end [label="End of tact 1", shape=point ]
        subgraph cluster1_mmp {
            label="Manufacturer of means of production"

            cluster1_1 [label="Node 1", color=white]


            subgraph cluster1_1_1 {
                label="Technological cycle 1"

                cluster1_1_1 [label="Node 2", color=white]
            }
            subgraph cluster1_1_2 {
                label="Technological cycle 2"

                cluster1_1_2 [label="Node 2", color=white]
            }
        }
    }

    subgraph cluster2 {
        label="Такт 2"
        t2start [label="Start of tact 2", shape=point]
        t2end [label="End of tact 2", shape=point]

    }
    t1end -> t2start
    mmp -> cluster1_1 [lhead=cluster1 label="           "]
}

The fiddle link for the same

Fiddle

Bagwell answered 20/4, 2018 at 14:2 Comment(1)
I tried out your solution, but it still doesn't work (see update 2). I assume there is more code that needs to be changed. Please look at update 2 and tell me, what exactly needs to be changed (in addition to the line mentioned in your answer).Trottier
R
0

Urm, did you just mean "lhead=cluster1_mmp" rather than ltail?

Your edge is specified as:

mmp -> cluster1_1 [ltail=cluster1_mmp]; 

The error message you have is "Warning: mmp -> cluster1_1: tail not inside tail cluster cluster1_mmp"

This says that your tail is not inside the tail cluster. The tail cluster is cluster1_mmp. cluster1_1, which is what you're trying to connect to is definitely inside cluster1_mmp. This explains your confusion.

Only after much investigation with a GraphvizFiddle did I eventually remember that with an arrow the pointy end is the head (that is, the syntax is tail -> head).

So, cluster1_1, the node you're trying to says is in cluster1_mmp is the head of the arrow. That's why your ltail specification isn't working. Changing it to lhead gets rid of the error message and generates a graph that looks like your picture. The arrow goes to the subgraph, exactly what you asked for in your question.

Here's are two GraphvizFiddles, one of the original code generating the original error and one with ltail changed to lhead which matches your picture.

(I'm sure I've spent ages debugging the same problem in my own graphs. Perhaps Graphviz could get an update to check if the the ltail parameter would make sense for the arrow head and vice versa and spit out a more helpful error message.)

Rea answered 18/4, 2018 at 19:56 Comment(2)
Please don't post comments as answers. Earn rep and then comment.Onaonager
Thanks for the feedback. You're both right that my original answer was so short it looked like a comment. It was always genuinely an answer and I had tested it before I posted. I've updated the answer to give a much longer explanation as to why I think changing ltail to lhead fixes the bug in the original code and generates the graph the original question asked for.Rea

© 2022 - 2024 — McMap. All rights reserved.