Improve visualizations

This commit is contained in:
Jan Petykiewicz 2026-03-08 22:13:10 -07:00
commit 43a9a6cb3a
9 changed files with 35 additions and 9 deletions

View file

@ -49,7 +49,7 @@ def main() -> None:
print("Failed to route.")
# 5. Visualize
fig, ax = plot_routing_results(results, [obstacle], bounds)
fig, ax = plot_routing_results(results, [obstacle], bounds, netlist=netlist)
fig.savefig("examples/simple_route.png")
print("Saved plot to examples/simple_route.png")

View file

@ -45,7 +45,7 @@ def main() -> None:
print(f" {nid}: valid={res.is_valid}, collisions={res.collisions}")
# 5. Visualize
fig, ax = plot_routing_results(results, [], bounds)
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
fig.savefig("examples/congestion.png")
print("Saved plot to examples/congestion.png")

View file

@ -59,16 +59,18 @@ def main() -> None:
print("Failed to route secondary net.")
# 5. Visualize
# Combine results for plotting
# Combine results and netlists for plotting
all_results = {**results1, **results2}
all_netlists = {**netlist_phase1, **netlist_phase2}
# Note: 'critical_net' is now in engine.static_obstacles internally,
# Note: 'critical_net' is now in engine.static_obstacles internally,
# but for visualization we plot it from the result object to see it clearly.
# We pass an empty list for 'static_obstacles' to plot_routing_results
# We pass an empty list for 'static_obstacles' to plot_routing_results
# because we want to see the path colored, not grayed out as an obstacle.
fig, ax = plot_routing_results(all_results, [], bounds)
fig, ax = plot_routing_results(all_results, [], bounds, netlist=all_netlists)
fig.savefig("examples/locked.png")
print("Saved plot to examples/locked.png")

View file

@ -61,7 +61,7 @@ def main() -> None:
print(f"{nid}: {status}, collisions={res.collisions}")
# 6. Visualize
fig, ax = plot_routing_results(results, [], bounds)
fig, ax = plot_routing_results(results, [], bounds, netlist=netlist)
fig.savefig("examples/sbends_radii.png")
print("Saved plot to examples/sbends_radii.png")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before After
Before After

View file

@ -3,12 +3,14 @@ from __future__ import annotations
from typing import TYPE_CHECKING
import matplotlib.pyplot as plt
import numpy as np
if TYPE_CHECKING:
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from shapely.geometry import Polygon
from inire.geometry.primitives import Port
from inire.router.pathfinder import RoutingResult
@ -16,6 +18,7 @@ def plot_routing_results(
results: dict[str, RoutingResult],
static_obstacles: list[Polygon],
bounds: tuple[float, float, float, float],
netlist: dict[str, tuple[Port, Port]] | None = None,
) -> tuple[Figure, Axes]:
"""Plot obstacles and routed paths using matplotlib."""
fig, ax = plt.subplots(figsize=(10, 10))
@ -34,7 +37,8 @@ def plot_routing_results(
color = "red" # Highlight failing nets
label_added = False
for comp in res.path:
for j, comp in enumerate(res.path):
# 1. Plot geometry
for poly in comp.geometry:
# Handle both Polygon and MultiPolygon (e.g. from SBend)
geoms = [poly] if hasattr(poly, "exterior") else poly.geoms
@ -43,6 +47,26 @@ def plot_routing_results(
ax.fill(x, y, alpha=0.7, fc=color, ec="black", label=net_id if not label_added else "")
label_added = True
# 2. Plot subtle port orientation arrow for internal ports
# (Every segment's end_port except possibly the last one if it matches target)
p = comp.end_port
rad = np.radians(p.orientation)
u = np.cos(rad)
v = np.sin(rad)
# Internal ports get smaller, narrower, semi-transparent arrows
ax.quiver(p.x, p.y, u, v, color="black", scale=40, width=0.003, alpha=0.3, pivot="tail", zorder=4)
# 3. Plot main arrows for netlist ports (if provided)
if netlist and net_id in netlist:
start_p, target_p = netlist[net_id]
for p in [start_p, target_p]:
rad = np.radians(p.orientation)
u = np.cos(rad)
v = np.sin(rad)
# Netlist ports get prominent arrows
ax.quiver(p.x, p.y, u, v, color="black", scale=25, width=0.005, pivot="tail", zorder=6)
ax.set_xlim(bounds[0], bounds[2])
ax.set_ylim(bounds[1], bounds[3])
ax.set_aspect("equal")
@ -51,5 +75,5 @@ def plot_routing_results(
handles, labels = ax.get_legend_handles_labels()
if labels:
ax.legend()
plt.grid(True)
ax.grid(alpha=0.6)
return fig, ax