# import graphviz # import json # from tempfile import NamedTemporaryFile # import os # def generate_binary_tree_diagram(json_input: str, output_format: str) -> str: # """ # Generates a binary tree diagram from JSON input. # Args: # json_input (str): A JSON string describing the binary tree structure. # It must follow the Expected JSON Format Example below. # Expected JSON Format Example: # { # "root": { # "id": "root", # "label": "50", # "left": { # "id": "left_1", # "label": "30", # "left": { # "id": "left_2", # "label": "20" # }, # "right": { # "id": "right_2", # "label": "40" # } # }, # "right": { # "id": "right_1", # "label": "70", # "left": { # "id": "left_3", # "label": "60" # }, # "right": { # "id": "right_3", # "label": "80" # } # } # } # } # Returns: # str: The filepath to the generated PNG image file. # """ # try: # if not json_input.strip(): # return "Error: Empty input" # data = json.loads(json_input) # if 'root' not in data: # raise ValueError("Missing required field: root") # dot = graphviz.Digraph( # name='BinaryTree', # format='png', # graph_attr={ # 'rankdir': 'TB', # Top-to-Bottom layout # 'splines': 'line', # Straight lines # 'bgcolor': 'white', # White background # 'pad': '0.5', # Padding around the graph # 'nodesep': '0.8', # Spacing between nodes # 'ranksep': '1.0' # Spacing between levels # } # ) # base_color = '#19191a' # def add_binary_tree_nodes(node, current_depth=0): # """ # Add binary tree nodes recursively with proper styling. # """ # if not node: # return # node_id = node.get('id', f'node_{current_depth}') # node_label = node.get('label', 'Node') # lightening_factor = 0.12 # if not isinstance(base_color, str) or not base_color.startswith('#') or len(base_color) != 7: # base_color_safe = '#19191a' # else: # base_color_safe = base_color # base_r = int(base_color_safe[1:3], 16) # base_g = int(base_color_safe[3:5], 16) # base_b = int(base_color_safe[5:7], 16) # current_r = base_r + int((255 - base_r) * current_depth * lightening_factor) # current_g = base_g + int((255 - base_g) * current_depth * lightening_factor) # current_b = base_b + int((255 - base_b) * current_depth * lightening_factor) # current_r = min(255, current_r) # current_g = min(255, current_g) # current_b = min(255, current_b) # node_color = f'#{current_r:02x}{current_g:02x}{current_b:02x}' # font_color = 'white' if current_depth * lightening_factor < 0.6 else 'black' # font_size = max(9, 14 - current_depth) # dot.node( # node_id, # node_label, # shape='circle', # style='filled', # fillcolor=node_color, # fontcolor=font_color, # fontsize=str(font_size), # width='0.8', # height='0.8' # ) # left_child = node.get('left') # if left_child: # add_binary_tree_nodes(left_child, current_depth + 1) # left_id = left_child.get('id', f'node_{current_depth + 1}_left') # dot.edge( # node_id, # left_id, # color='#4a4a4a', # arrowsize='0.8' # ) # right_child = node.get('right') # if right_child: # add_binary_tree_nodes(right_child, current_depth + 1) # right_id = right_child.get('id', f'node_{current_depth + 1}_right') # dot.edge( # node_id, # right_id, # color='#4a4a4a', # arrowsize='0.8' # ) # add_binary_tree_nodes(data['root'], current_depth=0) # with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp: # dot.render(tmp.name, format=output_format, cleanup=True) # return f"{tmp.name}.{output_format}" # except json.JSONDecodeError: # return "Error: Invalid JSON format" # except Exception as e: # return f"Error: {str(e)}" import graphviz import json from tempfile import NamedTemporaryFile import os def generate_binary_tree_diagram(json_input: str, output_format: str) -> str: """ Generates a binary tree diagram from JSON input. Args: json_input (str): A JSON string describing the binary tree structure. It must follow the Expected JSON Format Example below. Expected JSON Format Example: { "root": { "id": "root", "label": "50", "left": { "id": "left_1", "label": "30", "left": { "id": "left_2", "label": "20" }, "right": { "id": "right_2", "label": "40" } }, "right": { "id": "right_1", "label": "70", "left": { "id": "left_3", "label": "60" }, "right": { "id": "right_3", "label": "80" } } } } Returns: str: The filepath to the generated PNG image file. """ try: if not json_input.strip(): return "Error: Empty input" data = json.loads(json_input) if 'root' not in data: raise ValueError("Missing required field: root") dot = graphviz.Digraph( name='BinaryTree', format='png', graph_attr={ 'rankdir': 'TB', 'splines': 'line', 'bgcolor': 'white', 'pad': '0.5', 'nodesep': '0.8', 'ranksep': '1.0' } ) base_color = '#BEBEBE' def add_binary_tree_nodes(node, current_depth=0): if not node: return node_id = node.get('id', f'node_{current_depth}') node_label = node.get('label', 'Node') lightening_factor = 0.06 if not isinstance(base_color, str) or not base_color.startswith('#') or len(base_color) != 7: base_color_safe = '#BEBEBE' else: base_color_safe = base_color base_r = int(base_color_safe[1:3], 16) base_g = int(base_color_safe[3:5], 16) base_b = int(base_color_safe[5:7], 16) current_r = base_r + int((255 - base_r) * current_depth * lightening_factor) current_g = base_g + int((255 - base_g) * current_depth * lightening_factor) current_b = base_b + int((255 - base_b) * current_depth * lightening_factor) current_r = min(255, current_r) current_g = min(255, current_g) current_b = min(255, current_b) node_color = f'#{current_r:02x}{current_g:02x}{current_b:02x}' font_color = 'black' font_size = max(9, 14 - current_depth) dot.node( node_id, node_label, shape='circle', style='filled,rounded', fillcolor=node_color, fontcolor=font_color, fontsize=str(font_size), width='0.8', height='0.8' ) left_child = node.get('left') if left_child: add_binary_tree_nodes(left_child, current_depth + 1) left_id = left_child.get('id', f'node_{current_depth + 1}_left') dot.edge( node_id, left_id, color='#4a4a4a', arrowsize='0.8' ) right_child = node.get('right') if right_child: add_binary_tree_nodes(right_child, current_depth + 1) right_id = right_child.get('id', f'node_{current_depth + 1}_right') dot.edge( node_id, right_id, color='#4a4a4a', arrowsize='0.8' ) add_binary_tree_nodes(data['root'], current_depth=0) with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp: dot.render(tmp.name, format=output_format, cleanup=True) return f"{tmp.name}.{output_format}" except json.JSONDecodeError: return "Error: Invalid JSON format" except Exception as e: return f"Error: {str(e)}"