1717
1818import os
1919from pathlib import Path
20+ import sys
2021from PIL import Image
22+ import keyboard
2123from Parsing import get_full_graph
2224import matplotlib .pyplot as plt
2325import matplotlib .patches as mpatches
2426import networkx as nx
2527import json
2628
29+ def get_node_label (node ):
30+ if node [1 ]['name' ] != None :
31+ return node [1 ]['name' ]
32+ else :
33+ return ""
34+
2735def base_graph (G , ax , pos , label_edges = True ):
2836 # Draw nodes with different colors based on node types
2937 node_colors = []
@@ -33,15 +41,25 @@ def base_graph(G, ax, pos, label_edges = True):
3341 node_colors .append ('green' )
3442 elif 'node_type' in node_data [1 ] and node_data [1 ]['node_type' ] == 'Delivery Node' :
3543 node_colors .append ('blue' )
44+ elif 'node_type' in node_data [1 ] and node_data [1 ]['node_type' ] == 'Depot Node' :
45+ node_colors .append ('red' )
3646 else :
3747 node_colors .append ('gray' ) # Default color
3848 ax .text (pos [node ][0 ], pos [node ][1 ], str (node_data [1 ]['node_id' ]), fontsize = 8 , ha = 'center' , va = 'center' , color = "white" )
3949
4050 nx .draw_networkx_nodes (G , pos , ax = ax , node_size = 100 , node_color = node_colors )
41- nx .draw_networkx_edges (G , pos , ax = ax , edge_color = 'black' , width = 1 , arrows = False )
51+ nx .draw_networkx_edges (G , pos , ax = ax , edge_color = 'black' , width = 0.5 , arrows = False )
4252
43- # Draw edge labels with weights
4453 if label_edges :
54+ node_labels = {node [1 ]['node_id' ]: get_node_label (node ) for node in G .nodes (data = True )}
55+ for node , label in node_labels .items ():
56+ node_pos = pos [node ]
57+ x_offset = 0.5
58+ y_offset = - 0.8
59+ label_pos = [node_pos [0 ] + x_offset , node_pos [1 ] + y_offset ]
60+ plt .text (* label_pos , label , ha = 'center' , va = 'center' , fontsize = 6 ,
61+ bbox = dict (boxstyle = "round" , facecolor = 'lightblue' , alpha = 0.3 , edgecolor = "none" ))
62+
4563 edge_labels = nx .get_edge_attributes (G , 'weight' )
4664 nx .draw_networkx_edge_labels (G , pos , ax = ax , edge_labels = edge_labels , font_size = 7 )
4765
@@ -51,7 +69,7 @@ def base_graph(G, ax, pos, label_edges = True):
5169 center_x = (min (x_values ) + max (x_values )) / 2
5270 center_y = (min (y_values ) + max (y_values )) / 2
5371
54- ax .grid (True , linestyle = '-' , linewidth = 0.5 , color = 'gray' , zorder = 0 )
72+ ax .grid (True , linestyle = '-' , linewidth = 0.3 , color = 'gray' , zorder = 0 )
5573 # Set the x and y ticks with increments of 1
5674 x_ticks = range (int (min (x_values )), int (max (x_values )) + 1 )
5775 y_ticks = range (int (min (y_values )), int (max (y_values )) + 1 )
@@ -65,7 +83,8 @@ def base_graph(G, ax, pos, label_edges = True):
6583 mpatches .Patch (color = 'blue' , label = 'Delivery Node' ),
6684 mpatches .Patch (color = 'red' , label = 'Depot Node' ),
6785 mpatches .Patch (color = 'gray' , label = 'Junction Node' )]
68- ax .legend (handles = legend_handles )
86+ prop = {'size' : 7 } # Adjust font size as needed
87+ ax .legend (handles = legend_handles , prop = prop )
6988
7089 return ax
7190
@@ -80,18 +99,34 @@ def plot_overall_solution(graph, pos, solution_dir):
8099 with open (solution_dir + "chosen_x_ijk.json" , "r" ) as json_file :
81100 chosen_x_ijk = json .load (json_file )
82101
102+ graph .remove_edges_from (list (graph .edges ()))
103+
104+ bus_cnt = 0
83105 for bus , arc in chosen_x_ijk .items ():
84106 fig , ax = plt .subplots (figsize = (8 , 6 ))
85- ax = base_graph (graph , ax , pos , True )
86-
87- graph .remove_edges_from (list (graph .edges ()))
107+ fig .suptitle ('Bus ' + str (bus_cnt ) , fontsize = 20 )
108+ ax .clear ()
88109 graph .add_edges_from (arc )
110+ ax = base_graph (graph , ax , pos , False )
89111
90- nx .draw_networkx_edges (graph , pos , ax = ax , edge_color = 'red' , width = 1 , arrows = False )
112+ nx .draw_networkx_edges (graph , pos , ax = ax ,
113+ edge_color = 'red' , width = 1 , arrows = True )
114+ graph .remove_edges_from (arc )
115+ bus_cnt += 1
91116
92117 plt .show ()
93118
119+ space_pressed = False
120+
121+ def on_key_press (event ):
122+ global space_pressed
123+ if event .key == ' ' :
124+ space_pressed = True
125+ elif event .key == 'q' :
126+ sys .exit ()
127+
94128def plot_step_by_step (graph , pos , solution_dir , Gif = False ):
129+ global space_pressed
95130
96131 # Read the JSON file
97132 with open (solution_dir + "buses_paths.json" , "r" ) as json_file :
@@ -104,15 +139,49 @@ def plot_step_by_step(graph, pos, solution_dir, Gif=False):
104139
105140 bus_cnt = 0
106141 for bus , movements in buses_paths .items ():
142+ total_cost = 0
107143 fig , ax = plt .subplots (figsize = (8 , 6 ))
108144 fig .suptitle ('Bus ' + str (bus_cnt ) , fontsize = 20 )
145+ fig .canvas .mpl_connect ('key_press_event' , on_key_press )
146+ ax = base_graph (graph , ax , pos , False )
109147
110- for idx , info in enumerate (movements ):
148+ valid_movements = []
149+ for info in movements :
150+ if len (info ['path' ]) > 1 :
151+ valid_movements .append (info )
152+
153+ for idx , info in enumerate (valid_movements ):
111154 paths = info ['path' ]
112155 ax .clear ()
113- ax = base_graph (graph , ax , pos , True )
156+ ax = base_graph (graph , ax , pos , False )
157+ y_lim = plt .ylim ()
158+ x_lim = plt .xlim ()
159+ plt .ylim (y_lim [0 ], y_lim [1 ] * 1.2 )
160+
161+ x_center = (x_lim [0 ] + x_lim [1 ]) / 2
114162
115163 if Gif :
164+ text = info ['status' ]
165+ plt .text (x_center , y_lim [1 ] * 1.1 , text , ha = 'center' , va = 'center' ,
166+ fontsize = 10 , color = 'white' ,
167+ bbox = dict (boxstyle = "round" , facecolor = 'black' , edgecolor = "none" ))
168+
169+ load_text = f"Load : { info ['start_load' ]} -> { info ['finish_load' ]} "
170+ plt .text (x_lim [0 ], y_lim [1 ] * 1.15 , load_text , ha = 'left' ,
171+ va = 'center' , fontsize = 8 , color = 'white' ,
172+ bbox = dict (boxstyle = "round" , facecolor = 'purple' , edgecolor = "none" ))
173+
174+ time_text = f"Time : { info ['start_time' ]} -> { info ['finish_time' ]} "
175+ plt .text (x_lim [0 ], y_lim [1 ] * 1.05 , time_text , ha = 'left' ,
176+ va = 'center' , fontsize = 8 , color = 'white' ,
177+ bbox = dict (boxstyle = "round" , facecolor = 'blue' , edgecolor = "none" ))
178+
179+ total_cost += int (info ['path_cost' ])
180+ cost_text = f"Cost : { info ['path_cost' ]} - total Cost : { total_cost } "
181+ plt .text (x_lim [0 ], y_lim [1 ] * 0.95 , cost_text , ha = 'left' ,
182+ va = 'center' , fontsize = 8 , color = 'white' ,
183+ bbox = dict (boxstyle = "round" , facecolor = 'brown' , edgecolor = "none" ))
184+
116185 edges = list (zip (paths , paths [1 :]))
117186 nx .draw_networkx_edges (graph , pos , edgelist = edges , ax = ax , edge_color = 'r' ,
118187 width = 2 , arrows = True )
@@ -121,38 +190,53 @@ def plot_step_by_step(graph, pos, solution_dir, Gif=False):
121190 fig .savefig (frame_filename )
122191
123192 else :
124- if idx == 0 :
125- plt .pause (2 )
126- elif idx == len (movements ) - 1 :
127- edges = []
128- for segment in movements :
129- path = segment ['path' ]
130- if len (path ) > 2 :
131- for i in range (len (path ) - 1 ):
132- edges .append ((path [i ],path [i + 1 ]))
133- elif len (path ) == 2 :
134- edges .append (tuple (path ))
135- nx .draw_networkx_edges (graph , pos , edgelist = edges , ax = ax , edge_color = 'r' , width = 2 , arrows = False )
136- else :
137- edges = list (zip (paths , paths [1 :]))
138- nx .draw_networkx_edges (graph , pos , edgelist = edges , ax = ax , edge_color = 'r' , width = 2 , arrows = True )
139- plt .pause (1 )
193+ text = info ['status' ]
194+ plt .text (x_center , y_lim [1 ] * 1.1 , text , ha = 'center' , va = 'center' ,
195+ fontsize = 10 , color = 'white' ,
196+ bbox = dict (boxstyle = "round" , facecolor = 'black' , edgecolor = "none" ))
197+
198+ load_text = f"Load : { info ['start_load' ]} -> { info ['finish_load' ]} "
199+ plt .text (x_lim [0 ], y_lim [1 ] * 1.15 , load_text , ha = 'left' ,
200+ va = 'center' , fontsize = 8 , color = 'white' ,
201+ bbox = dict (boxstyle = "round" , facecolor = 'purple' , edgecolor = "none" ))
202+
203+ time_text = f"Time : { info ['start_time' ]} -> { info ['finish_time' ]} "
204+ plt .text (x_lim [0 ], y_lim [1 ] * 1.05 , time_text , ha = 'left' ,
205+ va = 'center' , fontsize = 8 , color = 'white' ,
206+ bbox = dict (boxstyle = "round" , facecolor = 'blue' , edgecolor = "none" ))
207+
208+ total_cost += int (info ['path_cost' ])
209+ cost_text = f"Cost : { info ['path_cost' ]} - total Cost : { total_cost } "
210+ plt .text (x_lim [0 ], y_lim [1 ] * 0.95 , cost_text , ha = 'left' ,
211+ va = 'center' , fontsize = 8 , color = 'white' ,
212+ bbox = dict (boxstyle = "round" , facecolor = 'brown' , edgecolor = "none" ))
213+
214+ edges = list (zip (paths , paths [1 :]))
215+ nx .draw_networkx_edges (graph , pos , edgelist = edges , ax = ax , edge_color = 'r' ,
216+ width = 2 , arrows = True )
217+
218+ while not space_pressed :
219+ plt .pause (0.1 )
220+ space_pressed = False
140221
141222 if Gif :
142- frames = [Image .open (f'{ gif_dir } /{ frame } ' ) for frame in sorted (os .listdir (gif_dir )) if frame .endswith (".png" )]
223+ frames = [Image .open (f'{ gif_dir } /{ frame } ' ) for frame in sorted (os .listdir (gif_dir ))
224+ if frame .endswith (".png" )]
143225 gif_filename = f'{ gif_dir } /bus_{ bus } .gif'
144226 frames [0 ].save (gif_filename , format = 'GIF' , append_images = frames [1 :],
145227 save_all = True , duration = 1000 , loop = 0 )
146228 [f .unlink () for f in Path (gif_dir ).glob ("*" ) if f .name .endswith (".png" )]
147229
148230 bus_cnt += 1
231+ plt .close (fig )
149232
150233 if not Gif :
151234 plt .show ()
152235
153236def main ():
154237 # Specify the folder name under the Inputs folder
155- problem_dir = input ("\n Enter folder name of the problem\n " )
238+ print ("-------------" )
239+ problem_dir = input ("Enter folder name of the problem\n " )
156240
157241 base_directory = "Samples/" + problem_dir + "/"
158242 solution_dir = base_directory + "Solution/"
0 commit comments