Graphviz Examples
Table of contents
This is simply a collection of Graphviz styles.
SysML v2 Style
Example 1
digraph DecompositionView {
rankdir = TB;
node [shape = record; style = rounded; fontsize = 10;];
vehicle [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td colspan="1"><b>«part»<br/>vehicle</b></td></tr>
<tr><td align="center" border="1" sides="T">attributes</td></tr>
<tr><td align="left">mass</td></tr>
<tr><td align="center" border="1" sides="T">actions</td></tr>
<tr><td align="left">perform providePower</td></tr>
</table>>;];
transmission [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td colspan="1"><b>«part»<br/>transmission</b></td></tr>
<tr><td align="center" border="1" sides="T">attributes</td></tr>
<tr><td align="left">mass</td></tr>
<tr><td align="center" border="1" sides="T">actions</td></tr>
<tr><td align="left">perform amplifyTorque</td></tr>
</table>>;];
engine [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td colspan="1"><b>«part»<br/>engine</b></td></tr>
<tr><td align="center" border="1" sides="T">attributes</td></tr>
<tr><td align="left">mass</td></tr>
<tr><td align="center" border="1" sides="T">actions</td></tr>
<tr><td align="left">perform generateTorque</td></tr>
</table>>;];
cylinders [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td colspan="1"><b>«part»<br/>cylinders[6]</b></td></tr>
</table>>;];
vehicle -> transmission;
vehicle -> engine;
engine -> cylinders;
label = "Decomposition View of vehicle";
labelloc = "t";
fontsize = 14;
}
Example 2
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QTabWidget
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtCore import QUrl
from diagram_renderer import SysMLRenderer
class SysMLViewer(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("SysML v2 Viewer")
self.setGeometry(100, 100, 1200, 800)
# Create central widget and layout
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
# Create tab widget
self.tab_widget = QTabWidget()
layout.addWidget(self.tab_widget)
# Create web views for each diagram
self.structure_view = QWebEngineView()
self.action_view = QWebEngineView()
self.tab_widget.addTab(self.structure_view, "Decomposition View of vehicle")
self.tab_widget.addTab(self.action_view, "Decomposition View of providePower")
# Generate and display diagrams
self.generate_diagrams()
def generate_diagrams(self):
# Create structure diagram
renderer = SysMLRenderer()
with renderer.dot.subgraph(name='cluster_0') as s:
s.attr(label='Decomposition View of vehicle')
# Create nodes
renderer.create_part_node('vehicle', 'vehicle',
stereotype='part',
attributes=['mass'],
actions=['perform providePower'])
renderer.create_part_node('transmission', 'transmission',
stereotype='part',
attributes=['mass'],
actions=['perform amplifyTorque'])
renderer.create_part_node('engine', 'engine',
stereotype='part',
attributes=['mass'],
actions=['perform generateTorque'])
renderer.create_part_node('cylinders', 'cylinders[6]',
stereotype='part')
# Add relationships
renderer.add_relationship('vehicle', 'transmission')
renderer.add_relationship('vehicle', 'engine')
renderer.add_relationship('engine', 'cylinders')
renderer.render('structure_diagram')
self.structure_view.setUrl(QUrl.fromLocalFile(f"{sys.path[0]}/structure_diagram.svg"))
# Create action decomposition diagram
renderer = SysMLRenderer()
with renderer.dot.subgraph(name='cluster_1') as s:
s.attr(label='Decomposition View of providePower')
# Create nodes
renderer.create_action_node('providePower', 'providePower',
stereotype='action',
performed_by='vehicle')
renderer.create_action_node('generateTorque', 'generateTorque',
stereotype='action',
performed_by='engine')
renderer.create_action_node('amplifyTorque', 'amplifyTorque',
stereotype='action',
performed_by='transmission')
# Add relationships
renderer.add_relationship('generateTorque', 'providePower')
renderer.add_relationship('amplifyTorque', 'providePower')
renderer.render('action_diagram')
self.action_view.setUrl(QUrl.fromLocalFile(f"{sys.path[0]}/action_diagram.svg"))
def main():
app = QApplication(sys.argv)
viewer = SysMLViewer()
viewer.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
diagram_renderer.py
import graphviz
class SysMLRenderer:
def __init__(self):
self.dot = None
self.setup_new_diagram()
def setup_new_diagram(self, name="SysML v2 Diagram"):
self.dot = graphviz.Digraph(comment=name)
self.setup_styling()
def setup_styling(self):
self.dot.attr(rankdir='TB', splines='ortho') # Use orthogonal lines
self.dot.attr('node',
shape='box',
style='rounded',
fillcolor='white',
color='black',
fontname='Arial')
self.dot.attr('edge',
color='black',
fontname='Arial',
fontsize='10')
def create_part_node(self, id, name, stereotype="part", attributes=None, actions=None):
# Create HTML-like label with separators and styled headers
label = f'''<<table border="0" cellborder="0" cellspacing="0" cellpadding="0" width="150">
<tr><td colspan="1" cellpadding="4"><font point-size="10">«{stereotype}»</font><br/><b>{name}</b></td></tr>'''
if attributes:
label += '''<tr><td align="center" border="1" sides="T" width="150" cellpadding="2"><font point-size="9"><i>attributes</i></font></td></tr>'''
for attr in attributes:
label += f'''<tr><td width="150" cellpadding="8"><table border="0" cellborder="0" cellspacing="0" cellpadding="0"><tr><td width="15"></td><td width="135" align="left"><font point-size="10">{attr}</font></td></tr></table></td></tr>'''
if actions:
label += '''<tr><td align="center" border="1" sides="T" width="150" cellpadding="2"><font point-size="9"><i>action</i></font></td></tr>'''
for action in actions:
label += f'''<tr><td width="150" cellpadding="8"><table border="0" cellborder="0" cellspacing="0" cellpadding="0"><tr><td width="15"></td><td width="135" align="left"><font point-size="10">{action}</font></td></tr></table></td></tr>'''
label += '</table>>'
self.dot.node(id, label, shape='box', margin="0")
def create_action_node(self, id, name, stereotype="action", performed_by=None):
label = f'''<<table border="0" cellborder="0" cellspacing="0" cellpadding="0" width="150">
<tr><td colspan="1" cellpadding="4"><font point-size="10">«{stereotype}»</font><br/><b>{name}</b></td></tr>'''
if performed_by:
label += f'''<tr><td align="center" border="1" sides="T" width="150" cellpadding="2"><font point-size="9"><i>performed by</i></font></td></tr><tr><td width="150" cellpadding="8"><table border="0" cellborder="0" cellspacing="0" cellpadding="0"><tr><td width="15"></td><td width="135" align="left"><font point-size="10">{performed_by}</font></td></tr></table></td></tr>'''
label += '</table>>'
self.dot.node(id, label, shape='box', margin="0")
def add_relationship(self, source, target, relationship_type=None):
# Use filled diamond arrowhead for composition relationships
self.dot.edge(source, target, dir='both', arrowtail='diamond', arrowhead='none')
def create_subgraph(self, name, label):
with self.dot.subgraph(name=f'cluster_{name}') as s:
s.attr(label=label, style='rounded')
return s
def render(self, filename):
return self.dot.render(filename, format='svg', cleanup=True)
Agile Card Style
Example 1
digraph AgileBoard {
// Global styling
graph [bgcolor = "white"; fontname = "Arial"; fontsize = 12; rankdir = "LR";];
node [shape = "none"; margin = 0;];
edge [color = "gray40"; fontname = "Arial"; fontsize = 10;];
// Card 1
CARD1 [label = <
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="8"
STYLE="rounded" COLOR="#dee2e6" BGCOLOR="#ffffff">
<!-- Title Row -->
<TR>
<TD>
<FONT POINT-SIZE="14"><B>User Login</B></FONT><BR/>
<FONT POINT-SIZE="10" COLOR="#6c757d">CARD-101</FONT>
</TD>
</TR>
<!-- Description Row -->
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#6c757d">
Implement user login functionality
</FONT>
</TD>
</TR>
<!-- Status Row -->
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#198754"><B>Status: In Progress</B></FONT>
</TD>
</TR>
</TABLE>
>;];
// Card 2
CARD2 [label = <
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="8"
STYLE="rounded" COLOR="#dee2e6" BGCOLOR="#ffffff">
<TR>
<TD>
<FONT POINT-SIZE="14"><B>Database Setup</B></FONT><BR/>
<FONT POINT-SIZE="10" COLOR="#6c757d">CARD-102</FONT>
</TD>
</TR>
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#6c757d">
Set up and configure main database
</FONT>
</TD>
</TR>
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#0d6efd"><B>Status: Completed</B></FONT>
</TD>
</TR>
</TABLE>
>;];
// Card 3
CARD3 [label = <
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="8"
STYLE="rounded" COLOR="#dee2e6" BGCOLOR="#ffffff">
<TR>
<TD>
<FONT POINT-SIZE="14"><B>UI Design</B></FONT><BR/>
<FONT POINT-SIZE="10" COLOR="#6c757d">CARD-103</FONT>
</TD>
</TR>
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#6c757d">
Create initial UI mockups
</FONT>
</TD>
</TR>
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#ffc107"><B>Status: Pending</B></FONT>
</TD>
</TR>
</TABLE>
>;];
// Card 4
CARD4 [label = <
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="8"
STYLE="rounded" COLOR="#dee2e6" BGCOLOR="#ffffff">
<TR>
<TD>
<FONT POINT-SIZE="14"><B>API Integration</B></FONT><BR/>
<FONT POINT-SIZE="10" COLOR="#6c757d">CARD-104</FONT>
</TD>
</TR>
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#6c757d">
Integrate with external API
</FONT>
</TD>
</TR>
<TR>
<TD>
<FONT POINT-SIZE="10" COLOR="#dc3545"><B>Status: Blocked</B></FONT>
</TD>
</TR>
</TABLE>
>;];
// Define dependencies (edges)
// Adjust the labels or arrow directions as needed:
CARD1 -> CARD2 [label = "depends on"; fontsize = 9;];
CARD4 -> CARD1 [label = "blocked by"; fontsize = 9;];
CARD3 -> CARD1 [label = "depends on"; fontsize = 9;];
CARD4 -> CARD2 [label = "requires"; fontsize = 9;];
}