Visualization

Background
Graphviz
General Approach
dot language reference
Workflow configuration
Example Transformation
References

Background

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

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.

General Approach

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.

dot language reference

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.

Figure 36. Metamodel of the dot language

Metamodel of the dot language

Types

This section describes the types of the dot language. Features are denoted by a qualifier "T", which has the following meaning:

POptional property.
P1Mandatory property.
R0..1 reference.
R11..1 reference.
R*0..* reference.
R+1..* reference.
EPAn 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.
OAn 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.

dot::graphvizmodel

This is the root element containing graph instances.

Table 32. dot::graphvizmodel features

Tnametype / argumentsdescription
R*graphsdot::graphContained graphs.
OaddGraphdot::graphThe graph instance to add to the model.
OaddGraphsCollection[dot::graph]A collection of graphs to add to the model.


dot::graph

This element represents a named graph instance.

Supertype: EObject

Table 33. dot::graph features

Tnametype / argumentsdescription
P1nameStringThe name of the graph.
P1typegraphtypeSpecifies whether a graph is directed (graphtype::digraph) or undirected (graphtype::graph).
PstrictEBooleanA graph may be declared a strict digraph. This forbids the creation of self-arcs and multi-edges.
R*stmtsdot::stmtStatements defining this graph.
OsetFontStringSets the default font for the graph.
OaddStatementdot::stmtAdds a statement to the graph.
OaddStatementsList[dot::stmt]Adds the given statements to the graph.
EPfilenameStringThe filename for the resulting dot file: "<name>.dot"
OsetAttribute

String name

String value

Sets an edge attribute.

The attribute's value.


dot::stmt

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

dot::node_stmt

Represents a node in the graph.

Supertype: stmt

Table 34. dot::node_stmt features

Tnametypedescription
PnameStringNode name.
Rportdot::port 
R*attributesdot::attr_listAttributes of this element.
OsetStyleStringSet style property of the node.
OsetFontStringSets the font for the node label.
OsetFontSizeStringSets the font size.
OsetLabelStringSets the node label.
OsetLabelList[String]Sets the node label which consists of several sections. This helps to create record layouts.
OsetShapeStringSets the node shape style.
OsetNameStringSets the node's name.
OsetFillColorStringSets the fill color.
OsetAttribute

String name

String value

Sets an edge attribute.

The attribute's value.


dot::edge_stmt_node

This is an edge

Supertype: stmt

Table 35. dot::edge_stmt_node features

Tnametype / argumentsdescription
Rnode_idnode_idNode identifier.
R*edgeRHSdot::edgeRHS 
R*attributesdot::attr_listAttributes of this element.
OsetArrowHeadStringSets the arrow head style.
OsetArrowTailStringSets the arrow tail style.
OsetStyleStringSets the edge's style property.
OsetWeightStringSets the line weight.
OsetColorStringSets the line and font color.
OsetFontcolorStringSets the font color.
OsetFontStringSets the font.
OsetFontSizeStringSets the font size.
OsetLabelStringSets the edge label.
OsetHeadLabelStringSets the label for the edge's head.
OsetTailLabelStringSets the label for the edge's tail.
OsetLineColorStringSets the line color.
OsetAttribute

String name

String value

Sets an edge attribute.

The attribute's value.


dot::attribute

Supertype: stmt

Table 36. dot::attribute features

Tnametypedescription
PnameStringAttribute name.
PvalueStringHolds the attribute's value.

dot::attr_stmt

Supertype: stmt

Table 37. dot::attr_stmt features

Tnametypedescription
Ptypedot::attributetypeAttribute type.
R*attributesdot::attr_listAttributes of this element.


dot::edge_stmt_subgraph

Supertype: stmt

Table 38. dot::edge_stmt_subgraph features

Tnametypedescription
Rsubgraphdot::subgraphThe referenced subgraph.
RedgeRHSdot::edgeRHS 
R*attributesdot::attr_listAttributes of this element.

dot::attr_list

Supertype: EObject

Table 39. dot::attr_list features

Tnametypedescription
R*a_listdot::a_list 


dot::a_list

Supertype: EObject

Table 40. dot::a_list features

Tnametypedescription
PnameStringList name.
PvalueStringThe value.

dot::edgeRHS

Represents the target an edge is pointing to.

Supertype: EObject

Table 41. dot::edgeRHS features

Tnametypedescription
Ropdot::edgeopEdge operation.


dot::edgeRHS_node

Supertype: edgeRHS

Table 42. dot::edgeRHS_node features

Tnametypedescription
Rnodedot::node_idNode identifier.


dot::edgeRHS_subgraph

Supertype: edgeRHS

Table 43. dot::edgeRHD_subgraph features

Tnametypedescription
Rsubgraphdot::subgraphA subgraph.

dot::subgraph

Supertype: stmt

Table 44. dot::subgraph features

Tnametype / argumentsdescription
PnameStringThe name of the subgraph.
R*stmtsdot::stmtStatements defining this graph.
OsetNameStringSets the subgraph's name.
OaddStatementdot::stmtAdds a statement to the subgraph.
OaddStatementsList[dot::stmt]Adds the given statements to the subgraph.
OsetLabelStringSets the subgraph's label.
OsetAttribute

String name

String value

Sets an edge attribute.

The attribute's value.


dot::node_id

Supertype: EObject

Table 45. dot::node_id features

Tnametypedescription
PnameStringNode identifier value.
Rportdot::portNode port.


dot::port

Supertype: EObject

Table 46. dot::port features

Tnametypedescription
PnameStringThe name of the port.
Pcompass_ptdot::compass_ptWhere the port should be placed at the element.


Enumerations

dot::edgeop

Context: edgeRHS#op

Table 47. dot::edgeop enum literals

namedescription
directedDirected edge.
undirectedUndirected edge.

dot::graphtype

Context: graph#graphtype

Table 48. dot::graphtype enum literals

namedescription
directedDirected graph.
undirectedUndirected graph.


dot::attributetype

Context: attr_stmt#type

Table 49. dot::attributetype enum literals

namedescription
graphAttribute denotes a graph.
nodeAttribute denotes a node.
edgeAttribute denotes an edge.

dot::compass_pt

Table 50. dot::compass_pt enum literals

namedescription
northDirection north.
northeastDirection northeast.
eastDirection east.
southeastDirection southeast.
southDirection south.
southwestDirection southwest.
westDirection west.
northwestDirection northwest.


Shapes

Table 51. Shapes

box

polygon

ellipse

circle

doublecircle

point

egg

triangle

plaintext

diamond

trapezium

parallelogram

house

hexagon

septagon

octagon

doubleoctagon

tripleoctagon

invtriangle

invtrapezium

invhouse

Mdiamond

Msquare

Mcircle

rect

rectangle

none

 

Arrow styles

Table 52. Arrows

box

obox

crow

dot

odot

inv

oinv

invdot

invodot

none

normal

tee

vee

   

Value reference

Output formats

Table 53. Graphviz output formats

NameDescriptionNameDescription
bmpWindows Bitmap Formatcanon 
dotDOTxdotDOT
diaDia formatepsEncapsulated PostScript
figFIGgtkGTK canvas

gd

gd2

GD/GD2 formatsgifGIF
hpglHP-GL/2icoIcon Image File Format

imap

imap_np

cmapx

cmapx_np

Server-side and client-side imagemaps

jpg

jpeg

jpe

JPEG
mifFrameMaker MIF formatmpMetaPost
pclPCLpdfPortable Document Format (PDF)
picPIC

plain

plain-ext

Simple text format
pngPortable Network Graphics formatpsPostScript
ps2PostScript for PDF

svg

svgz

Scalable Vector Graphics
tgaTruevision Targa Format (TGA)

tif

tiff

TIFF (Tag Image File Format)

vml

vmlz

Vector Markup Language (VML)vrmlVRML
vtxVisual Thought formatwbmpWireless BitMap format
xlibXlib canvas  

Workflow configuration

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

namedescriptiondefaultexample
targetDirOutput directory of resulting .dot files and processdot[.bat|.sh] src-gen
dotTargetDirOutput directory of images produced by Graphviz when calling the generated processdot.[bat|sh] command..src-gen/images
topFunctionCallExpressionThis is the qualified path to the Xtend function to call to perform the M2M transformation. 

ecore2dot::toGraphVizmodel

(model)

pathToDotExeThe 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/

graphviz-2.12/bin/

outputFormatGraphviz 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>

Example Transformation

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.

References

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: