Quickstart#
Everything on this page runs with just pip install xarray-spatial.
No data download, no GDAL, no configuration.
Your first analysis#
generate_terrain builds synthetic elevation data, so you can try the
library before touching real rasters:
import numpy as np
import xarray as xr
from xrspatial import generate_terrain, hillshade, slope
template = xr.DataArray(np.zeros((400, 600)), dims=['y', 'x'])
terrain = generate_terrain(template, x_range=(0, 6000), y_range=(0, 4000))
shaded = hillshade(terrain)
incline = slope(terrain)
Each function takes an xr.DataArray and returns a new xr.DataArray
with the same shape, dims, and coords. If you have matplotlib installed
(the plot extra), look at the result with:
shaded.plot.imshow(cmap='gray')
The .xrs accessor#
The same operations are available as methods on any DataArray through
the xrs accessor, which is handy for tab completion and method
chaining. These two lines are equivalent:
incline = slope(terrain)
incline = terrain.xrs.slope()
Reading and writing GeoTIFFs#
xrspatial.geotiff reads and writes GeoTIFF / COG natively, GDAL not
required. A round trip:
from xrspatial.geotiff import open_geotiff, to_geotiff
to_geotiff(terrain, 'terrain.tif', crs=3857, cog=True)
dem = open_geotiff('terrain.tif') # 2D DataArray for a single band
shaded = hillshade(dem)
open_geotiff also accepts http(s):// URLs and, with fsspec
installed, s3:// / gs:// / az:// ones. See
GeoTIFF / COG for the full I/O surface and
Safe GeoTIFF IO usage for its validation behavior.
Datasets#
Most functions also accept an xr.Dataset. Single-input functions apply
the operation to each data variable and return a Dataset. Multi-input
functions (multispectral indices) accept a Dataset with band-name keyword
arguments.
from xrspatial import slope
from xrspatial.multispectral import ndvi
# Single-input: returns a Dataset with slope for each variable
slope_ds = slope(my_dataset)
# Multi-input: map Dataset variables to band parameters
ndvi_result = ndvi(my_dataset, nir='band_5', red='band_4')
Scaling up#
For rasters that don’t fit in memory, chunk the input and the same
function call returns a lazy dask-backed result (needs the dask
extra):
chunked = terrain.chunk({'y': 200, 'x': 200})
lazy = slope(chunked) # nothing computed yet
result = lazy.compute()
See Dask backend behavior for which functions stay lazy and how chunk boundaries are handled. For GPU execution, pass a cupy-backed DataArray to the same functions; the Installation page covers GPU setup.
Before you rely on results#
Warning
Read Caveats & Assumptions before production use. The big ones: geodesic terrain functions assume WGS84 coordinates, outputs are float32, and NaN is the nodata sentinel. The Stability policy and LTS commitment page explains the per-function, per-backend feature tiers.
Check out the user guide for worked examples of every module.