xrspatial.pathfinding.a_star_search#
- xrspatial.pathfinding.a_star_search(surface: DataArray, start: tuple | list | array, goal: tuple | list | array, barriers: list = [], x: str | None = 'x', y: str | None = 'y', connectivity: int = 8, snap_start: bool = False, snap_goal: bool = False, friction: DataArray = None, search_radius: int | None = None) DataArray[source]#
Calculate the least-cost path from a starting point to a goal through a surface graph, optionally weighted by a friction surface.
A* is a modification of Dijkstra’s Algorithm that is optimized for a single destination. It prioritizes paths that seem to be leading closer to a goal using an admissible heuristic.
When a friction surface is provided, edge costs are
geometric_distance * mean_friction_of_endpoints, matching the cost model used bycost_distance(). The heuristic is scaled by the minimum friction value to remain admissible.The output is an equal-sized
xr.DataArraywith NaN for non-path pixels and the accumulated cost at each path pixel.Backend support
Backend
Strategy
NumPy
Numba-jitted kernel (fast, in-memory)
Dask
Sparse Python A* with LRU chunk cache — loads chunks on demand so the full grid never needs to fit in RAM
CuPy
CPU fallback (transfers to numpy, runs numba kernel, transfers back)
Dask + CuPy
Same sparse A* as Dask, with cupy→numpy chunk conversion
Memory safety
Before allocating arrays, the numpy and cupy backends check whether the grid would exceed 80 % of available RAM. If so, a
MemoryErroris raised suggestingsearch_radiusor dask. Whensearch_radius=Noneand the grid would exceed 50 % of RAM, an automatic radius is computed. For very long paths (manhattan distance > 1000 pixels) with auto-radius, hierarchical pathfinding (HPA*) is used: the grid is coarsened, a global route is found, then refined segment by segment.snap_startandsnap_goalare not supported with Dask-backed arrays (raisesValueError).- Parameters:
surface (xr.DataArray) – 2D array of values to bin.
start (array-like object of 2 numeric elements) – (y, x) or (lat, lon) coordinates of the starting point.
goal (array like object of 2 numeric elements) – (y, x) or (lat, lon) coordinates of the goal location.
barriers (array like object, default=[]) – List of values inside the surface which are barriers (cannot cross).
x (str, default='x') – Name of the x coordinate in input surface raster.
y (str, default='y') – Name of the y coordinate in input surface raster.
connectivity (int, default=8)
snap_start (bool, default=False) – Snap the start location to the nearest valid value before beginning pathfinding.
snap_goal (bool, default=False) – Snap the goal location to the nearest valid value before beginning pathfinding.
friction (xr.DataArray, optional) – 2-D friction (cost) surface. Must have the same shape as surface. Values must be positive and finite for passable cells; NaN or
<= 0marks impassable barriers. When provided, edge costs becomegeometric_distance * mean_friction_of_endpoints.search_radius (int, optional) – Limit the A* search to a bounding box of
±search_radiuspixels around the start and goal. Dramatically reduces memory for large grids when start and goal are relatively close. IfNone(default) and the full grid would exceed 50 % of available RAM, an automatic radius is computed. Ignored for dask-backed arrays (already memory-safe).
- Returns:
path_agg – 2D array of pathfinding values. All other input attributes are preserved.
- Return type:
xr.DataArray of the same type as surface.
References
Red Blob Games: https://www.redblobgames.com/pathfinding/a-star/implementation.html # noqa
Nicholas Swift: https://medium.com/@nicholas.w.swift/easy-a-star-pathfinding-7e6689c7f7b2 # noqa
Examples
… sourcecode:: python
>>> import numpy as np >>> import xarray as xr >>> from xrspatial import a_star_search >>> agg = xr.DataArray(np.array([ ... [0, 1, 0, 0], ... [1, 1, 0, 0], ... [0, 1, 2, 2], ... [1, 0, 2, 0], ... [0, 2, 2, 2] ... ]), dims=['lat', 'lon']) >>> height, width = agg.shape >>> _lon = np.linspace(0, width - 1, width) >>> _lat = np.linspace(height - 1, 0, height) >>> agg['lon'] = _lon >>> agg['lat'] = _lat
>>> barriers = [0] # set pixels with value 0 as barriers >>> start = (3, 0) >>> goal = (0, 1) >>> path_agg = a_star_search(agg, start, goal, barriers, 'lon', 'lat')