Adding key or legend?

I’m a new GraphViz user, so maybe I’m missing something obvious. I’m working on a graph that (currently) has about 100 nodes. Is there a way to add a key or legend on the bottom of the graph, to show what the different shapes and colors mean? I have a label, but I’d like more than that.

My current solution is a second graph that I import as a node image. I’m working on a timeline, so I have a list of years down the left side of the graph, and I put an extra node at the bottom and rank my legend with that node. Unfortunately, it shows up on the left side of the graph rather then centered with the graph label. I tried using impagepos=bc, but that seems to center the image in the node, not the graph. Is there a way to force the image to be centered, or a way to force the node to be the entire width of the graph (then maybe imagepos will work)?

Another issue is that my graph is top-to-bottom, but I’d like the legend to be left-to-right. Am I correct in thinking GraphViz doesn’t support that?

Is there a more elegant solution than using a second graph?

3 Likes

Is this what you are after?

digraph l {
  subgraph clusterMain {
	graph [labelloc="b" labeljust="r" label=<
	<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
	<TR><TD>left 1</TD><TD>right 1</TD></TR>
	<TR><TD>left 2</TD><TD>right 2</TD></TR>	</TABLE>>];
  a -> b -> c
  "more nodes and edges"
}
}

legend2

2 Likes

Thank you for the suggestion. Using a subgraph allowed me make a nice legend. The end result wasn’t quite what I had envisioned, but it’s a more elegant solution that what I had been trying.

1 Like

Unless I am missing something, you don’t need to use a subgraph. You can do the same thing in the root graph. So if you can encode your key using an Html-like string, you should be set.

2 Likes

I failed to show why I used the cluster - by doing so I can have a key and a (root) graph title.

1 Like

Gotcha. By the way, I have often used the approach mentioned by Gibson, especially when the additional material can’t be represented in an HTML-like string, such as using node shapes as keys. A simple gvpr script can be used to put the pieces together. As a colleague once said, “People don’t want to draw graphs; they want to draw diagrams that might include graphs.” Since Graphviz just does graphs, there will always be a need for other tools to provide the missing pieces.

My key contains nodes, edges, an HTML table and a few lines of text. I wasn’t able to get all of the elements to line up properly in a box until Steve recommended using a subgraph. That made everything come together very nicely. I’d hoped to have it at the bottom right of the graph, which it isn’t, but it looks better than I had anticipated.

Hello!
I would insert some text lines at the bottom left of the graph. Can you explain me a simple way to do that?
Thank you

Use graph-level label, labelloc, and labeljust. I added newlines for spacing.

digraph l {
	graph [labelloc="b" labeljust="l" label="\nthe slow green frog made\nmany millions of dollars"];
	
  a -> b -> c
  "more nodes and edges"
}

Gives:
textatbottom1

To answer a question you didn’t ask and to embellish Steve’s reply, in addition to text, a label can also be an HTML-like label. This can allow you to add a fairly rich table or list to serve as a key to the graph image. HTML-like labels can also contain images, so you can create an image using some other tool and then import that into the label.

1 Like

You can draw additional invisible edges and node(s) at the bottom of the diagram and set them the same rank as the legend (also need to turn on the newrank attribute for graph). By adjusting the height and width of the invisible node(s), you can move the legend to the desired distance.

An image that shows the invisible:

Final image:

Script:

digraph {    
    newrank=true // enable ranking between nodes and clusters
    
    a->b->c
    
    subgraph clusterLegend { 
    rank = sink;
    label = "Legend";
    fontsize = 20
    node [ color="white" ]
    {rank=same; key; key2}
    key [ label=<<table border="0" cellpadding="2" cellspacing="0" cellborder="0">
      <tr><td align="right" port="i1">A</td></tr>
      <tr><td align="right" port="i2">A</td></tr>
      </table>> ]
    key2 [ label=<<table border="0" cellpadding="2" cellspacing="0" cellborder="0">
      <tr><td align="left" port="i1">B</td><td>     The reason for A is B</td></tr>
      <tr><td align="left" port="i2">B</td><td>     The solution for A is B</td></tr>
      </table>>]
    key:i1 -> key2:i1 
    key:i2 -> key2:i2 [ arrowhead="odiamond" style=dashed ]
    }
   
   // Invisible nodes and edges
    d [style=invis width=5 height=5]
    c->d [style=invis]
   
   // Setting a same rank between cluster and invisible node
   {rank=same;key;key2;d;}
}
1 Like

I’m new to the forum but I’m a long time Graphviz user. I’m late to this thread but I see that it is still getting sporadic replies so I just wanted to post what I did a while back to implement a legend / key for my graphs / diagrams. I used subgraph / cluster with multiple nodes that consisted of HTML labels. In my case, I have three separate nodes and then linked them together. It isn’t the best solution but I think it ended up working well. For the most part, it stays out of the way of my main diagram content.

Note that the code won’t render the images since they are local for me.

Enjoy!

Here is the output:

Here is the code:

digraph diagram_ApplicationContext_app_283 {
    // Graph & cluster attributes
    graph [
        colorscheme = pastel28
        compound = true // allows edges between clusters
        fillcolor = 6
        fontname = verdana
        fontsize = 8
        // TODO - Need to move this path out to app.config / make it work with wiki
        imagepath = "C:\Users\..."
        labeljust = l // aligns label to the left
        labelloc = t // puts label at top of diagram
        newrank = true
        nodesep = .25 // separation between nodes in inches (default is 0.25
        overlap = false // prism is also interesting
        rankdir = LR // LR (left-to-right) or TB (top-to-bottom)
        ranksep = 0.75 // separation between ranks in inches (default is 0.5)
        ratio = auto // aspect ratio. diagram is tighter when it is declared
        shape = box
        splines = true // uses curved lines to avoid nodes
        style = "filled"
    ]

    // Node attributes
    node [
        colorscheme = pastel28
        fillcolor = 8
        fontname = verdana
        fontsize = 8
        margin = "0.1, 0.05"
        shape = box
        style = "filled, rounded"
    ]

    // Edge attributes
    edge [
        arrowsize = 0.7
        color = gray40
        penwidth = 0.7
    ]

    subgraph cluster_legend {
        id = legend
        colorscheme = x11
        fillcolor = white
        label = <<b>Legend</b>>
        margin = 0
        pencolor = gray70
        style = filled

        legend_entities [
            shape = plaintext
            style = "" // leave blank to revert to the normal default styles
            label = <
                <table border="0" cellborder="0" cellspacing="0" >
                    <tr>
                        <td align="left" colspan="2"><font point-size="7"><b>Level</b></font></td>
                        <td align="left"><font point-size="7"> <b>In-Focus</b> </font></td>
                        <td align="left"><font point-size="7"> <b>External</b> </font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/area-16px.png" /></td>
                        <td align="left"><font point-size="7">Area</font></td>
                        <td><img src="/icons/area-in.png" /></td>
                        <td><img src="/icons/area-out.png" /></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/platform-16px.png" /></td>
                        <td align="left"><font point-size="7">Platform</font></td>
                        <td><img src="/icons/platform-in.png" /></td>
                        <td><img src="/icons/platform-out.png" /></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/system-16px.png" /></td>
                        <td align="left"><font point-size="7">System</font></td>
                        <td><img src="/icons/system-in.png" /></td>
                        <td><img src="/icons/system-out.png" /></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/tier-16px.png" /></td>
                        <td align="left"><font point-size="7">Tier</font></td>
                        <td><img src="/icons/tier-in.png" /></td>
                        <td><img src="/icons/tier-out.png" /></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/web-application-16px.png" /></td>
                        <td align="left"><font point-size="7">Application</font></td>
                        <td><img src="/icons/application-in.png" /></td>
                        <td><img src="/icons/application-out.png" /></td>
                    </tr>
                </table>
            >
        ]

        legend_apptypes [
            shape = "plaintext"
            style = "" // leave blank to revert to the normal default styles
            label = <
                <table border="0" cellborder="0" cellspacing="0" >
                    <tr>
                        <td align="left" colspan="4"><font point-size="7"><b>Application Types</b></font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/batch-16px.png" /></td>
                        <td align="left"><font point-size="7">Batch</font></td>
                        <td><img src="/icons/database-16px.png" /></td>
                        <td align="left"><font point-size="7">Database</font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/email-16px.png" /></td>
                        <td align="left"><font point-size="7">Email</font></td>
                        <td><img src="/icons/file-system-16px.png" /></td>
                        <td align="left"><font point-size="7">File System</font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/other-16px.png" /></td>
                        <td align="left"><font point-size="7">Other</font></td>
                        <td><img src="/icons/report-16px.png" /></td>
                        <td align="left"><font point-size="7">Reports</font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/service-fabric-16px.png" /></td>
                        <td align="left"><font point-size="7">Service Fabric</font></td>
                        <td><img src="/icons/url-route-16px.png" /></td>
                        <td align="left"><font point-size="7">URL Route</font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/web-application-16px.png" /></td>
                        <td align="left"><font point-size="7">Web Application</font></td>
                        <td><img src="/icons/web-service-16px.png" /></td>
                        <td align="left"><font point-size="7">Web Service</font></td>
                    </tr>
                </table>
            >
        ]

        legend_linetypes [
            shape = "plaintext"
            style = "" // leave blank to revert to the normal default styles
            label = <
                <table border="0" cellborder="0" cellspacing="0" >
                    <tr>
                        <td align="left" colspan="2"><font point-size="7"><b>Line Types</b></font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/line-solid-16px.png" /></td>
                        <td align="left"><font point-size="7">Makes calls to</font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/line-dashed-16px.png" /></td>
                        <td align="left"><font point-size="7">Links to</font></td>
                    </tr>
                    <tr>
                        <td><img src="/icons/blank-16px.png" /></td>
                        <td align="left"> </td>
                    </tr>
                    <tr>
                        <td><img src="/icons/blank-16px.png" /></td>
                        <td align="left"> </td>
                    </tr>
                    <tr>
                        <td><img src="/icons/blank-16px.png" /></td>
                        <td align="left"> </td>
                    </tr>
                </table>
            >
        ]

        legend_entities -> legend_apptypes [style=invis]
        legend_apptypes -> legend_linetypes [style=invis]
    }


    label = <
        <table border="0" cellborder="0" cellspacing="0">
            <tr>
                <td align="left"><b>Application Context Diagram for SomeApplication [Batch]</b></td>
            </tr>
            <tr>
                <td align="left">Generated: 1/5/2023 1:30:15 PM</td>
            </tr>
            <tr>
                <td align="left">File: ACD for SomeApplication [Batch].png</td>
            </tr>
        </table>
    >
    subgraph cluster_area_1 {
        fillcolor = "1"
        label = <
            <table border="0" cellspacing="0" cellborder="0">
                <tr>
                    <td><img src="/icons/area-24px.png" /></td>
                    <td align="left">SomeArea</td>
                </tr>
            </table>
        >
        style = "filled"
        URL = "/Diagram/Render/AreaContext/1"

        subgraph cluster_plat_5 {
            fillcolor = "5"
            label = <
                <table border="0" cellspacing="0" cellborder="0">
                    <tr>
                        <td><img src="/icons/platform-24px.png" /></td>
                        <td align="left">SomePlatform</td>
                    </tr>
                </table>
            >
            style = "filled"
            URL = "/Diagram/Render/PlatformContext/5"

            subgraph cluster_sys_91 {
                fillcolor = "3"
                label = <
                    <table border="0" cellspacing="0" cellborder="0">
                        <tr>
                            <td><img src="/icons/system-24px.png" /></td>
                            <td align="left">SomeSystem</td>
                        </tr>
                    </table>
                >
                style = "filled, rounded"
                URL = "/Diagram/Render/SystemApplications/91"

                subgraph cluster_tier_1 {
                    fillcolor = "/slategray1"
                    label = <
                        <table border="0" cellspacing="0" cellborder="0">
                            <tr>
                                <td><img src="/icons/tier-24px.png" /></td>
                                <td align="left">Batch<br/>(POBA)</td>
                            </tr>
                        </table>
                    >
                    style = "filled, dashed"
                    URL = "/Diagram/Render/SystemTierContext/1"

                app_283_ [
                    fillcolor = "4"
                    label = <
                        <table border="0" cellspacing="0" cellborder="0">
                            <tr>
                                <td><img src="/icons/Batch-24px.png" /></td>
                                <td align="left"><b>SomeApplication<br/>[Batch]</b></td>
                            </tr>
                        </table>
                    >
                    id = "app_283_"
                    shape = "box3d"
                    style = "bold, filled"
                    URL = "/Diagram/Render/ApplicationContext/283"
                ]
                }
            }
        }
    }
    subgraph cluster_area_5 {
        fillcolor = "2"
        label = <
            <table border="0" cellspacing="0" cellborder="0">
                <tr>
                    <td><img src="/icons/area-24px.png" /></td>
                    <td align="left">Technology<br/>Infrastructure <br/>(TI)</td>
                </tr>
            </table>
        >
        style = "filled"
        URL = "/Diagram/Render/AreaContext/5"

        subgraph cluster_plat_6 {
            fillcolor = "6"
            label = <
                <table border="0" cellspacing="0" cellborder="0">
                    <tr>
                        <td><img src="/icons/platform-24px.png" /></td>
                        <td align="left">Microsoft 365 </td>
                    </tr>
                </table>
            >
            style = "filled"
            URL = "/Diagram/Render/PlatformContext/6"

            subgraph cluster_sys_33 {
                fillcolor = "8"
                label = <
                    <table border="0" cellspacing="0" cellborder="0">
                        <tr>
                            <td><img src="/icons/system-24px.png" /></td>
                            <td align="left">Exchange</td>
                        </tr>
                    </table>
                >
                style = "filled, rounded"
                URL = "/Diagram/Render/SystemApplications/33"

                app_20_ [
                    fillcolor = "7"
                    label = <
                        <table border="0" cellspacing="0" cellborder="0">
                            <tr>
                                <td><img src="/icons/Email-24px.png" /></td>
                                <td align="left">MAIL<br/>[Email]</td>
                            </tr>
                        </table>
                    >
                    id = "app_20_"
                    shape = "box3d"
                    style = "filled"
                    URL = "/Diagram/Render/ApplicationContext/20"
                ]
                }
        }
    }

    app_283_ -> app_20_ [id = "app_283_,app_20_", style="solid"]

    // A quirk of Graphviz is that the title is rendered last. So the easiest way
    // to format it is to change the attributes after everything else is rendered.
    graph[
        fontsize = 10
    ]
}
2 Likes

Just what I was looking for

Thanks!

1 Like