Skip to content

Instantly share code, notes, and snippets.

@kaigouthro
Created August 12, 2024 07:35
Show Gist options
  • Save kaigouthro/fd9aed52895a5668f6059f5e9d93f5a8 to your computer and use it in GitHub Desktop.
Save kaigouthro/fd9aed52895a5668f6059f5e9d93f5a8 to your computer and use it in GitHub Desktop.
pyflowchart streamlit + cheat sheet

Instructions from PyFlowchart Documentation

Installation:

  1. Install using pip:
    $ pip install pyflowchart

Basic Usage:

  1. Flowchart Python code from the command line:

    $ python -m pyflowchart example.py 
    • Replace example.py with the name of your Python file.
    • This outputs the flowchart in flowchart.js DSL.
  2. Output to an HTML file:

    $ python -m pyflowchart example.py -o example.html
    • This creates an interactive HTML file (example.html) displaying the flowchart.
  3. Flowchart a specific function or method:

    $ python -m pyflowchart example.py -f function_name
    • Replace function_name with the actual function name.
    • For methods:
      $ python -m pyflowchart example.py -f ClassName.method_name

Flowcharting in Python:

  1. Import necessary classes:

    from pyflowchart import * 
  2. Create nodes:

    st = StartNode('a_pyflow_test')
    op = OperationNode('do something')
    cond = ConditionNode('Yes or No?')
    io = InputOutputNode(InputOutputNode.OUTPUT, 'something...')
    sub = SubroutineNode('A Subroutine')
    e = EndNode('a_pyflow_test') 
  3. Connect the nodes:

    st.connect(op)
    op.connect(cond)
    cond.connect_yes(io)
    cond.connect_no(sub)
    sub.connect(op, "right") 
    io.connect(e) 
  4. Create a Flowchart object and generate the flowchart DSL:

    fc = Flowchart(st)
    print(fc.flowchart())
  5. Output to an HTML file (programmatically):

    output_html('output.html', 'a_pyflow_test', fc.flowchart()) 

Python to Flowchart (from code):

  1. Generate a flowchart from Python code:
from pyflowchart import Flowchart
with open('simple.py') as f:
    code = f.read()
fc = Flowchart.from_code(code)
print(fc.flowchart())
  • Replace simple.py with your Python filename.

Advanced Usage (from code):

  1. Using Flowchart.from_code():
Flowchart.from_code(code, field="", inner=True, simplify=True, conds_align=False) 
  • code: Python code to convert.
  • field: Specific function/method to flowchart (e.g., "foo" or "Bar.buzz").
  • inner: If True, parse the body of field as nested. If False, treat as a single node.
  • simplify: If True, simplify one-line if and while statements.
  • conds_align: If True, align consecutive if statements.

Command Line Interface (CLI):

  1. Advanced options with CLI:
python -m pyflowchart [-f FIELD] [-i] [--no-simplify] [--conds-align] [-o OUTPUT] code_file 
  • -f FIELD: Specify the field (function/method).
  • -i: Equivalent to inner=True.
  • --no-simplify: Disable simplification (simplify=False).
  • --conds-align: Enable alignment of if statements.
  • -o OUTPUT: Output to a file (e.g., -o output.html).
from dataclasses import dataclass, field
from typing import List, Dict, Optional

@dataclass
class Node:
    id: str
    type: str  # e.g., "start", "operation", "condition", "input_output", "end"
    content: str
    x: int = 0
    y: int = 0

@dataclass
class Connection:
    source_id: str
    target_id: str
    type: str = "default"  # e.g., "yes", "no" for conditions

@dataclass
class Flowchart:
    nodes: List[Node] = field(default_factory=list)
    connections: List[Connection] = field(default_factory=list)

class GraphEditor:
    def __init__(self):
        self.flowchart = Flowchart()

    def add_node(self, node_type, content, x=0, y=0):
        node_id = self._generate_unique_id()
        node = Node(id=node_id, type=node_type, content=content, x=x, y=y)
        self.flowchart.nodes.append(node)
        return node_id

    def update_node(self, node_id, content=None, x=None, y=None):
        for node in self.flowchart.nodes:
            if node.id == node_id:
                if content is not None:
                    node.content = content
                if x is not None:
                    node.x = x
                if y is not None:
                    node.y = y
                break

    def delete_node(self, node_id):
        self.flowchart.nodes = [node for node in self.flowchart.nodes if node.id != node_id]
        # Also delete connections associated with the node
        self.flowchart.connections = [
            conn
            for conn in self.flowchart.connections
            if conn.source_id != node_id and conn.target_id != node_id
        ]

    def add_connection(self, source_id, target_id, connection_type="default"):
        connection = Connection(
            source_id=source_id, target_id=target_id, type=connection_type
        )
        self.flowchart.connections.append(connection)

    def delete_connection(self, source_id, target_id):
        self.flowchart.connections = [
            conn
            for conn in self.flowchart.connections
            if not (conn.source_id == source_id and conn.target_id == target_id)
        ]

    def _generate_unique_id(self):
        # Simple ID generation (replace with a more robust method if needed)
        return str(len(self.flowchart.nodes) + 1)

    def get_flowchart(self):
        return self.flowchart

Explanation:

  • Node dataclass:

    • id: Unique identifier for the node.
    • type: The type of node (start, operation, condition, etc.).
    • content: The text or data within the node.
    • x, y: Coordinates for positioning the node in the UI.
  • Connection dataclass:

    • source_id: ID of the starting node.
    • target_id: ID of the ending node.
    • type: Type of connection (e.g., "yes", "no" for conditions).
  • Flowchart dataclass:

    • nodes: List of Node objects.
    • connections: List of Connection objects.
  • GraphEditor class:

    • Provides methods for manipulating the flowchart:
      • add_node(): Adds a new node to the flowchart.
      • update_node(): Modifies an existing node's properties.
      • delete_node(): Removes a node and its associated connections.
      • add_connection(): Creates a connection between two nodes.
      • delete_connection(): Removes a connection.
      • _generate_unique_id(): Generates unique IDs for nodes (you might want to replace this with a more robust ID generation mechanism).
      • get_flowchart(): Returns the current Flowchart object.

How to use it in Streamlit:

  1. Initialize GraphEditor:

    graph_editor = GraphEditor()
  2. Use Streamlit components to interact with GraphEditor:

    • Example (adding a node):
      node_type = st.selectbox("Node Type", ["start", "operation", "condition", ...])
      content = st.text_input("Content")
      if st.button("Add Node"):
          graph_editor.add_node(node_type, content)
  3. Retrieve and display the flowchart:

    flowchart = graph_editor.get_flowchart()
    # Use flowchart.nodes and flowchart.connections to visualize the graph

Key improvements:

  • Dataclasses: Using dataclasses makes the code more readable and concise.
  • Type hints: Type hints improve code clarity and help with error detection.
  • Clearer method names: More descriptive method names (e.g., add_node, update_node) enhance readability.
  • ID generation: Includes a basic _generate_unique_id method for node IDs.
  • Connection types: The Connection dataclass now has a type field for different connection types (e.g., "yes", "no").

Remember to implement the visualization part using a suitable library or method in your Streamlit UI. You'll likely need to handle drag-and-drop interactions, rendering nodes and connections, and updating the GraphEditor based on user actions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment