|
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. |
|
|
|
Args: |
|
json_input (str): A JSON string describing the radial diagram structure. |
|
It must follow the Expected JSON Format Example below. |
|
|
|
Returns: |
|
str: The filepath to the generated PNG image file. |
|
|
|
Expected JSON Format Example: |
|
{ |
|
"central_node": "Making Coffee", |
|
"nodes": [ |
|
{ |
|
"id": "coffee_components", |
|
"label": "Coffee Components", |
|
"relationship": "Involves", |
|
"subnodes": [ |
|
{ |
|
"id": "equipment", |
|
"label": "Equipment Needed", |
|
"relationship": "Requires", |
|
"subnodes": [ |
|
{"id": "coffee_maker", "label": "Coffee Maker", "relationship": "e.g."}, |
|
{"id": "mug", "label": "Mug", "relationship": "For"} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
"id": "coffee_process_enjoyment", |
|
"label": "Process & Enjoyment", |
|
"relationship": "Leads to", |
|
"subnodes": [ |
|
{ |
|
"id": "preparation_steps", |
|
"label": "Preparation Steps", |
|
"relationship": "Involves", |
|
"subnodes": [ |
|
{"id": "grind_beans", "label": "Grind Beans", "relationship": "Step 1 (if whole)"}, |
|
{"id": "heat_water", "label": "Heat Water", "relationship": "Step 2"} |
|
] |
|
} |
|
] |
|
} |
|
] |
|
} |
|
""" |
|
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', |
|
graph_attr={ |
|
'overlap': 'false', |
|
'splines': 'true', |
|
'bgcolor': 'white', |
|
'pad': '0.5', |
|
'layout': 'neato' |
|
}, |
|
node_attr={ |
|
'fixedsize': 'false' |
|
} |
|
) |
|
|
|
base_color = '#19191a' |
|
|
|
|
|
dot.node( |
|
'central', |
|
data['central_node'], |
|
shape='box', |
|
style='filled,rounded', |
|
fillcolor=base_color, |
|
fontcolor='white', |
|
fontsize='16' |
|
) |
|
|
|
|
|
|
|
add_nodes_and_edges(dot, 'central', data.get('nodes', []), current_depth=1, base_color=base_color) |
|
|
|
|
|
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)}" |
|
|
|
|