@@ -30,11 +30,9 @@ def visualize_cbs_tree(
3030 node_colors .append ("lightblue" )
3131 node_sizes .append (initial_size )
3232
33- # Add edge from parent
34- # if node.parent_idx is not None:
33+ # Add edge from parent only if parent exists in expanded_nodes
3534 if node .parent_idx is not None and node .parent_idx in expanded_nodes :
3635 G .add_edge (node .parent_idx , idx )
37- # G.add_edge(0, 5)
3836 print (f"adding edge btwn { node .parent_idx } and { idx } " )
3937
4038 # Add unexpanded nodes
@@ -52,44 +50,86 @@ def visualize_cbs_tree(
5250 # if node.parent_idx is not None and node.parent_idx >= 0:
5351 # G.add_edge(node.parent_idx, idx)
5452
53+ # Debug: print all edges in the graph
54+ print (f"\n All edges in graph: { list (G .edges ())} " )
55+ print (f"All nodes in graph: { list (G .nodes ())} " )
56+
57+
5558 # Use hierarchical layout with fixed horizontal spacing
56- pos = _hierarchy_pos (G , root = next (iter (G .nodes ()), None ), vert_gap = 0.3 , horiz_gap = 1.5 )
59+ # Handle disconnected components
60+ pos = {}
61+ x_offset = 0
62+ for component in nx .weakly_connected_components (G ):
63+ subgraph = G .subgraph (component )
64+ root = next (iter (subgraph .nodes ()))
65+ component_pos = _hierarchy_pos (subgraph , root = root , vert_gap = 0.3 , horiz_gap = 3.0 )
66+
67+ # Offset each component horizontally to avoid overlap
68+ for node , (x , y ) in component_pos .items ():
69+ pos [node ] = (x + x_offset , y )
70+
71+ # Increment x_offset for next component
72+ if len (component_pos ) > 0 :
73+ x_offset += max (x for x , y in component_pos .values ()) + 3
5774
58- # Extract edge coordinates
75+ print (f"Positions: { pos } " )
76+
77+ # Extract edge coordinates with hover text
5978 edge_x = []
6079 edge_y = []
80+ edge_text = []
6181 for edge in G .edges ():
6282 print (f"Drawing edge: { edge } " )
6383 if edge [0 ] in pos and edge [1 ] in pos :
6484 x0 , y0 = pos [edge [0 ]]
6585 x1 , y1 = pos [edge [1 ]]
86+ print (f" From ({ x0 } , { y0 } ) to ({ x1 } , { y1 } )" )
6687 edge_x .extend ([x0 , x1 , None ])
6788 edge_y .extend ([y0 , y1 , None ])
89+ edge_text .extend ([f"Node { edge [0 ]} → Node { edge [1 ]} " , f"Node { edge [0 ]} → Node { edge [1 ]} " , None ])
6890 else :
91+ print (f" Edge position not found" )
6992 edge_x .extend ([1 , 1 , None ])
7093 edge_y .extend ([5 , 5 , None ])
71-
94+ edge_text .extend ([f"Node { edge [0 ]} → Node { edge [1 ]} " , f"Node { edge [0 ]} → Node { edge [1 ]} " , None ])
95+
7296 # Extract node coordinates
7397 node_x = []
7498 node_y = []
75- for node in G .nodes ():
99+ node_list = list (G .nodes ())
100+ for node in node_list :
76101 x , y = 1 , 1
77102 if node in pos :
78103 x , y = pos [node ]
104+ else :
105+ print (f"WARNING: Node { node } not in positions!" )
79106 node_x .append (x )
80107 node_y .append (y )
81108
109+ print (f"Node coordinates: { list (zip (node_list , node_x , node_y ))} " )
110+
82111 # Create figure
83112 fig = go .Figure ()
84113
85- # Add edges
114+ # Add edges (visible lines)
86115 fig .add_trace (go .Scatter (
87116 x = edge_x , y = edge_y ,
88117 mode = 'lines' ,
89118 line = dict (width = 2 , color = '#888' ),
90119 hoverinfo = 'none' ,
91120 showlegend = False
92121 ))
122+
123+ # Add invisible thick edges for hover detection
124+ fig .add_trace (go .Scatter (
125+ x = edge_x , y = edge_y ,
126+ mode = 'lines' ,
127+ line = dict (width = 20 , color = 'rgba(0,0,0,0)' ),
128+ text = edge_text ,
129+ hoverinfo = 'text' ,
130+ showlegend = False
131+ ))
132+
93133 # Add nodes
94134 fig .add_trace (go .Scatter (
95135 x = node_x , y = node_y ,
@@ -99,10 +139,10 @@ def visualize_cbs_tree(
99139 color = node_colors ,
100140 line = dict (width = 2 , color = 'darkblue' )
101141 ),
102- text = [node_labels [ node ] for node in G . nodes () if node in node_labels ],
142+ text = [node_labels . get ( node , f"Node { node } " ) for node in node_list ],
103143 hoverinfo = 'text' ,
104144 showlegend = False ,
105- customdata = list ( G . nodes ())
145+ customdata = node_list
106146 ))
107147
108148 fig .update_layout (
@@ -157,26 +197,33 @@ def visualize_cbs_tree(
157197def _hierarchy_pos (G , root = None , vert_gap = 0.2 , horiz_gap = 1.0 , xcenter = 0.5 ):
158198 """
159199 Create hierarchical layout for tree visualization with fixed horizontal spacing.
200+ Spreads nodes wide at each level to avoid overlaps.
160201 """
161202 if not nx .is_tree (G ):
162203 G = nx .DiGraph (G )
163204
164- def _hierarchy_pos_recursive (G , root , vert_gap = 0.2 , horiz_gap = 1.0 , xcenter = 0.5 , pos = None , parent = None , child_index = 0 ):
205+ def _hierarchy_pos_recursive (G , root , vert_gap = 0.2 , horiz_gap = 1.0 , xcenter = 0.5 , pos = None , parent = None , child_index = 0 , level_nodes = None ):
165206 if pos is None :
166207 pos = {root : (xcenter , 0 )}
208+ level_nodes = {0 : [root ]}
167209 else :
210+ level = pos [parent ][1 ] / (- vert_gap )
168211 pos [root ] = (xcenter , pos [parent ][1 ] - vert_gap )
212+ if int (level ) + 1 not in level_nodes :
213+ level_nodes [int (level ) + 1 ] = []
214+ level_nodes [int (level ) + 1 ].append (root )
169215
170216 neighbors = list (G .neighbors (root ))
171217
172218 if len (neighbors ) != 0 :
173219 num_children = len (neighbors )
174- # Spread children horizontally with fixed gap
175- start_x = xcenter - (num_children - 1 ) * horiz_gap / 2
220+ # Spread children very wide to avoid any overlap
221+ spread = num_children * horiz_gap * 2
222+ start_x = xcenter - spread / 2
176223 for i , neighbor in enumerate (neighbors ):
177- nextx = start_x + i * horiz_gap
224+ nextx = start_x + i * ( spread / max ( num_children - 1 , 1 ))
178225 _hierarchy_pos_recursive (G , neighbor , vert_gap = vert_gap , horiz_gap = horiz_gap ,
179- xcenter = nextx , pos = pos , parent = root , child_index = i )
226+ xcenter = nextx , pos = pos , parent = root , child_index = i , level_nodes = level_nodes )
180227
181228 return pos
182229
0 commit comments