This project is a local Python desktop app for replaying classic graph search algorithms on a real OpenStreetMap road network. It keeps OSMnx for map download/caching, NetworkX for the graph/search logic, and now uses PySide6 + PyQtGraph for a faster, more spacious simulation dashboard.
The default scenario uses Melbourne only as a demo:
- Place:
Melbourne, Victoria, Australia - Start:
Monash University Clayton campus - Goal:
State Library Victoria, Melbourne
You can change the city, network type, start, and goal without touching the core search or visualization code.
main.py: CLI entry point, scenario loading, headless summary mode, and app launchalgorithms.py: BFS, DFS, Dijkstra, A*, and Greedy Best-First Search with replay tracesmap_utils.py: OSM loading, caching, geocoding, nearest-node lookup, and graph helpersui.py: PySide6 desktop window, controls, metrics panels, and playback orchestrationvisualization.py: PyQtGraph map canvas, layered overlays, and rendering helpersconfig.py: editable defaults for place, endpoints, network type, speed, and playback tuningrequirements.txt: Python dependencies
- Real road/walking/bike networks from OpenStreetMap
- Configurable:
place_namenetwork_typestart_querygoal_query- direct coordinates for start/goal
- selected algorithm
- animation speed
- batch stepping
- Resizable PySide6 desktop dashboard with:
- large main map area
- right control sidebar
- lower metrics and summary panels
- splitter-based layout
- Fast PyQtGraph rendering:
- base map drawn once
- lightweight overlay updates during playback
- brighter recent search trail
- emphasized frontier
- final path overlay
- Route update workflow from the UI with background scenario loading
- Sequential compare mode
- Metrics for every algorithm:
- runtime
- explored nodes
- path cost
- path length
- found/not found
- optimal/not optimal under the chosen weighting
- Optional CSV export of summary metrics
- Local graph caching in
cache/graphs/
Activate your environment, then install the dependencies:
conda activate pathfinder
pip install -r requirements.txtOr use the environment Python directly:
C:\Users\han\anaconda3\envs\pathfinder\python.exe -m pip install -r requirements.txtDefault Melbourne demo:
python main.pyOr:
C:\Users\han\anaconda3\envs\pathfinder\python.exe main.pyThe first run can take a while because the app downloads/caches the map and precomputes all algorithm traces. After that, reruns are much faster.
- The map is the main visual focus on the left.
- The right sidebar contains:
Route SetupAlgorithmPlayback
- The lower panel contains:
- live metrics
- a summary table for all algorithms
- session/legend information
Load / Update Scenario: load a new city/start/goal/network combinationStart / Resume: begin playbackPause: stop playback without resettingNext Step: advance one search stepReset: restart the current algorithm replaySpeed: increases base playback rateBatch: advances multiple search steps per timer tickSequential compare mode: automatically rolls through the algorithmsAdaptive stepping: slower near the start/end, faster in the middle of long runs
Edit config.py, or override settings from the CLI.
Example defaults:
DEFAULT_CONFIG = SimulationConfig(
place_name="Melbourne, Victoria, Australia",
network_type="walk",
start_query="Monash University Clayton campus",
goal_query="State Library Victoria, Melbourne",
graph_radius_m=12000.0,
animation_speed=8.0,
batch_steps=1,
compare_mode=False,
selected_algorithm="A*",
)The default demo uses a route-centered graph radius so the working graph stays reasonable.
Start on Dijkstra:
python main.py --algorithm DijkstraEnable compare mode:
python main.py --compare-modeIncrease playback throughput:
python main.py --animation-speed 12 --batch-steps 3Use another city:
python main.py `
--place-name "Sydney, New South Wales, Australia" `
--start-query "University of Sydney" `
--goal-query "Sydney Opera House" `
--network-type walkUse direct coordinates:
python main.py `
--place-name "Melbourne, Victoria, Australia" `
--start-lat -37.9106 --start-lon 145.1362 `
--goal-lat -37.8097 --goal-lon 144.9653If a place is large, use a working graph radius so the app loads a point-centered subgraph around the route corridor instead of the whole place:
python main.py `
--place-name "Victoria, Australia" `
--start-query "Monash University Clayton campus" `
--goal-query "State Library Victoria, Melbourne" `
--graph-radius-m 12000When --graph-radius-m is set, the app downloads a graph around the midpoint between start and goal, expanded by the straight-line distance plus a buffer.
- BFS and DFS ignore edge weights by design.
- Dijkstra and A* use OSM edge
lengthas the route cost. - A* uses straight-line geographic distance to the goal as the heuristic.
- Greedy Best-First Search uses only the heuristic and is not guaranteed to be optimal.
- Dijkstra and A* should match on weighted path cost when both find a path.
You can still precompute everything without launching the GUI:
python main.py --no-gui --metrics-csv outputs/search_metrics.csvThe CSV includes:
- runtime
- explored nodes
- path cost
- path length
- found/not found
- optimal/not optimal
- Queries work best when they are specific, for example
State Library Victoria, Melbourne. - The resolver tries both the raw query and a place-qualified variant such as
<query>, <place_name>. - If geocoding fails or is ambiguous, provide explicit coordinates instead.
