Graphviz Examples

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

main.py

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;];
}