Graphviz Legend/Key with Nodes

user2904448 picture user2904448 · Oct 21, 2013 · Viewed 7.6k times · Source

I am trying to create a legend/key in Graphviz that contains, not just text, but nodes and edges. While I've read this post, the HTML table does not seem to work with what I am trying to do.

Right now, the code I am using is:

digraph G {
fontname="Helvetica";
labelloc=t;
rankdir=LR;
label="Course Graph";

node[style=filled, fontname="Helvetica", colorscheme=greens3, color=1];

subgraph cluster_key {
    rank=min;

    label="Key";
    rankdir=LR;

    kc1[label="Course", peripheries=2, color=2];
    k1[shape=plaintext, style=solid, label="Required Course"]
    prereq[label="Course 1"];
    kc2[label="Course 2"];
    prereq->kc2;
    k2[shape=plaintext, style=solid, label="Course 1 is a prerequisite for Course 2"]
    coreq1[label="Course 1"];
    coreq2[label="Course 2"];
    coreq1->coreq2[dir=both];
    k3[shape=plaintext, style=solid, label="Course 1 and Course 2 are corequisite"]

    or[style="dashed", color="black", shape="diamond", label="OR"];
    or1[label="Course 1"];
    or1 -> or[style="dashed", dir="none"];
    or2[label="Course 2"];
    or2 -> or[style="dashed", dir="none"];
    kc3[label="Course 3"]
    or->kc3;
    k4[shape=plaintext, style=solid, label="You must take either Course 1 OR\nCourse 2 before taking Course 3"]
    { rank=min;k1 k2 k3 k4 }
}

c3[color=3, peripheries=2];
c4[color=3, peripheries=2];

c1->c2[dir=both];
c2->c3;

c4_reqs[style="dashed", color="black", shape="diamond", label="OR"];
c4_reqs->c4;
c2->c4_reqs[style="dashed", dir="none"];
c5->c4_reqs[style="dashed", dir="none"];

}

The result of this code is:

The result of this code is

but I would like something more like this - preferably sized smaller:

ebut I would like something more like

Answer

Potherca picture Potherca · Oct 23, 2013

You weren't far off. With some minor adjustments I got the following result:

enter image description here

The most important change I made was use rank=source instead of rank=min to get the nodes lined up correctly.

To fix the text alignment I used \r to align the text to the right (\l does the same but to the left) and give all of the plaintext nodes the same width.

The entire code looks like this (I added some comments where I made the changes):

digraph G {
    fontname="Helvetica";
    labelloc=t;
    rankdir=LR;
    label="Course Graph";

    node[style=filled, fontname="Helvetica", colorscheme=greens3, color=1];

    subgraph cluster_key {
        //rank=min; /* this doesn't really do anything for you */

        label="Key";
        //rankdir=LR; /* this is also not needed*/

        kc1[label="Course", peripheries=2, color=2];
        k1[shape=plaintext, style=solid, label="Required Course\r", width=3.5] // Add fixed width so all nodes line up

        prereq[label="Course 1"];
        kc2[label="Course 2"];
        prereq->kc2;
        k2[shape=plaintext, style=solid, label="Course 1 is a prerequisite for Course 2\r", width=3.5]  // Add fixed width

        coreq1[label="Course 1"];
        coreq2[label="Course 2"];
        coreq1->coreq2[dir=both];
        k3[shape=plaintext, style=solid, label="Course 1 and Course 2 are corequisite\r", width=3.5]    // Add fixed width

        or[style="dashed", color="black", shape="diamond", label="OR"];
        or1[label="Course 1"];
        or1 -> or[style="dashed", dir="none"];
        or2[label="Course 2"];
        or2 -> or[style="dashed", dir="none"];
        kc3[label="Course 3"]
        or->kc3;
        k4[shape=plaintext, style=solid, label="You must take either Course 1 OR\rCourse 2 before taking Course 3\r", width=3.5] // Add fixed width

        { rank=source;k1 k2 k3 k4 } // Use "source in stead of min
    }

    c3[color=3, peripheries=2];
    c4[color=3, peripheries=2];

    c1->c2[dir=both];
    c2->c3;

    c4_reqs[style="dashed", color="black", shape="diamond", label="OR"];
    c4_reqs->c4;
    c2->c4_reqs[style="dashed", dir="none"];
    c5->c4_reqs[style="dashed", dir="none"];

}

On a side note, the code could be cleaned up a bit by placing all of the plaintext nodes together, so attributes wouldn't have to be declared more often. This would have the added benefit of the nodes and rank attribute not being split into different parts in the code:

    { 
        rank=source
        node [shape=plaintext, style=solid, width=3.5]

        k1 [label="Required Course\r"]
        k2 [label="Course 1 is a prerequisite for Course 2\r"]
        k3 [label="Course 1 and Course 2 are corequisite\r"]
        k4 [label="You must take either Course 1 OR\rCourse 2 before taking Course 3\r"]
    }