Skip to content

Visualization with GraphVIZ DOT

Malte Isberner edited this page May 9, 2013 · 9 revisions

Visualization with GraphVIZ DOT

AutomataLib provides a very convenient way of visualizing automata and graphs, using the well-known GraphVIZ DOT tool. Visualization here means both exporting them to a DOT file, which can be processed for rendering by external tools (such as those distributed with GraphVIZ), and also rendering and displaying them directly from your application using a Java interface. This page will guide you on how to accomplish this.

Impatient readers interested in application only may skip right to the example.

Prerequisites

In order to use DOT for visualizing automata and graphs, the GraphVIZ software has to be installed on your machine (downloads page). Additionally, the dot (dot.exe on Windows) utility has to be installed in a directory contained in the PATH environment variable.

Customizing the Rendering

The central interface for customizing how an automaton or graph is rendered is GraphDOTHelper (source, javadoc) from the automata-core artifact. This interface declares four methods:

  • writePreamble() can be used to write arbitrary GraphVIZ statements before the actual body of the graph is written (but after the opening digraph {). This could, for example, include additional nodes.
  • writePostamble() can be used to write arbitrary GraphVIZ statements after the actual body of the graph has been written. In this method, nodes (states) from the graph (automaton) can be referenced by a mapping providing their ID, which is not possible in the writePreamble method.
  • getStateProperties() allows to define GraphVIZ properties for single nodes (states), or signal to suppress rendering them by returning false. For example, invoking properties.put(SHAPE, "box") will lead to the current node being rendered as a rectangle instead of a circle.
  • getEdgeProperties() allows to define GraphVIZ properties for single edges (transitions), or signal to suppress rendering them by returning false. For example, invoking properties.put("style", "dashed") will lead to the respective edge being drawn using a dashed line.

DOTPlottableGraphs

A graph can be annotated with information about how it prefers to be rendered. This is accomplished by implementing the DOTPlottableGraph (source, javadoc) interface, declared in the automata-core artifact. This interface extends the Graph interface by declaring one additional method, getGraphDOTHelper(), which is used to obtain a GraphDOTHelper for rendering this graph.

Rendering an Automaton or Graph Object to DOT

Transforming an Automaton or Graph object to a DOT description is handled by the GraphDOT (source, javadoc) utility class. The procedure slightly differs, depending on whether an Automaton or a Graph should be rendered, and whether or not this comes with instructions how it prefers to be rendered.

All of the methods mentioned below take a parameter of type Appendable, to which the DOT description is written. Appendable is a very lean interface, implemented by most of the Java framework classes appropriate for this goal, like StringBuilder, BufferedWriter and so on.

Rendering Graphs

As the name "GraphVIZ" suggests, the DOT format describes graphs, not automata. Rendering Graphs therefore is the much easier case.

  • write(DOTPlottableGraph<N,E> graph, Appendable a, ...) is the straightforward case, where a DOTPlottableGraph providing its own GraphDOTHelper is translated to DOT.
  • write(Graph<N,E> graph, Appendable a, ...) works for every Graph reference. This method employs reflection to check if the Graph object passed is an instance of a DOTPlottableGraph. If so, the respective DOT helper will be used; otherwise, a standard helper will be used.
  • write(Graph<N,E> graph, GraphDOTHelper<N,? super E> helper, Appendable a, ...) is used to explicitly specify a GraphDOTHelper. Note: For DOTPlottableGraphs, the shipped helper is ignored.

Rendering Automata

As stated above, the DOT format describes graphs. Rendering automata is accomplished by internally translating them to a Graph representation, if necessary. Note that since the Automaton interfaces provides no explicit input alphabet, the inputs to be considered when rendering have to be manually provided.

  • write(Automaton<S,I,T> automaton, GraphDOTHelper<S,? super Pair<I,T>> helper, Collection<? extends I> inputs, Appendable a, ...) renders an automaton using the supplied GraphDOTHelper. The automaton is translated into a graph as described [here](Automata to Graph Conversion).
  • write(Automaton<S,I,T> automaton, Collection<? extends I> inputs, Appendable a, ...) renders an automaton using either a specialized helper (obtained from automata implementing the DOTPlottableAutomaton (source, javadoc) interface), or a default helper for rendering automata. The automaton is translated into a graph as described [here](Automata to Graph Conversion).

Further Customization

You might have noticed the ellipsis (...) in most of the methods mentioned above. In fact, all those method come with an additional varargs parameter called additionalHelpers of type GraphDOTHelper<N,? super E>[]. These parameter can be used to specify a sequence of GraphDOTHelpers for further customization. GraphVIZ properties for nodes and edges are aggregated by subsequently calling getXXXProperties() on each helper (in the order they are being passed). If one of these invocations return false, the respective node or edge is not rendered. The writePreamble and writePostamble methods are handled in a similar fashion.

Note that while properties set by previous helpers may be overridden or even completely removed by invoking properties.clear(), it is not possible for any of the additional helpers to revert a possible rendering suppression by a previous (including the builtin, if the graph is a DOTPlottableGraph).

Visualizing DOT in Your Application

The class DOT (source, javadoc) from the automata-commons-dotutil artifact provides several methods that facilitate interaction with the external dot program. However, at this point we just want to focus on the most convenient way: by creating a special Writer object (note that Writer as a subclass of Appendable can be passed to the GraphDOT.write(...) methods mentioned above).

This Writer can be used to write arbitrary GraphVIZ data to. Its close() method, however, triggers the actual DOT rendering to be performed and opens a window displaying the rendering result (or a message box, if there were errors during rendering). The Writer can be instantiated by a call to DOT.createDotWriter(boolean modal). The mandatory boolean parameter indicates whether or not the window shall be modal or not. In the former case, the call to close() will block, and execution (in the calling thread) will not proceed until the window is closed.

Example

The following listing shows how a simple plottable graph can be visualized in a modal window.

DOTPlottableGraph<?,?> graph = ...;

Writer w = DOT.createDOTWriter(true); // true indicates that the dialog is modal
GraphDOT.write(graph, w); // Requires handling of IOException!
w.close(); // Causes the visualization window to appear. Note that since the dialog
           // was set to be modal, this call will block until the window is closed.
Clone this wiki locally