Mermaid Diagram Generation

Convert GraphContext objects to Mermaid.js diagram strings for visualization

context_to_mermaid

Converts a GraphContext into a Mermaid.js flowchart diagram string. The resulting string can be rendered in Markdown environments that support Mermaid (GitHub, Jupyter with extensions, documentation sites, etc.).


source

context_to_mermaid


def context_to_mermaid(
    ctx:GraphContext, # The GraphContext to visualize
    direction:str='TD', # Diagram direction: "TD" (top-down) or "LR" (left-right)
    node_color_map:Optional=None, # Map of node labels to CSS colors
)->str: # Mermaid.js diagram string

Convert a GraphContext into a Mermaid.js diagram string.

Example Usage

import uuid
from cjm_graph_plugin_system.core import GraphNode, GraphEdge, GraphContext

# Create sample nodes
alice_id = str(uuid.uuid4())
bob_id = str(uuid.uuid4())
ml_id = str(uuid.uuid4())

nodes = [
    GraphNode(id=alice_id, label="Person", properties={"name": "Alice"}),
    GraphNode(id=bob_id, label="Person", properties={"name": "Bob"}),
    GraphNode(id=ml_id, label="Concept", properties={"name": "Machine Learning"})
]

# Create sample edges
edges = [
    GraphEdge(id=str(uuid.uuid4()), source_id=alice_id, target_id=ml_id, relation_type="MENTIONS"),
    GraphEdge(id=str(uuid.uuid4()), source_id=bob_id, target_id=ml_id, relation_type="MENTIONS"),
    GraphEdge(id=str(uuid.uuid4()), source_id=alice_id, target_id=bob_id, relation_type="KNOWS")
]

# Create GraphContext
ctx = GraphContext(nodes=nodes, edges=edges)

# Convert to Mermaid
mermaid_str = context_to_mermaid(ctx)
print(mermaid_str)
graph TD
    N0["Alice"]
    N1["Bob"]
    N2["Machine Learning"]
    N0 -->|MENTIONS| N2
    N1 -->|MENTIONS| N2
    N0 -->|KNOWS| N1
# Test with node color mapping
color_map = {
    "Person": "#ffaaaa",
    "Concept": "#aaaaff"
}

mermaid_styled = context_to_mermaid(ctx, node_color_map=color_map)
print(mermaid_styled)
graph TD
    N0["Alice"]
    style N0 fill:#ffaaaa
    N1["Bob"]
    style N1 fill:#ffaaaa
    N2["Machine Learning"]
    style N2 fill:#aaaaff
    N0 -->|MENTIONS| N2
    N1 -->|MENTIONS| N2
    N0 -->|KNOWS| N1
# Test left-right direction
mermaid_lr = context_to_mermaid(ctx, direction="LR")
print(mermaid_lr)
graph LR
    N0["Alice"]
    N1["Bob"]
    N2["Machine Learning"]
    N0 -->|MENTIONS| N2
    N1 -->|MENTIONS| N2
    N0 -->|KNOWS| N1
# Test with empty context
empty_ctx = GraphContext(nodes=[], edges=[])
mermaid_empty = context_to_mermaid(empty_ctx)
print(mermaid_empty)
assert mermaid_empty == "graph TD"
graph TD
# Test node with special characters in name
special_node = GraphNode(
    id=str(uuid.uuid4()),
    label="Quote",
    properties={"name": 'He said "hello"'}
)
special_ctx = GraphContext(nodes=[special_node], edges=[])
mermaid_special = context_to_mermaid(special_ctx)
print(mermaid_special)
assert "He said 'hello'" in mermaid_special  # Double quotes replaced with single quotes
graph TD
    N0["He said 'hello'"]
# Test fallback to label when no name/title property
label_only_node = GraphNode(
    id=str(uuid.uuid4()),
    label="UnnamedThing",
    properties={"other": "value"}
)
label_ctx = GraphContext(nodes=[label_only_node], edges=[])
mermaid_label = context_to_mermaid(label_ctx)
print(mermaid_label)
assert "UnnamedThing" in mermaid_label
graph TD
    N0["UnnamedThing"]
# Test that edges referencing missing nodes are skipped
orphan_edge = GraphEdge(
    id=str(uuid.uuid4()),
    source_id="nonexistent-1",
    target_id="nonexistent-2",
    relation_type="BROKEN"
)
single_node = GraphNode(id=str(uuid.uuid4()), label="Lonely", properties={"name": "Solo"})
orphan_ctx = GraphContext(nodes=[single_node], edges=[orphan_edge])
mermaid_orphan = context_to_mermaid(orphan_ctx)
print(mermaid_orphan)
assert "BROKEN" not in mermaid_orphan  # Orphan edge should not appear
graph TD
    N0["Solo"]