Spaces:
Running
Running
File size: 6,049 Bytes
c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 c73b6d7 991c9f4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
import graphviz
def add_nodes_and_edges(dot: graphviz.Digraph, parent_id: str, nodes_list: list, current_depth: int, base_color: str):
"""
Recursively adds nodes and edges to a Graphviz Digraph object,
applying a color gradient and consistent styling.
Args:
dot (graphviz.Digraph): The Graphviz Digraph object to modify.
parent_id (str): The ID of the parent node for the current set of nodes.
nodes_list (list): A list of dictionaries, each representing a node
with 'id', 'label', 'relationship', and optional 'subnodes'.
current_depth (int): The current depth in the graph hierarchy (0 for central node).
base_color (str): The hexadecimal base color for the deepest nodes.
"""
# Calculate color for current depth, making it lighter
# This factor determines how quickly the color lightens per level.
lightening_factor = 0.12
# Convert base_color hex to RGB for interpolation
# Ensure base_color is a valid hex string before converting
if not isinstance(base_color, str) or not base_color.startswith('#') or len(base_color) != 7:
base_color = '#19191a' # Fallback to default dark if invalid
base_r = int(base_color[1:3], 16)
base_g = int(base_color[3:5], 16)
base_b = int(base_color[5:7], 16)
# Calculate current node color by blending towards white
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)
# Clamp values to 255 to stay within valid RGB range
current_r = min(255, current_r)
current_g = min(255, current_g)
current_b = min(255, current_b)
node_fill_color = f'#{current_r:02x}{current_g:02x}{current_b:02x}'
# Font color: white for dark nodes, black for very light nodes for readability
font_color = 'white' if current_depth * lightening_factor < 0.6 else 'black'
# Edge colors and font sizes
edge_color = '#4a4a4a' # Dark gray for lines
# Font size adjusts based on depth, ensuring a minimum size
font_size = max(9, 14 - (current_depth * 2))
edge_font_size = max(7, 10 - (current_depth * 1))
for node in nodes_list:
node_id = node.get('id')
label = node.get('label')
relationship = node.get('relationship')
# Basic validation for node data
if not all([node_id, label, relationship]):
raise ValueError(f"Invalid node: {node}")
# Add node with specified style
dot.node(
node_id,
label,
shape='box', # All nodes are rectangular
style='filled,rounded', # Filled and rounded corners
fillcolor=node_fill_color,
fontcolor=font_color,
fontsize=str(font_size)
)
# Add edge from parent to current node
dot.edge(
parent_id,
node_id,
label=relationship,
color=edge_color,
fontcolor=edge_color, # Edge label color also dark gray
fontsize=str(edge_font_size)
)
# Recursively call for subnodes
if 'subnodes' in node:
add_nodes_and_edges(dot, node_id, node['subnodes'], current_depth + 1, base_color)
# import graphviz
# def add_nodes_and_edges(dot: graphviz.Digraph, parent_id: str, nodes_list: list, current_depth: int, base_color: str):
# """
# Recursively adds nodes and edges to a Graphviz Digraph object,
# applying a color gradient and consistent styling.
# Args:
# dot (graphviz.Digraph): The Graphviz Digraph object to modify.
# parent_id (str): The ID of the parent node for the current set of nodes.
# nodes_list (list): A list of dictionaries, each representing a node
# with 'id', 'label', 'relationship', and optional 'subnodes'.
# current_depth (int): The current depth in the graph hierarchy (0 for central node).
# base_color (str): The hexadecimal base color for the deepest nodes.
# """
# lightening_factor = 0.06
# if not isinstance(base_color, str) or not base_color.startswith('#') or len(base_color) != 7:
# base_color = '#BEBEBE'
# base_r = int(base_color[1:3], 16)
# base_g = int(base_color[3:5], 16)
# base_b = int(base_color[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_fill_color = f'#{current_r:02x}{current_g:02x}{current_b:02x}'
# font_color = 'black'
# edge_color = '#4a4a4a'
# font_size = max(9, 14 - (current_depth * 2))
# edge_font_size = max(7, 10 - (current_depth * 1))
# for node in nodes_list:
# node_id = node.get('id')
# label = node.get('label')
# relationship = node.get('relationship')
# if not all([node_id, label, relationship]):
# raise ValueError(f"Invalid node: {node}")
# dot.node(
# node_id,
# label,
# shape='box',
# style='filled,rounded',
# fillcolor=node_fill_color,
# fontcolor=font_color,
# fontsize=str(font_size)
# )
# dot.edge(
# parent_id,
# node_id,
# label=relationship,
# color=edge_color,
# fontcolor=edge_color,
# fontsize=str(edge_font_size)
# )
# if 'subnodes' in node:
# add_nodes_and_edges(dot, node_id, node['subnodes'], current_depth + 1, base_color) |