class DiagramGenerator
A class that generates various types of diagrams including flowcharts, process flows, and network diagrams using matplotlib and networkx, returning base64-encoded PNG images.
/tf/active/vicechatdev/e-ink-llm/graphics_generator.py
228 - 373
moderate
Purpose
DiagramGenerator provides a unified interface for creating different diagram types from specifications. It takes a GraphicSpec object containing diagram parameters (type, steps, nodes, edges, direction) and generates visual diagrams as base64-encoded images. The class supports flowcharts (vertical/horizontal), process diagrams, and network diagrams, with automatic error handling and fallback to error diagrams when generation fails.
Source Code
class DiagramGenerator:
"""Generates diagrams like flowcharts, process flows, organizational charts"""
def generate_diagram(self, spec: GraphicSpec) -> GraphicSpec:
"""Generate a diagram based on specification"""
params = spec.parameters
diagram_type = params.get('style', 'flowchart').lower()
try:
if diagram_type == 'flowchart':
return self._create_flowchart(spec)
elif diagram_type == 'process':
return self._create_process_diagram(spec)
elif diagram_type == 'network':
return self._create_network_diagram(spec)
else:
return self._create_flowchart(spec) # Default to flowchart
except Exception as e:
print(f"Error generating diagram: {e}")
return self._create_error_diagram(spec, f"Diagram generation failed: {e}")
def _create_flowchart(self, spec: GraphicSpec) -> GraphicSpec:
"""Create a flowchart diagram"""
params = spec.parameters
steps = params.get('steps', ['Start', 'Process', 'End'])
direction = params.get('direction', 'vertical')
fig, ax = plt.subplots(figsize=(10, 8))
if direction == 'horizontal':
self._draw_horizontal_flowchart(ax, steps)
else:
self._draw_vertical_flowchart(ax, steps)
ax.set_xlim(-1, len(steps))
ax.set_ylim(-1, len(steps))
ax.axis('off')
ax.set_title(spec.description, fontsize=14, fontweight='bold', pad=20)
plt.tight_layout()
spec.image_data = self._fig_to_base64(fig)
spec.width = 1000
spec.height = 800
plt.close(fig)
return spec
def _draw_vertical_flowchart(self, ax, steps):
"""Draw a vertical flowchart"""
y_positions = np.linspace(len(steps)-1, 0, len(steps))
for i, (step, y) in enumerate(zip(steps, y_positions)):
# Draw box
box = FancyBboxPatch((0.1, y-0.2), 1.8, 0.4,
boxstyle="round,pad=0.05",
facecolor='white', edgecolor='black', linewidth=2)
ax.add_patch(box)
# Add text
ax.text(1, y, step, ha='center', va='center', fontsize=11, fontweight='bold')
# Draw arrow to next step
if i < len(steps) - 1:
ax.annotate('', xy=(1, y_positions[i+1]+0.2), xytext=(1, y-0.2),
arrowprops=dict(arrowstyle='->', lw=2, color='black'))
def _draw_horizontal_flowchart(self, ax, steps):
"""Draw a horizontal flowchart"""
x_positions = np.linspace(0, len(steps)-1, len(steps))
for i, (step, x) in enumerate(zip(steps, x_positions)):
# Draw box
box = FancyBboxPatch((x-0.4, 0.3), 0.8, 0.4,
boxstyle="round,pad=0.05",
facecolor='white', edgecolor='black', linewidth=2)
ax.add_patch(box)
# Add text
ax.text(x, 0.5, step, ha='center', va='center', fontsize=11, fontweight='bold')
# Draw arrow to next step
if i < len(steps) - 1:
ax.annotate('', xy=(x_positions[i+1]-0.4, 0.5), xytext=(x+0.4, 0.5),
arrowprops=dict(arrowstyle='->', lw=2, color='black'))
def _create_process_diagram(self, spec: GraphicSpec) -> GraphicSpec:
"""Create a process diagram"""
# Similar to flowchart but with different styling
return self._create_flowchart(spec)
def _create_network_diagram(self, spec: GraphicSpec) -> GraphicSpec:
"""Create a network diagram using networkx"""
params = spec.parameters
nodes = params.get('nodes', ['A', 'B', 'C'])
edges = params.get('edges', [('A', 'B'), ('B', 'C')])
fig, ax = plt.subplots(figsize=(8, 8))
# Create network graph
G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
# Position nodes
pos = nx.spring_layout(G, seed=42)
# Draw network
nx.draw(G, pos, ax=ax, with_labels=True, node_color='white',
node_size=1500, font_size=12, font_weight='bold',
edge_color='black', linewidths=2)
ax.set_title(spec.description, fontsize=14, fontweight='bold')
plt.tight_layout()
spec.image_data = self._fig_to_base64(fig)
spec.width = 800
spec.height = 800
plt.close(fig)
return spec
def _fig_to_base64(self, fig) -> str:
"""Convert matplotlib figure to base64 encoded image"""
buffer = io.BytesIO()
fig.savefig(buffer, format='png', dpi=150, bbox_inches='tight',
facecolor='white', edgecolor='none')
buffer.seek(0)
image_data = buffer.getvalue()
buffer.close()
return base64.b64encode(image_data).decode('utf-8')
def _create_error_diagram(self, spec: GraphicSpec, error_msg: str) -> GraphicSpec:
"""Create an error placeholder diagram"""
fig, ax = plt.subplots(figsize=(6, 4))
ax.text(0.5, 0.5, f"Error: {error_msg}", ha='center', va='center',
transform=ax.transAxes, fontsize=12,
bbox=dict(boxstyle="round,pad=0.3", facecolor="lightgray"))
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
spec.image_data = self._fig_to_base64(fig)
spec.width = 600
spec.height = 400
plt.close(fig)
return spec
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
No constructor parameters: The class has no __init__ method defined, so it uses the default constructor with no parameters. Instantiation is straightforward with no required arguments.
Return Value
The main method generate_diagram() returns a GraphicSpec object with populated image_data (base64-encoded PNG), width, and height attributes. All internal methods also return modified GraphicSpec objects. The image_data field contains a base64-encoded string that can be decoded to display or save the generated diagram.
Class Interface
Methods
generate_diagram(self, spec: GraphicSpec) -> GraphicSpec
Purpose: Main entry point that generates a diagram based on the specification's style parameter and returns the modified spec with image data
Parameters:
spec: GraphicSpec object containing description and parameters dict with keys: 'style' (flowchart/process/network), 'steps' (list of step names), 'direction' (vertical/horizontal), 'nodes' (list of node names), 'edges' (list of tuples)
Returns: Modified GraphicSpec object with image_data (base64 PNG string), width, and height populated
_create_flowchart(self, spec: GraphicSpec) -> GraphicSpec
Purpose: Creates a flowchart diagram with boxes and arrows, supporting vertical or horizontal layout
Parameters:
spec: GraphicSpec with parameters containing 'steps' (list of strings) and 'direction' ('vertical' or 'horizontal')
Returns: GraphicSpec with generated flowchart image data, width=1000, height=800
_draw_vertical_flowchart(self, ax, steps)
Purpose: Draws flowchart boxes and arrows vertically on the provided matplotlib axes
Parameters:
ax: Matplotlib axes object to draw onsteps: List of step names/labels to display in the flowchart
Returns: None (modifies ax in-place)
_draw_horizontal_flowchart(self, ax, steps)
Purpose: Draws flowchart boxes and arrows horizontally on the provided matplotlib axes
Parameters:
ax: Matplotlib axes object to draw onsteps: List of step names/labels to display in the flowchart
Returns: None (modifies ax in-place)
_create_process_diagram(self, spec: GraphicSpec) -> GraphicSpec
Purpose: Creates a process diagram (currently delegates to flowchart creation)
Parameters:
spec: GraphicSpec with process diagram parameters
Returns: GraphicSpec with generated process diagram image data
_create_network_diagram(self, spec: GraphicSpec) -> GraphicSpec
Purpose: Creates a network diagram using networkx with nodes and edges in a spring layout
Parameters:
spec: GraphicSpec with parameters containing 'nodes' (list of node names) and 'edges' (list of (source, target) tuples)
Returns: GraphicSpec with generated network diagram image data, width=800, height=800
_fig_to_base64(self, fig) -> str
Purpose: Converts a matplotlib figure to a base64-encoded PNG string
Parameters:
fig: Matplotlib figure object to convert
Returns: Base64-encoded string representation of the figure as PNG (150 DPI, white background)
_create_error_diagram(self, spec: GraphicSpec, error_msg: str) -> GraphicSpec
Purpose: Creates a simple error placeholder diagram displaying the error message
Parameters:
spec: GraphicSpec object to populate with error diagramerror_msg: Error message string to display in the diagram
Returns: GraphicSpec with error diagram image data, width=600, height=400
Dependencies
matplotlibnumpynetworkxiobase64
Required Imports
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
import numpy as np
import networkx as nx
import io
import base64
Usage Example
from dataclasses import dataclass
from typing import Dict, Any
@dataclass
class GraphicSpec:
description: str
parameters: Dict[str, Any]
image_data: str = ''
width: int = 0
height: int = 0
# Instantiate the generator
generator = DiagramGenerator()
# Create a flowchart specification
flowchart_spec = GraphicSpec(
description='User Login Process',
parameters={
'style': 'flowchart',
'steps': ['Start', 'Enter Credentials', 'Validate', 'Success'],
'direction': 'vertical'
}
)
# Generate the diagram
result = generator.generate_diagram(flowchart_spec)
print(f'Generated image size: {result.width}x{result.height}')
print(f'Image data length: {len(result.image_data)}')
# Create a network diagram
network_spec = GraphicSpec(
description='Network Topology',
parameters={
'style': 'network',
'nodes': ['Server', 'Router', 'Client1', 'Client2'],
'edges': [('Server', 'Router'), ('Router', 'Client1'), ('Router', 'Client2')]
}
)
network_result = generator.generate_diagram(network_spec)
# Decode and save the image
import base64
with open('diagram.png', 'wb') as f:
f.write(base64.b64decode(network_result.image_data))
Best Practices
- Always ensure the GraphicSpec object has a valid 'parameters' dictionary before calling generate_diagram()
- The class automatically closes matplotlib figures to prevent memory leaks, but be aware of memory usage when generating many diagrams
- Default values are provided for missing parameters: style defaults to 'flowchart', steps default to ['Start', 'Process', 'End'], direction defaults to 'vertical'
- Error handling is built-in: if diagram generation fails, an error diagram is returned instead of raising an exception
- The class is stateless and thread-safe - each method call is independent and doesn't modify class state
- For network diagrams, ensure edges reference nodes that exist in the nodes list to avoid networkx errors
- The generated base64 image data can be directly embedded in HTML img tags using data:image/png;base64, prefix
- DPI is set to 150 for good quality; modify _fig_to_base64 if different resolution is needed
- The class modifies the input GraphicSpec object in-place, setting image_data, width, and height attributes
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class GraphicsGenerator 71.2% similar
-
class IllustrationGenerator 69.8% similar
-
class ChartGenerator 64.8% similar
-
function demo_graphics_generation 56.7% similar
-
function generate_diagram_data 54.5% similar