Quick Tour

from gvdot import Dot, Markup, Port, Nonce

Class Dot is a DOT language builder. Method graph() establishes or amends graph attributes. node() and edge() define and amend nodes and edges. Method subgraph() defines or amends subgraphs, returning an instance of Block, the base class of Dot. Most builder methods are actually Block methods.

Code

dot = Dot(directed=True)
dot.graph(label="Basic Construction", rankdir="LR")
dot.node("a", label="Node A", shape="box")
dot.node("b", label="Node B")
dot.edge("a", "b", style="dashed", color="blue")
dot.edge("b", "c", label=" B/C ")
block = dot.subgraph("cluster_1")
block.graph(style="rounded", color="orange")
block.node("c", style="filled", color="orange")
block.edge("c","d")
dot.node("b", penwidth=1.75)        # Amend node b
dot.edge("b", "c", labelfloat=True) # Amend b -> c

DOT language
representation

digraph {

    rankdir=LR

    a [label="Node A" shape=box]
    b [label="Node B" penwidth=1.75]

    a -> b [style=dashed color=blue]
    b -> c [label=" B/C " labelfloat=true]

    subgraph cluster_1 {
        style=rounded
        color=orange
        c [style=filled color=orange]
        c -> d
    }

    label="Basic Construction"
}

Rendered

_images/basic-construction.svg

str(dot) returns a Dot object’s DOT language representation. Dot invokes Graphviz programs with that representation as input, rendering to files (save()), image bytes (to_rendered()), or SVG strings (to_svg()). In notebooks, show() and show_source() display rendered SVG and DOT language.

Use anywhere

dot.save("images/basic.png")          # Write to file
data = dot.to_rendered(format="jpg")  # Get image bytes
svg = dot.to_svg()                    # Get SVG
print(dot)                            # Print DOT language

Use in notebooks

dot.show()         # Display rendered SVG
dot.show_source()  # Display DOT language

Methods graph_default(), node_default(), and edge_default() establish or amend default attributes for graphs, nodes, and edges.

Code

dot = Dot()
dot.graph_default(labelloc="t", rankdir="LR", bgcolor="antiquewhite")
dot.node_default(shape="circle", fontsize=10, margin=0)
dot.edge_default(fontsize=8, fontcolor="green")
dot.graph(label="Choices")
dot.node(1, label="First")
dot.node(2, label="Second")
dot.node(3, label="Third")
dot.node("distraction", shape="diamond")
dot.edge(1, 2, label="steady")
dot.edge(2, 3, label="progress")
dot.edge(1, "distraction")

DOT language
representation

graph {

    graph [labelloc=t rankdir=LR bgcolor=antiquewhite]
    node [shape=circle fontsize=10 margin=0]
    edge [fontsize=8 fontcolor=green]

    1 [label="First"]
    2 [label="Second"]
    3 [label="Third"]
    distraction [shape=diamond]

    1 -- 2 [label="steady"]
    2 -- 3 [label="progress"]
    1 -- distraction

    label="Choices"
}

Rendered

_images/default-attributes.svg

A role is a named collection of attribute values. Methods graph_role(), node_role(), and edge_role() define or amend roles. Assigning a role name to an element’s role attribute causes that element to inherit the role’s attribute values.

Code

dot = Dot(directed=True).graph(rankdir="LR")
dot.graph_role("library", cluster=True, bgcolor="gray80", penwidth=0)
dot.node_role("header", shape="box", fillcolor="orange")
dot.node_role("source", shape="box", fillcolor="cyan2")
dot.node_role("executable", shape="hexagon", fillcolor="green", margin=0.02)
dot.edge_role("include", color="orange", penwidth=2)
dot.edge_role("link", color="green", penwidth=2)
dot.node_default(style="filled", width=0, height=0,
                 fontsize=10, fontname="monospace")
block = dot.subgraph().graph(role="library")
block.node("interactor.h", role="header")
block.node("interactor.cpp", role="source")
block.edge("interactor.h", "interactor.cpp", role="include")
dot.node("model.h", role="header")
dot.node("main.cpp", role="source")
dot.node("server", role="executable")
dot.edge("model.h", "main.cpp", role="include")
dot.edge("interactor.h", "main.cpp", role="include")
dot.edge("main.cpp", "server", role="link")
dot.edge("interactor.cpp", "server", role="link")

DOT language
representation

digraph {

    node [style=filled width=0 height=0 fontsize=10 fontname=monospace]

    rankdir=LR

    "model.h" [shape=box fillcolor=orange]
    "main.cpp" [shape=box fillcolor=cyan2]
    server [shape=hexagon fillcolor=green margin=0.02]

    "model.h" -> "main.cpp" [color=orange penwidth=2]
    "interactor.h" -> "main.cpp" [color=orange penwidth=2]
    "main.cpp" -> server [color=green penwidth=2]
    "interactor.cpp" -> server [color=green penwidth=2]

    subgraph {
        cluster=true
        bgcolor=gray80
        penwidth=0
        "interactor.h" [shape=box fillcolor=orange]
        "interactor.cpp" [shape=box fillcolor=cyan2]
        "interactor.h" -> "interactor.cpp" [color=orange penwidth=2]
    }
}

Rendered

_images/roles.svg

A theme is a normal Dot object from which other Dot objects inherit graph attributes, default attributes, and roles. Method use_theme() establishes the inheritance relationship.

Code

list_theme = Dot()
list_theme.all_default(penwidth=1.25)
list_theme.node_default(shape="box", width=0, height=0, style="filled")
list_theme.edge_default(arrowsize=0.75)
list_theme.node_role("element", margin=0.05, fillcolor="khaki")
list_theme.node_role("nil", label="NIL", fontname="sans-serif",
                     fontsize=8, margin=0.02)
list_theme.edge_role("link", color="#333")
list_theme.edge_role("nil", style="dashed")
list_theme.graph(rankdir="LR")

dot = Dot(directed=True)
dot.use_theme(list_theme)
dot.node("Fred", role="element")
dot.node("Wilma", role="element")
dot.node("Betty", role="element")
dot.node("Barney", role="element")
dot.edge("Fred", "Wilma", role="link")
dot.edge("Wilma", "Betty", role="link")
dot.edge("Betty", "Barney", role="link")
dot.edge("Barney", "nil", role="nil")
dot.node("nil", role="nil")

DOT language
representation

digraph {

    graph [penwidth=1.25]
    node [penwidth=1.25 shape=box width=0 height=0 style=filled]
    edge [penwidth=1.25 arrowsize=0.75]

    rankdir=LR

    Fred [margin=0.05 fillcolor=khaki]
    Wilma [margin=0.05 fillcolor=khaki]
    Betty [margin=0.05 fillcolor=khaki]
    Barney [margin=0.05 fillcolor=khaki]
    nil [label="NIL" fontname="sans-serif" fontsize=8 margin=0.02]

    Fred -> Wilma [color="#333"]
    Wilma -> Betty [color="#333"]
    Betty -> Barney [color="#333"]
    Barney -> nil [style=dashed]
}

Rendered

_images/themes.svg

Most methods return self, enabling chained method calls.

Code

dot = Dot().graph(rankdir="LR").node_default(width=0, height=0)
dot.node("a", shape="circle").node("b",shape="diamond")
dot.edge("a","b")

DOT language
representation

graph {
    node [width=0 height=0]
    rankdir=LR
    a [shape=circle]
    b [shape=diamond]
    a -- b
}

Rendered

_images/method-chaining.svg

A Nonce is a placeholder for a unique identifier generated by Dot. Those generated identifiers will not conflict with any others, either generated or explicitly provided.

Code

theme = Dot()
theme.node_default(shape="plain")
theme.edge_default(arrowhead="none")
theme.node_role("anchor", label="", width=.10, height=.10,
                style="filled", shape="square")

dot = Dot(directed=True).use_theme(theme)
source = Nonce()
sink = Nonce()
dot.node(source, role="anchor")
dot.node(sink, role="anchor")
dot.edge(source,"A").edge("A",sink)
dot.edge(source,"B").edge("B",sink)
dot.edge(source,"C").edge("C",sink)

DOT language
representation

digraph {

    node [shape=plain]
    edge [arrowhead=none]

    _nonce_1 [label="" width=0.1 height=0.1 style=filled shape=square]
    _nonce_2 [label="" width=0.1 height=0.1 style=filled shape=square]

    _nonce_1 -> A
    A -> _nonce_2
    _nonce_1 -> B
    B -> _nonce_2
    _nonce_1 -> C
    C -> _nonce_2
}

Rendered

_images/nonces.svg

Applications use Markup to delineate Graphviz HTML strings.

Code

dot = Dot()
dot.graph(rankdir="LR", label=Markup(
    '<b>Graphviz HTML Strings</b><br/>are supported'))
dot.node(1,label=Markup('x<sub><font point-size="10">1</font></sub>'))
dot.node(2,label=Markup('x<sub><font point-size="10">2</font></sub>'))
dot.edge(1,2)

DOT language
representation

graph {
    rankdir=LR
    1 [label=<x<sub><font point-size="10">1</font></sub>>]
    2 [label=<x<sub><font point-size="10">2</font></sub>>]
    1 -- 2
    label=<<b>Graphviz HTML Strings</b><br/>are supported>
}

Rendered

_images/markup.svg

An edge endpoint can be a Port.

Code

dot = Dot(directed=True)
dot.graph(rankdir="LR")
dot.node_default(shape="record")
dot.node("node1", label="First|<link>next")
dot.node("node2", label="Second|<link>next")
dot.node("node3", label="Third|<link>next")
dot.edge(Port("node1","link", "s"), Port("node2", cp="w"))
dot.edge(Port("node2","link"), Port("node3", cp="s"))
dot.edge(Port("node3","link"), Port("node1", cp="ne"))

DOT language
representation

digraph {
    node [shape=record]
    rankdir=LR
    node1 [label="First|<link>next"]
    node2 [label="Second|<link>next"]
    node3 [label="Third|<link>next"]
    node1:link:s -> node2:w
    node2:link -> node3:s
    node3:link -> node1:ne
}

Rendered

_images/ports.svg

Dot constructor argument multigraph=True enables multiple edges between endpoints. Discriminants allow those edges to be amended.

Code

dot = Dot(multigraph=True).graph(rankdir="LR")
dot.edge("a", "b", label="One")
dot.edge("a", "b", label="Two", color="red")
dot.edge("a", "b", "x", label="Three", style="dashed")
dot.edge("a", "b", "x", color="blue", penwidth=2.5) # Amend third edge

DOT language
representation

graph {
    rankdir=LR
    a -- b [label="One"]
    a -- b [label="Two" color=red]
    a -- b [label="Three" style=dashed color=blue penwidth=2.5]
}

Rendered

_images/multigraphs.svg

Keep in Mind

While several Dot methods correspond to DOT language statements, gvdot is not a DOT language format printer, streaming out DOT language statements with every call.

Instead, applications build Graphviz diagrams structurally starting with a Dot object. When finished, they save or render a DOT language representation of that object. Method call order is for the most part irrelevant, and amendments to already defined elements do not create additional DOT language statements; they change the one statement ultimately emitted.

Similarly, roles, themes, and nonces are not resolved until a DOT language representation is required, and those resolutions are ephemeral — further changes to the Dot object, roles, or themes can lead to different resolutions if a DOT language representation is required again.


This tour is available as a notebook on GitHub.