Things that are described graphically are easier to comprehend than textual descriptions, right? What is most important regarding comprehensibility is the alignment of the concepts that need to be conveyed with the abstractions in the language. A well-designed textual notation can go a long way. Of course, for certain kinds of information, a graphical notation is better: relationships between entities, the timing/sequence of events or some kind of signal/data flow. On the contrary, rendering expressions graphically is a dead end. When deciding about a suitable notation, you might want to consider the following two forces: in most (but not all!) tool environments, editors for textual notations (incl. code completion, syntax highlighting and the like) are much easier to build and evolve than really user-friendly and scalable graphical editors. Also, instead of using full-blown graphical editing, you might want to consider textual editing plus graphical visualization (read only, auto-layout, created via transformation). In many cases, this is absolutely good enough.
This part of the documentation explains how to visualize models via Graphviz.
Graphviz is an open source tool that rendes images based on a textual description of a graph. It is quite powerful and widely used. It is available on many platforms. Please download it from www.graphviz.org and install it on your machine.
In order to visualize a model, you have to write a model to model
transformation from your DSL meta model to the meta model of the input
language for Graphviz. The oAW Graphviz support comes with this meta
model, it's name is dot. After running the
transformation for a given input model, you have to call a code generator
(also supplied with the oAW Graphviz integration plugins) that generates
the text representation of the dot file. This generator also generates a
batch file processdot.bat
(and a shell script
processdot.sh
) that contains calls to the
dot.exe
renderer to generate the actual GIF images.
To make that batch file work, make sure you set the
GRAPHVIZ_BIN environment variable to point to the
bin
directory of your Graphviz installation.
The metamodel of the dot language is shown in the figure below. The diagram was generated with the Graphviz visualization itself, using the transformation described in the previous section.
This section describes the types of the dot language. Features are denoted by a qualifier "T", which has the following meaning:
P | Optional property. |
P1 | Mandatory property. |
R | 0..1 reference. |
R1 | 1..1 reference. |
R* | 0..* reference. |
R+ | 1..* reference. |
EP | An extension function with zero or one argument. It can be treated like a property except that the function must called with brackets(). The function can be called on elements of the specified type. The extension is provided by dotlib. |
O | An extension function that takes at least one additional argument besides the caller argument. This function behaves like an operation. The extension is provided by dotlib. |
This is the root element containing graph instances.
Table 32. dot::graphvizmodel features
T | name | type / arguments | description |
---|---|---|---|
R* | graphs | dot::graph | Contained graphs. |
O | addGraph | dot::graph | The graph instance to add to the model. |
O | addGraphs | Collection[dot::graph] | A collection of graphs to add to the model. |
This element represents a named graph instance.
Supertype: EObject
Table 33. dot::graph features
T | name | type / arguments | description |
---|---|---|---|
P1 | name | String | The name of the graph. |
P1 | type | graphtype | Specifies whether a graph is directed (graphtype::digraph) or undirected (graphtype::graph). |
P | strict | EBoolean | A graph may be declared a strict digraph. This forbids the creation of self-arcs and multi-edges. |
R* | stmts | dot::stmt | Statements defining this graph. |
O | setFont | String | Sets the default font for the graph. |
O | addStatement | dot::stmt | Adds a statement to the graph. |
O | addStatements | List[dot::stmt] | Adds the given statements to the graph. |
EP | filename | String | The filename for the resulting dot file: "<name>.dot" |
O | setAttribute | String name String value | Sets an edge attribute. The attribute's value. |
This is the base class for statement types.
Supertype: EObject
Subtypes: edge_stmt_node, edge_stmt_subgraph, node_stmt, attribute, attr_stmt, subgraph
Abstract: true
Represents a node in the graph.
Supertype: stmt
Table 34. dot::node_stmt features
T | name | type | description |
---|---|---|---|
P | name | String | Node name. |
R | port | dot::port | |
R* | attributes | dot::attr_list | Attributes of this element. |
O | setStyle | String | Set style property of the node. |
O | setFont | String | Sets the font for the node label. |
O | setFontSize | String | Sets the font size. |
O | setLabel | String | Sets the node label. |
O | setLabel | List[String] | Sets the node label which consists of several sections. This helps to create record layouts. |
O | setShape | String | Sets the node shape style. |
O | setName | String | Sets the node's name. |
O | setFillColor | String | Sets the fill color. |
O | setAttribute | String name String value | Sets an edge attribute. The attribute's value. |
This is an edge
Supertype: stmt
Table 35. dot::edge_stmt_node features
T | name | type / arguments | description |
---|---|---|---|
R | node_id | node_id | Node identifier. |
R* | edgeRHS | dot::edgeRHS | |
R* | attributes | dot::attr_list | Attributes of this element. |
O | setArrowHead | String | Sets the arrow head style. |
O | setArrowTail | String | Sets the arrow tail style. |
O | setStyle | String | Sets the edge's style property. |
O | setWeight | String | Sets the line weight. |
O | setColor | String | Sets the line and font color. |
O | setFontcolor | String | Sets the font color. |
O | setFont | String | Sets the font. |
O | setFontSize | String | Sets the font size. |
O | setLabel | String | Sets the edge label. |
O | setHeadLabel | String | Sets the label for the edge's head. |
O | setTailLabel | String | Sets the label for the edge's tail. |
O | setLineColor | String | Sets the line color. |
O | setAttribute | String name String value | Sets an edge attribute. The attribute's value. |
Supertype: stmt
Table 36. dot::attribute features
T | name | type | description |
---|---|---|---|
P | name | String | Attribute name. |
P | value | String | Holds the attribute's value. |
Supertype: stmt
Table 37. dot::attr_stmt features
T | name | type | description |
---|---|---|---|
P | type | dot::attributetype | Attribute type. |
R* | attributes | dot::attr_list | Attributes of this element. |
Supertype: stmt
Table 38. dot::edge_stmt_subgraph features
T | name | type | description |
---|---|---|---|
R | subgraph | dot::subgraph | The referenced subgraph. |
R | edgeRHS | dot::edgeRHS | |
R* | attributes | dot::attr_list | Attributes of this element. |
Supertype: EObject
Supertype: EObject
Represents the target an edge is pointing to.
Supertype: EObject
Supertype: edgeRHS
Supertype: edgeRHS
Supertype: stmt
Table 44. dot::subgraph features
T | name | type / arguments | description |
---|---|---|---|
P | name | String | The name of the subgraph. |
R* | stmts | dot::stmt | Statements defining this graph. |
O | setName | String | Sets the subgraph's name. |
O | addStatement | dot::stmt | Adds a statement to the subgraph. |
O | addStatements | List[dot::stmt] | Adds the given statements to the subgraph. |
O | setLabel | String | Sets the subgraph's label. |
O | setAttribute | String name String value | Sets an edge attribute. The attribute's value. |
Context: edgeRHS#op
Context: graph#graphtype
Table 48. dot::graphtype enum literals
name | description |
---|---|
directed | Directed graph. |
undirected | Undirected graph. |
Context: attr_stmt#type
Table 49. dot::attributetype enum literals
name | description |
---|---|
graph | Attribute denotes a graph. |
node | Attribute denotes a node. |
edge | Attribute denotes an edge. |
Table 50. dot::compass_pt enum literals
name | description |
---|---|
north | Direction north. |
northeast | Direction northeast. |
east | Direction east. |
southeast | Direction southeast. |
south | Direction south. |
southwest | Direction southwest. |
west | Direction west. |
northwest | Direction northwest. |
Table 53. Graphviz output formats
Name | Description | Name | Description |
---|---|---|---|
bmp | Windows Bitmap Format | canon | |
dot | DOT | xdot | DOT |
dia | Dia format | eps | Encapsulated PostScript |
fig | FIG | gtk | GTK canvas |
gd gd2 | GD/GD2 formats | gif | GIF |
hpgl | HP-GL/2 | ico | Icon Image File Format |
imap imap_np cmapx cmapx_np | Server-side and client-side imagemaps | jpg jpeg jpe | JPEG |
mif | FrameMaker MIF format | mp | MetaPost |
pcl | PCL | Portable Document Format (PDF) | |
pic | PIC | plain plain-ext | Simple text format |
png | Portable Network Graphics format | ps | PostScript |
ps2 | PostScript for PDF | svg svgz | Scalable Vector Graphics |
tga | Truevision Targa Format (TGA) | tif tiff | TIFF (Tag Image File Format) |
vml vmlz | Vector Markup Language (VML) | vrml | VRML |
vtx | Visual Thought format | wbmp | Wireless BitMap format |
xlib | Xlib canvas |
To invoke the transformation (and subsequently generate the dot text
files) you need to write a workflow that calls into the
model2dotfile.oaw
workflow supplied with the oAW
Graphviz integration.
<workflow> <property name="modelFile" value="platform:/resource/org.openarchitectureware.graphviz.ecoredemo/model/Ecore.ecore"/> <property name="targetDir" value="src-gen/" /> <component id="read" class="org.eclipse.mwe.emf.Reader"> <useSingleGlobalResourceSet value="true"/> <modelSlot value="model"/> <uri value="${modelFile}"/> </component> <cartridge file="model2dotfile.oaw" targetDir="${targetDir}" topFunctionCallExpression="ecore2dot::toGraphVizmodel(model)" inheritAll="true"/> </workflow>
The model2dotfile.oaw
workflow has some
configuration parameters described in the table below.
Table 54. model2dotfile.oaw
configuration
properties
name | description | default | example |
---|---|---|---|
targetDir | Output directory of resulting .dot
files and processdot[.bat|.sh] | src-gen | |
dotTargetDir | Output directory of images produced by Graphviz when
calling the generated processdot.[bat|sh]
command. | . | src-gen/images |
topFunctionCallExpression | This is the qualified path to the Xtend function to call to perform the M2M transformation. |
| |
pathToDotExe | The absolute path to the dot executable, only the directory the executable is contained in. Note that the default will only work on Windows. If the dot executable is already on your system path you can set this property to an empty string. | %GRAPHVIZ_BIN%/ | /usr/local/
|
outputFormat | Graphviz output format. Valid options see output formats. | gif |
You may want to include the SystemCommand
workflow component into your workflow to execute the processing of dot
files after their generation.
<!-- Mac/Linux --> <component class="oaw.util.stdlib.SystemCommand"> <directory value="src-gen"/> <command value="sh"/> <arg value="processdot.sh"/> </component> <!-- Windows --> <component class="oaw.util.stdlib.SystemCommand"> <directory value="src-gen"/> <command value="cmd"/> <arg value="/c"/> <arg value="processdot.sh"/> </component>
The following is an example transformation, extensively commented. It visualizes meta models (i.e. any .ecore file).
// this is the source meta model - ecore for the example here import ecore; // this is the target meta model; dot is the language to // create graphviz graphs import dot; // there's a number of utility functions for working with the // dot meta model extension dotlib; // top level, we create graphvizmodel which contains // a number of graphs, each eventually resulting in its // own dot file, and GIF image create dot::graphvizmodel toGraphVizmodel(EPackage p): // you can add a number of graphs. Here, we add // only one. addGraph( toGraph(p) ) ;
// mapping a model element to a graph uses the mapToGraph // function from dotlib. All those mapping functions need // to be cached to make sure that if they are called several // times they are evaluated only once. cached toGraph(EPackage p): // creates the actual graph object p.mapToGraph() // each graph needs to have a name; // will result in the filename for the dot // and gif files for the graph .setName( "ecoremetamodel" ) // a graph contains statements. Statements // can be nodes, edges or subgraphs. Here we // add a subgraph for the package. .addStatement( p.toSubgraph() ) ;
cached toSubgraph( EPackage p ): // this call maps the package to a subgraph.... p.mapToSubgraph() // every subgraph MUST have a name - very important! .setName("ecore") // this is the label shown in the diagram .setLabel("ecore") // again, we cann add statements to graphs: // nodes, edges and additional subgraphs. // here we add a node for each class in the EPackage .addStatements( p.classes().toNode() ) // and then we create an edge for each reference // of an EClass to another EClass. .addStatements( p.classes().eReferences.select(r|EClass.isInstance(r.eType)).toRefEdge() ) // finally, we create an edge for the inheritance // relationships. Note the difference in the coding // between the implementation for the referneces // and for the inheritance. The difference is that // for the reference there's an object (an instance // of EReference) in the source model. For the in- // heritance thing, there isn't. .addStatements( p.classes().addSuperclassEdges() ) ;
// create a Node for an EClass cached toNode( EClass c ): // this one creates the actual node object c.mapToNode() // the record shape is special, it can have // several "compartments", like the UML class // symbol. That's what we need here. .setShape("record") // sets the label, using the special { and } character // do define compartments in the record shape. .setLabel( "{"+c.name+"|"+c.eAttributes.collect(a|a.name+": "+a.eType.name).toString("\\n")+"}" ) // sets the style to bold lines and filled .setStyle("bold, filled") // fill color, obviously .setFillColor("grey") // and line color. .setLineColor( "black" ) ;
// creates an edge for an EReference cached toRefEdge( EReference r ): // creates the actual edge. Parameters // are source node, target node, and the // edge node itself mapToDirectedEdge( r.eContainer, r.eType, r ) // the label on the edge .setLabel( r.name ) // the label at the target end of the // line .setHeadLabel( " "+r.lowerBound.toString() + ".." + r.upperBound.toString() ) // set the arrow head type .setArrowHead("vee") // and use a diamond shape at the tail of // the arrow if it's a containment relaitonship .setArrowTail( r.containment ? "diamond" : "none" ) ;
// this one is used to iterate over all the superclasses // for a given class. In a very real sense, the only // reson for this function is to declare a variable // name for base! addSuperclassEdges( EClass base ): // call toSuperclassEdge for all supertypes of // a given base clas base.eSuperTypes.toSuperclassEdge( base ) ; // creates a direct edge for an inheritance relationship cached toSuperclassEdge( EClass super, EClass base ): // creates the actual edge. Parameters are // source node, target node and the node for // the edge itself (here: null) mapToDirectedEdge( base, super, null ) // sets the arrowhead to be the // "UML inheritance arrow" .setArrowHead("empty") ; // helper function returning all the EClasses // in an EPackage classes(EPackage p): p.eClassifiers.typeSelect(EClass);
You can now run the generated processdot.bat
or
processdot.sh
to render the actual images.
This reference cannot cover a complete description of Graphviz and the dot language. So it is recommended to have the respective reference documents by hand to be able to use the full power of this library. See these links for further reading:
The Graphviz homepage.
www.graphviz.org/doc/info/lang.html
The DOT language. A definition of the DOT abstract grammar.
http://www.graphviz.org/doc/info/attrs.html
Node, Edge and Graph Attributes reference.
A user guide for DOT. Recommended reading.
http://sourceforge.net/projects/eclipsegraphviz
An Eclipse plugin which provides a viewer for DOT graphs.