Source code for ware_ops_algos.utils.visualization

from datetime import timezone

import networkx as nx
import pandas as pd
from matplotlib import pyplot as plt


[docs] def render_graph(G, plot: bool = True, out_name=False, draw_edge_labels=False, with_labels=False, dpi=700, font_size=5, node_size=50, node_color='lightblue') -> None: pos = nx.get_node_attributes(G, 'pos') nx.draw(G, pos=pos, with_labels=with_labels, node_color=node_color, font_size=font_size, node_size=node_size) weight = nx.get_edge_attributes(G, 'weight') if draw_edge_labels: nx.draw_networkx_edge_labels(G, pos, edge_labels=weight, font_size=font_size) if out_name: plt.savefig(out_name, dpi=dpi) if plot: plt.show()
[docs] def plot_route(network_graph: nx.Graph, route: list[tuple[int, int]]): """Visualizes a picker route""" pos = nx.get_node_attributes(network_graph, 'pos') plt.figure(figsize=(10, 8)) plt.title("Route Visualization") nx.draw(network_graph, pos, with_labels=False, node_size=30, node_color='lightgray', edge_color='lightgray', alpha=0.3) edges = [(route[i], route[i + 1]) for i in range(len(route) - 1)] nx.draw_networkx_edges(network_graph, pos, edgelist=edges, edge_color='red', width=6) plt.show()
[docs] def plot_route_with_directions(network_graph: nx.Graph, route: list[tuple[int, int]]): """Visualizes a picker route with direction arrows, including repeated edges.""" pos = nx.get_node_attributes(network_graph, 'pos') plt.figure(figsize=(10, 8)) plt.title("Route with Directions") # Draw the base graph nx.draw(network_graph, pos, with_labels=False, node_size=30, node_color='lightgray', edge_color='lightgray', alpha=0.3) # Count edge directions edge_counts = {} for i in range(len(route) - 1): start, end = route[i], route[i + 1] key = (start, end) edge_counts[key] = edge_counts.get(key, 0) + 1 for i in range(len(route) - 1): start, end = route[i], route[i + 1] x1, y1 = pos[start] x2, y2 = pos[end] dx = x2 - x1 dy = y2 - y1 offset = 0.05 * (edge_counts[(start, end)] - 1) + 0.1 norm = (dx ** 2 + dy ** 2) ** 0.5 offset_x = -dy / norm * offset offset_y = dx / norm * offset plt.arrow(x1 + offset_x, y1 + offset_y, dx * 0.9, dy * 0.9, length_includes_head=True, head_width=0.15, head_length=0.2, fc='red', ec='red') plt.axis('off') plt.show()
[docs] def plot_picker_gantt(assignments, use_datetime=False, tz=timezone.utc, figsize=(12, 6)): """ Visualize batch assignments per picker as a Gantt chart. - assignments: list of dicts (output from schedule_routing_batches) or a DataFrame required keys/cols: picker_id, batch_idx, start_time, end_time - use_datetime: if True, convert epoch seconds to datetimes for the x-axis - tz: timezone for datetime display when use_datetime=True """ df = pd.DataFrame(assignments) if not isinstance(assignments, pd.DataFrame) else assignments.copy() df = df.sort_values(["picker_id", "start_time", "batch_idx"]).reset_index(drop=True) x_start = df["start_time"].min() x_end = df["end_time"].max() pickers = sorted(df["picker_id"].unique()) picker_to_y = {pid: i for i, pid in enumerate(pickers)} if use_datetime: df["_x_start"] = pd.to_datetime(df["start_time"], unit="s", utc=True).dt.tz_convert(tz) df["_x_end"] = pd.to_datetime(df["end_time"], unit="s", utc=True).dt.tz_convert(tz) xtitle = f"Time ({tz})" else: df["_x_start"] = df["start_time"] df["_x_end"] = df["end_time"] xtitle = "Time (units)" fig, ax = plt.subplots(figsize=figsize) height = 0.8 # lane height for _, row in df.iterrows(): y = picker_to_y[row["picker_id"]] start = row["_x_start"] end = row["_x_end"] width = end - start ax.barh(y=y, width=width, left=start, height=height, align="center", edgecolor="black") # Label with batch_idx (small) ax.text(start, y, f"#{int(row['batch_idx'])}", va="center", ha="left", fontsize=8) ax.set_yticks(list(picker_to_y.values())) ax.set_yticklabels([f"Picker {pid}" for pid in pickers]) ax.set_xlabel(xtitle) ax.set_title("Batch Assignment per Picker (Gantt)") ax.grid(True, axis="x", linestyle="--", alpha=0.4) if not use_datetime: ax.set_xlim(left=min(x_start, df["_x_start"].min()), right=max(x_end, df["_x_end"].max())) fig.tight_layout() plt.show()