UML Diagrams
From charlesreid1
You can use Graphviz's Dot package to create UML diagrams.
Use the pyreverse utility, part of the pylint suite.
pip install pylint
Example diagram here: https://charlesreid1.com/wiki/Olipy
Contents
Class Diagram Examples
Simple Class
You can make a simple class UML diagram like this:
<graphviz> digraph G { rankdir="LR" node [shape=record]; Arches [shape=record,label="<f0> Arches | <f1> problemSetup() : void \\ \lscheduleInitialize() : void \\ \linitialize() : void \\ \lscheduleComputeStableTimestep() : void \\ \lcomputeStableTimestep() : void \\ \lscheduleTimeAdvance() : void \\ \ltimeAdvance() : void \\ | \\ <f2> sharedState_ : SimulationState \\ \lmyMaterial_ : Material \\ "]; } </graphviz> |
<graphviz>
digraph G { rankdir="LR" node [shape=record]; Arches [shape=record,label="<f0> Arches | <f1> problemSetup() : void \\ \lscheduleInitialize() : void \\ \linitialize() : void \\ \lscheduleComputeStableTimestep() : void \\ \lcomputeStableTimestep() : void \\ \lscheduleTimeAdvance() : void \\ \ltimeAdvance() : void \\ |
\\
<f2> sharedState_ : SimulationState \\ \lmyMaterial_ : Material \\ "]; } </graphviz> |
Inheritance Diagram
Class inheritance can be illustrated with a UML diagram with a black arrow pointing from the child to the parent.
This code:
<graphviz> digraph G { node [shape=record]; BaseClass [shape=record,label="{<f0> BaseClass \\ | <f1> + doSomething() : void \\ }"]; DerivedClass [shape=record,label="{<f0> ScalarEqn \\ | <f1> + doSomethingDerived() : void \\ }"]; BaseClass->DerivedClass [dir=back]; } </graphviz> |
Makes this diagram:
<graphviz> digraph G { node [shape=record]; BaseClass [shape=record,label="{<f0> BaseClass \\ |
<f1> + doSomething() : void \\
}"]; DerivedClass [shape=record,label="{<f0> ScalarEqn \\ |
<f1> + doSomethingDerived() : void \\
}"];
</graphviz> |
Composition & Aggregation
Composition
Composition is a strong relationship between two entities, usually linked strongly by lifecycle. To say "an instance of class A MUST have an instance of class B" means that B composes A. It is a 1-to-1 (or 1-to-N) relationship. Think of a situation where you call class A's constructor, and class A's constructor calls class B's constructor; and vice-versa with the destructor (A's destructor calls B's destructor).
A concrete example would be a car and an engine. The two are related by composition: there is a strong lifecycle dependency between the two, and the relationship is 1-to-1.
Composition can be illustrated in a UML diagram as follows:
<graphviz> digraph G { node [shape=record]; Car [shape=record,label="Car"]; Engine [shape=record,label="Engine"]; Car->Engine [dir=back]; } </graphviz> </graphviz> |
<graphviz>
digraph G { node [shape=record];
Car->Engine [dir=back,arrowtail="diamond"]; } </graphviz> |
And if you want you can even describe the relationship by adding head and tail labels, following http://en.wikipedia.org/wiki/Class_diagram :
<graphviz> digraph G { node [shape=record]; Car [shape=record,label="Car"]; Engine [shape=record,label="Engine"]; Car->Engine [dir=back,arrowtail="diamond"]; } </graphviz>
|
<graphviz> digraph G { node [shape=record];
Car->Engine [dir=back,arrowtail="diamond",headlabel="1..1",label=" ",taillabel="1..1"]; } </graphviz> |
Aggregation
Aggregation is a weaker, many-to-many relationship: for example, ducks and ponds. There is not necessarily a strong lifecycle dependency between the two classes, and it represents a relationship best described as "is part of": "class B is part of class A".
<graphviz> digraph G { node [shape=record]; Duck [shape=record,label="Duck"]; Pond [shape=record,label="Pond"]; Duck->Pond [dir=back,arrowtail="odiamond"]; } </graphviz> |
<graphviz> digraph G { node [shape=record]; Duck [shape=record,label="Duck"]; Pond [shape=record,label="Pond"]; Duck->Pond [dir=back,arrowtail="odiamond"]; } </graphviz>
|
And again modifying the head and tail to show more information about the relationship is possible:
<graphviz> digraph G { node [shape=record]; Duck [shape=record,label="Duck"]; Pond [shape=record,label="Pond"]; Duck->Pond [dir=back,arrowtail="odiamond",taillabel="1..*",label=" ",headlabel="0..*"]; } </graphviz>
|
digraph G { node [shape=record];
Duck->Pond [dir=back,arrowtail="odiamond",taillabel="1..*",label=" ",headlabel="1..*"]; } </graphviz> |
Non-Specific Relationship
You can keep the interaction unspecific by making the line plain. This is a relationship that would not otherwise be called out, but you want to draw attention to it.
<graphviz> digraph G { node [shape=record]; CEO [shape=record,label="CEO"]; Peon [shape=record,label="Peon"]; CEO->Peon [arrowhead="none",label="Weekly Message from the CEO"]; } </graphviz> |
digraph G { node [shape=record]; CEO [shape=record,label="CEO"]; Peon [shape=record,label="Peon"]; CEO->Peon [arrowhead="none",label="Weekly Message from the CEO"]; } </graphviz> |
Useful Links
- List of all attributes, their class, possible values, etc: http://www.graphviz.org/doc/info/attrs.html#points
- Wikipedia page on class diagrams: http://en.wikipedia.org/wiki/Class_diagram