import graphviz | |
import json | |
from tempfile import NamedTemporaryFile | |
import os | |
from graph_generator_utils import add_nodes_and_edges | |
def generate_radial_diagram(json_input: str) -> str: | |
""" | |
Generates a radial (center-expanded) diagram from JSON input. | |
""" | |
try: | |
if not json_input.strip(): | |
return "Error: Empty input" | |
data = json.loads(json_input) | |
if 'central_node' not in data or 'nodes' not in data: | |
raise ValueError("Missing required fields: central_node or nodes") | |
dot = graphviz.Digraph( | |
name='RadialDiagram', | |
format='png', | |
engine='neato', # Use 'neato' or 'fdp' for radial/force-directed layout | |
graph_attr={ | |
'overlap': 'false', # Prevent node overlap | |
'splines': 'true', # Smooth splines for edges | |
'bgcolor': 'white', # White background | |
'pad': '0.5', # Padding around the graph | |
'layout': 'neato' # Explicitly set layout engine for consistency | |
}, | |
node_attr={ | |
'fixedsize': 'false' # Allow nodes to resize based on content | |
} | |
) | |
base_color = '#19191a' # Base color for the central node and gradient | |
# Central node styling (rounded box, dark color) | |
dot.node( | |
'central', | |
data['central_node'], | |
shape='box', # Rectangular shape | |
style='filled,rounded', # Filled and rounded corners | |
fillcolor=base_color, # Darkest color | |
fontcolor='white', # White text for dark background | |
fontsize='16' # Larger font for central node | |
) | |
# Add child nodes and edges recursively starting from depth 1 | |
# The add_nodes_and_edges function will handle styling consistent with other graphs | |
add_nodes_and_edges(dot, 'central', data.get('nodes', []), current_depth=1, base_color=base_color) | |
# Save to temporary file | |
with NamedTemporaryFile(delete=False, suffix='.png') as tmp: | |
dot.render(tmp.name, format='png', cleanup=True) | |
return tmp.name + '.png' | |
except json.JSONDecodeError: | |
return "Error: Invalid JSON format" | |
except Exception as e: | |
return f"Error: {str(e)}" | |