Releases: xarray-contrib/xarray-spatial
Releases · xarray-contrib/xarray-spatial
v0.10.1
New features
- accessor: backend-aware .xrs.open_geotiff on DataArray and Dataset (#2598)
- geotiff: add bbox= to open_geotiff for geographic-space windowed reads (#2556)
Bug fixes and improvements
- rasterize: honor resolution= exactly when bounds don't divide evenly (#2597)
- reproject: fix vertical-datum shift crash on integer DEMs (#2596)
- resample: clamp dask interp overlap depth per axis (#2547) (#2599)
- zonal: fix trim() with NaN sentinel on numpy and cupy backends (#2559) (#2594)
- reproject: reject explicit out-of-range nodata for integer dtypes (#2591)
- zonal: fix cupy backend dropping all-NaN zones and desyncing zone_ids (#2562) (#2589)
- resample: refresh transform to match actual coord orientation (#2571) (#2587)
- rasterize: validate resolution= shape and element type (#2576) (#2586)
- resample: preserve integer precision in nodata mask comparison (#2570) (#2592)
- zonal: keep hypsometric_integral dask path fully lazy (#2563) (#2593)
- geotiff: accept projected GeoTIFFs that carry a base geographic CRS (#2603)
- polygonize: reject non-finite simplify_tolerance (#2575) (#2584)
- reproject: unit-aware bounds_policy="auto" blow-up detection (#2600)
- zonal: validate return_type at entry to stats() (#2558) (#2578)
- resample: validate target_resolution and scale_factor up front (#2574) (#2590)
- rasterize: support descending-x in like= templates (#2568) (#2595)
- rasterize: reject zig-zag duplicate-coord patterns in _check_uniform_axis (#2585)
- polygonize: fix dask chunk-dependent merging and DN corruption (#2601)
- zonal: make crop() return (0, 0) on all backends when no zone matches (#2580)
- rasterize: reject partial width/height overrides instead of silent ignore (#2579)
- zonal: fix crosstab cat_ids overcount when earlier categories are filtered out (#2560) (#2577)
- resample: preserve scalar non-dim coords and refresh stale nodata attr (#2542) (#2549)
- zonal: fix hypsometric_integral dask+cupy backend (#2525) (#2529)
- geotiff: include GB allocation estimate in max_pixels error message (#2554)
- zonal: raise on 'majority' in zonal_stats dask path instead of silent drop (#2528) (#2531)
- reproject: fix half-pixel offset in geoid and datum-shift grid lookups (#2508) (#2516)
- rasterize: reject NaN fill against integer dtype (#2504) (#2512)
- geotiff: reject distinct per-band nodatavals on write (#2514) (#2519)
- zonal: guard unbounded allocation in stats(return_type='xarray.DataArray') (#2523) (#2533)
- zonal: rechunk apply 3D dask output along stacked axis (#2526) (#2532)
- rasterize: hoist poly_props/poly_global cupy.asarray above all_touched (#2506) (#2510)
- polygonize: auto-detect attrs['transform'] for output georeferencing (#2536) (#2541)
- geotiff: reconcile COG write stability across registry, contract, and docstring (#2520)
- zonal: rename crop(zones_ids=) to crop(zone_ids=) with deprecation shim (#2521) (#2527)
- reproject: preserve integer dtype in dask+cupy fast path (#2505) (#2509)
- geotiff: scope max_pixels to the chunk when chunks= is supplied (#2501) (#2502)
v0.10.0
GeoTIFF release contract
Tiers what the public GeoTIFF and COG surface promises for this release.
xrspatial.geotiff.SUPPORTED_FEATURES is the source of truth; the bullets
below mirror it. See the reference page at docs/source/reference/geotiff.rst
for the per-tier semantics and the audit trail.
Stable
- Local-file GeoTIFF read (
open_geotiff) on the eager numpy backend, including windowed reads viawindow=. Covered by the window-read suite inxrspatial/geotiff/tests/. (epic #2340) - Dask reads (
read_geotiff_dask). Cross-backend parity against the eager numpy reader is gated bytest_backend_parity_matrix.pyandtest_backend_full_parity_2211.py. (epic #2341) - Local-file GeoTIFF write (
to_geotiff) on the CPU writer. (epic #2340) - Local COG read and write (
reader.local_cog,writer.cog) for axis-aligned 2D / 3D rasters with the lossless codecsnone,deflate,lzw,zstd,packbits, internal overviews only, and normal CRS / transform / dtype / nodata / band / pixel-is-area / pixel-is-point round-trip. Backed by the writer compliance suite (#2292), the cross-backend parity gate (#2293), and the per-tile byte-budget contract (#2294 / #2298). (epic #2286) - Lossless stable codecs:
none,deflate,lzw,zstd,packbits. Integer and float byte-for-byte round-trip. (epic #2340)
Advanced
- fsspec-routed reads (
reader.fsspec) and HTTPS reads (reader.http). The transport layer works but the redirect / retry / cache surface is not contracted at the stable bar. (epic #2344) - HTTP COG reads (
reader.http_cog). Range fetching, range coalescing, the SSRF / private-host filter, and the per-tile byte cap are pinned by the byte-budget contract (#2294 / #2298), but the broader transport surface is tracked separately for stable promotion. (epic #2344) - VRT reads (
reader.vrt). Limited to simple GDAL VRT mosaics over GeoTIFF sources that agree on CRS, transform orientation, pixel size, dtype, and band count. See the VRT support matrix indocs/source/reference/geotiff.rst. (epic #2342, PR #2321) - External
.tif.ovrsidecar reads (reader.sidecar_ovr). (epic #2340) - Writer overviews and BigTIFF (
writer.overviews,writer.bigtiff). (epic #2340) - BigTIFF COG writes (
writer.bigtiff_cog). The external-interop gate lives intest_bigtiff_cog_compliance_2286.py; promotion to stable follows the same release-cycle soak rule as the rest of the COG surface. (epic #2286)
Experimental
- GPU reads and writes (
reader.gpu,writer.gpu). Cross-backend numerical parity is not claimed at this tier. (epic #2341) - Experimental codecs:
lerc,jpeg2000,j2k,lz4. Requireallow_experimental_codecs=Trueon both read and write paths. Reader support across GDAL versions is uneven. (epic #2340) - Permissive read escape hatches:
allow_rotated=True(reader.allow_rotated) andallow_unparseable_crs=True(reader.allow_unparseable_crs). Both bypass a read-side check that the writer normally rejects. (epic #2340) - Rich-tag writes:
writer.gdal_metadata_xmlandwriter.extra_tags. Free-form payloads are written verbatim; interop with rasterio, libtiff, and GDAL depends on the payload. Gated byallow_experimental_codecs=Trueon writes from a fresh DataArray; round-tripped attrs from a previous read are exempt. (epic #2340)
Internal-only
codec.jpeg(JPEG-in-TIFF). The encoder writes self-contained JFIF tiles without the TIFF JPEGTables tag (347), so the on-disk output is not interoperable with libtiff, GDAL, or rasterio. Reads and writes require the dedicatedallow_internal_only_jpeg=Trueopt-in;allow_experimental_codecs=Truedoes not unlock this path. (epic #2340)
Unsupported for this release (these combinations fail closed: the writer or reader raises rather than silently producing a wrong result)
- Warped VRTs (
<VRTDataset subClass="VRTWarpedDataset">). (PR #2321) - Nested VRTs (a
<SourceFilename>pointing at another.vrt). (PR #2321) - VRT mosaics whose sources disagree on CRS, pixel size, dtype, or band count without an explicit opt-in. The default raises
MixedBandMetadataError. (PR #2321) to_geotiff(..., cog=True, tiled=False). COG output requires the tiled layout. (epic #2286)- Rotated transforms on the write path. The reader has an
allow_rotated=Trueescape hatch in the experimental tier; the writer has no equivalent. (epic #2340) - 1xN / Nx1 writes without an explicit
attrs['transform']. The writer used to borrow the non-degenerate axis's spacing and silently invent the wrong pixel size; the writer now raises. (epic #2340)
Bug fixes and improvements
- Move shapely from a required dependency to an optional
vectorextra. shapely (and GEOS) used to load on everyimport xrspatialbecauserasterize.pyimported it at module top level. It is now imported lazily, so a plainpip install xarray-spatialneither installs nor loads shapely. The only paths that need it are the vector-to-raster functionsrasterizeandpolygonize; installpip install xarray-spatial[vector]to use them. Callingrasterizewithout shapely raises a clear ImportError pointing at the extra. Follows the same pattern as the matplotlib change (#2494). (#2496) - Move matplotlib from a required dependency to an optional
plotextra. A plainpip install xarray-spatialno longer pulls in matplotlib (and its pillow / fonttools / kiwisolver / contourpy / cycler / pyparsing chain), since no compute path imports it -- every matplotlib use is a lazy import inside the.xrs.plotaccessor helpers. Installpip install xarray-spatial[plot]to use plotting; calling.xrs.plot()without it now raises a clear ImportError pointing at the extra instead of a bareModuleNotFoundError. pandas stays required because xarray depends on it and several core modules import it directly. (#2494) - Reconcile
xrspatial.geotiff.SUPPORTED_FEATURESwith the GeoTIFF release-contract tiering proposed in epic #2340. Addsreader.windowedatstable(covered by the existing window-read suite) andreader.daskatstable(covered by the cross-backend parity matrix intest_backend_parity_matrix.pyandtest_backend_full_parity_2211.py). Demotesreader.allow_rotatedandreader.allow_unparseable_crsfromadvancedtoexperimentalto match the epic's placement of permissive read-side escape hatches in the Experimental tier. A new shape test (test_supported_features_shape_2348.py) pins the structural invariants of the mapping (every entry carries a tier label; the tier set is closed at{stable, advanced, experimental, internal_only}; the dict literal contains no duplicate keys) so future drift fails CI. Runtime behaviour of every read and write path is unchanged; this is metadata-only. Callers gating on the exact string value of these two demoted entries will need to update their checks. (#2348) - Promote the local COG read and write paths to the
stabletier inxrspatial.geotiff.SUPPORTED_FEATURES.SUPPORTED_FEATURES['writer.cog']andSUPPORTED_FEATURES['reader.local_cog']now reportstable;reader.http_cogstaysadvancedwhile the HTTP transport surface is contracted separately. The stable COG contract covers axis-aligned 2D / 3D rasters, the CPU writer and CPU reader, the lossless codecs (none,deflate,lzw,zstd,packbits), internal overviews, and normal CRS / transform / dtype / nodata / band / pixel-is-area / pixel-is-point round-trip. GPU COG paths, experimental codecs, rotated transforms, external.tif.ovrsidecars, file-like destinations withcog=True, BigTIFF COG, and HTTP COG remain outside the contract. Backed by the writer compliance suite (#2292), the cross-backend parity gate (#2293), and the per-tile byte-budget contract (#2294 / #2298). The reference docs (docs/source/reference/geotiff.rst) and the COG overview notebook spell out the full contract. (#2300) - Resolve the GeoTIFF writer's
GeographicTypeGeoKey/ProjectedCSTypeGeoKeydecision via pyproj instead of an EPSG number range. The legacy heuristic (4326 + 4000-4999 -> geographic, else projected) silently mis-tagged geographic CRSes registered outside the 4000-4999 block (NAD83(2011) = 6318, GDA2020 = 7844, WGS 84 (G2139) = 9057, etc.) as projected and projected codes inside the block (4087 / 4088 / 4499) as geographic, corrupting the CRS at write time. The writer now callspyproj.CRS.from_epsg(...).is_geographic. When pyproj can't classify a code (uninstalled, or installed but the local PROJ database lacks the entry), the writer raises the newUnknownCRSModelTypeErrorrather than guessing -- a small vetted allowlist (4326, 4269, 4267, 4258, 4283, 4322, 4230, 4019, 4047) is still honoured for the pyproj-missing case.pyprojis now listed under thegeotiffextra. (#2277) - Shut down the per-tile compression
ThreadPoolExecutoron every exit path of the streaming tiled-write code into_geotiff. The old code only calledshutdown(wait=True)after the tile-row loop completed, so any mid-stream raise (compression failure, dask compute failure, file write failure) bypassed shutdown and leaked worker threads. The loop now runs insidetry/finallyand the finally callsshutdown(wait=True, cancel_futures=True)so queued tiles get dropped on the error path instead of blocking the unwind. The pool's workers carry anxrspatial-geotiff-tile-compressthread_name_prefixso leak-detection tests can tell them apart from dask's own offload/scheduler pools. (#2276) - Remove read-side emission of the 13 deprecated GeoTIFF attrs (
crs_name,geog_citation,datum_code,angular_units,semi_major_axis,inv_flattening,linear_units,projection_code,vertical_crs,vertical_citation,vertical_units,colormap_rgba,cmap) and bumpattrs['_xrspatial_geotiff_contract']from 1 to 2. Downstream code that read these viaattrs[key]now seesKeyError; migrate toattrs.get(key)or derive the value fromattrs['crs']/attrs['crs_wkt']...
v0.9.9
Version 0.9.9 - 2026-05-05
Bug fixes and improvements
- Add geotiff edge-case tests and integer-coord fallback (#1482) (#1492)
- Use synchronous dask scheduler for different-CRS merge parity test (#1495)
- Fetch COG tiles concurrently in HTTP path to mask RTT (#1487)
- Geotiff polish: validation, caching caps, parallelism thresholds, memory guards (#1488) (#1493)
- Round-trip transform, crs, and tag metadata through to_geotiff/open_geotiff (#1484) (#1494)
- Tighten geotiff reader: partial-tile shape check, ModelTransformation rotation guard (#1486) (#1491)
- Add geotiff writer test matrix (#1483) (#1490)
- Stream tile writes per dask chunk segment to bound peak memory in to_geotiff (#1485) (#1489)
- Add regression test for GPU pred=3 multi-sample TIFFs (#1479) (#1481)
- Make cubic resample prefilter explicit so chunk seams stay sub-eps (#1464) (#1478)
- Preserve input float dtype through resample() (#1467) (#1476)
- Resample polish: fix cubic depth comment, tighten NaN threshold, add edge tests (#1475)
- Fix dask aggregate boundary contamination and clean up bookkeeping (#1469) (#1477)
- Support 3D rasters, expose nodata, document target_resolution tuple in resample (#1466) (#1474)
- Cover cupy median/mode, dask+cupy, integer input, target_resolution tuple in resample tests (#1470) (#1473)
- Refresh transform and nodata attrs on resample output (#1465) (#1472)
- Inline dask aggregate kernel in resample (#1463) (#1468)
- Emit fresh grid metadata and propagate _FillValue in reproject (#1458) (#1462)
- Polish reproject/merge docstrings and cover Inf and parameter edge cases (#1459) (#1461)
- Batch CuPy reductions and drop redundant copies in reproject (#1460)
- Add transform_precision parameter to merge() (#1452) (#1456)
- Preserve non-spatial coords through reproject() and merge() (#1455)
- Guard _apply_vertical_shift against non-finite coords; add vertical CRS tests (#1453)
- Honor per-raster nodata sentinels in merge() (#1448) (#1449)
- Preserve input attrs through reproject() and merge() (#1446)
- Fix dask reproject dtype and same-CRS dask merge (#1450)
- Validate raster inputs in reproject public APIs (#1431) (#1432)
- Add memory guard and scalar validation to generate_terrain (#1443) (#1444)
- Validate scalar parameters in hydro public APIs (#1427) (#1428)
- Validate mannings_n DataArray values in flood (#1437) (#1438)
- Add _validate_raster on secondary DataArray args in hydro (#1425) (#1426)
- Validate grid/bounds/precision params in reproject (#1433) (#1434)
- Validate cellsize in hydro public APIs (#1429) (#1430)
- Validate pathfinding inputs and cap waypoints (#1439) (#1440)
- Validate raster/mask inputs in polygonize (#1441) (#1442)
- Add memory guard to flow_direction_mfd numpy/cupy backends (#1423) (#1424)
- Reject NaN/Inf in reproject scalar inputs (#1435) (#1436)
- Lazy assembly for hand_mfd dask path (#1416) (#1417)
- Return NaN from glcm_texture angle=None when no angle has valid pairs (#1408) (#1409)
- Use ground distance for sky_view_factor horizon angle (#1407) (#1410)
- Exclude centre cell from morph_erode/dilate when kernel[centre]==0 (#1397) (#1398)
- Use sized slice in dask morph chunk writeback (#1399) (#1400)
- Merge sink_d8 labels across dask tile boundaries (#1394) (#1395)
- Reject complex dtypes in _validate_raster() (#1384) (#1387)
- Reject underflowing sigma_spatial in bilateral() (#1390) (#1392)
- Use int64 row_ptr in _build_row_csr_numba (#1388) (#1391)
- Reject mixed-backend arrays in validate_arrays() (#1383) (#1386)
- Reject non-positive inputs in wpm() (#1382) (#1385)
- Guard _idw knearest against unbounded grid x k allocation (#1377) (#1380)
- Validate raster dtype in convolve_2d() (#1389) (#1393)
- Reject all-zero rasters in mesh_utils.create_triangulation (#1378) (#1381)
- Validate dtypes per band in mahalanobis() (#1376) (#1379)
- Guard owa() against unbounded criteria stack (#1370) (#1375)
- Guard spline() TPS against unbounded memory allocations (#1372) (#1374)
- Reject n_samples<=0 in mcda sensitivity (#1371) (#1373)
- Guard flow_path_d8() against unbounded memory allocations (#1364) (#1368)
- Guard flow_path_mfd() against unbounded memory allocations (#1365) (#1369)
- Guard flow_path_dinf() against unbounded memory allocations (#1363) (#1367)
- Guard snap_pour_point_d8() against unbounded memory allocations (#1362) (#1366)
- Guard sink_d8() against unbounded memory allocations (#1356) (#1361)
v0.9.8
Version 0.9.8 - 2026-04-29
Bug fixes and improvements
- Guard stream_order_dinf() against unbounded memory allocations (#1350) (#1354)
- Guard basin_d8() against unbounded memory allocations (#1357) (#1359)
- Guard flow_length_dinf() against unbounded memory allocations (#1355) (#1358)
- Guard flow_length_mfd() against unbounded memory allocations (#1351) (#1353)
- Guard stream_order_mfd() against unbounded memory allocations (#1349) (#1352)
- Guard watershed_dinf() against unbounded memory allocations (#1345) (#1348)
- Guard stream_link_dinf() against unbounded memory allocations (#1343) (#1347)
- Guard hand_dinf() against unbounded memory allocations (#1344) (#1346)
- Guard stream_link_mfd() against unbounded memory allocations (#1337) (#1341)
- Guard flow_length_d8() against unbounded memory allocations (#1327) (#1332)
- Guard hand_d8() against unbounded memory allocations (#1323) (#1326)
- Guard hand_mfd() against unbounded memory allocations (#1338) (#1340)
- Guard watershed_mfd() against unbounded memory allocations (#1339) (#1342)
- Guard watershed_d8() against unbounded memory allocations (#1329) (#1330)
- Guard fill_d8() against unbounded eager allocations (#1334) (#1336)
- Guard stream_link_d8() against unbounded memory allocations (#1333) (#1335)
- Guard stream_order_d8() against unbounded memory allocations (#1328) (#1331)
- Guard flow_accumulation_dinf() against unbounded memory allocations (#1322) (#1325)
- Guard flow_accumulation_mfd() against unbounded memory allocations (#1321) (#1324)
- Guard gpu_rtx hillshade and viewshed against unbounded GPU allocations (#1308) (#1310)
- Guard min_observable_height() against unbounded boolean stack (#1317) (#1320)
- Guard flow_accumulation() against unbounded eager allocations (#1318) (#1319)
- Reject NaN/Inf weights in mcda combine and ahp_weights (#1311) (#1312)
- Support TIFF predictor=3 on the CPU write path (#1313) (#1314)
- Guard kriging() against unbounded N x N and grid x N allocations (#1307) (#1309)
- Guard surface_distance() against unbounded eager allocations (#1303) (#1305)
- Guard landforms() against unbounded kernel allocations (#1302) (#1304)
- Enforce equal band shapes in true_color() (#1293) (#1301)
- Guard sky_view_factor() against unbounded eager allocations (#1299) (#1300)
- Guard resample() against unbounded output allocations (#1295) (#1297)
- Guard sieve() numpy and cupy backends against oversized rasters (#1296) (#1298)
- Guard kde and line_density against oversize output grids (#1287) (#1289)
- Reject oversize focal kernels before allocation (#1284) (#1286)
- Guard mahalanobis allocations against oversized rasters (#1288) (#1290)
- Guard true_color() eager backends against oversized rasters (#1291) (#1292)
- Add memory guard to geodesic slope/aspect (#1283) (#1285)
- Validate dt against CFL stability bound in diffuse() (#1281) (#1282)
- Cap erode() parameters and run memory guard on every backend (#1275) (#1277)
- Validate cellsize in curvature() (#1270) (#1272)
- Add memory guard to emerging_hotspots public API (#1274) (#1276)
- Validate input rasters in edge_detection public API (#1271) (#1273)
- Guard diffuse() against unbounded allocations and steps loop (#1267) (#1268)
- Add memory guards to dasymetric public API (#1261) (#1263)
- Guard cost_distance CuPy backend against oversize rasters (#1262) (#1264)
- Guard morphology kernel allocations against oversized kernels (#1256) (#1258)
- Cap window_size and distance in glcm_texture (#1257) (#1259)
- Guard cost_distance numpy path against oversize rasters (#1252) (#1253)
v0.9.7
New features
- Add kernel density estimation (KDE) (#1170)
- Add standalone raster resampling (#1152) (#1172)
- Add GPU COG overview support (#1150) (#1174)
- Add geometry simplification to polygonize() (#1176)
- Add polygon clipping function (#1144) (#1173)
- Add hypsometric_integral to zonal module (#1073)
Bug fixes and improvements
- Fix dask OOM in visibility and viewshed modules (#1167)
- QA/QC: align sieve with GDAL and add parity tests (#1169)
- Numba-ize visibility module loops (#1177) (#1179)
- Fix hillshade gradient to use Horn's method (#1175) (#1178)
- Fix duplicate notebook numbers and restructure to standard format (#1181)
- Fix OOM in geotiff dask read, sieve memory, and reproject GPU fallback (#1183)
- Add memory guards to reproject CuPy paths and output grid (#1186, #1187) (#1188)
- Fix NaN pixels producing spurious polygons in numpy/dask backends (#1190) (#1194)
- Fix CuPy Bellman-Ford iteration limit in cost_distance (#1192)
- Fix geotiff unbounded allocation DoS and VRT path traversal (#1189)
- Fix KDE all-zero output with descending-coordinate templates (#1199)
- Fix crop=True dropping boundary pixels when all_touched=True (#1197) (#1200)
- Add allocation guards to GPU read and VRT read paths (#1196)
- Fix resample interpolation coordinate mapping (#1202) (#1204)
- Fix float32 truncation in balanced_allocation iteration loop (#1203) (#1205)
- Fix bump OOM with int32 coords, default-count cap, per-chunk dask partitioning (#1206) (#1208)
- Pass dask chunks to rasterize in clip_polygon to keep mask lazy (#1207) (#1209)
- Cut head_tail_breaks and box_plot dask re-scans (#1213)
- Fuse hypsometric_integral dask path to a single graph evaluation (#1212)
- Cap dask graph size in read_geotiff_dask and batch adler32 transfers (#1211)
- Bound per-tile allocations in TIFF reader (#1215) (#1216)
- Fix GPU predictor kernel stride for multi-sample tiled TIFFs (#1220) (#1222)
- Reject TIFFs whose declared tile grid exceeds TileOffsets length (#1219) (#1221)
- Reject oversize rasterize outputs before allocation (#1223) (#1224)
- Fix cupy zonal_stats silently ignoring nodata_values=0 (#1227) (#1228)
- Guard viewshed numpy path against oversize rasters (#1229) (#1230)
- Reject integer-dtyped input in perlin() (#1232) (#1233)
- Reject oversize bump output rasters before allocation (#1231) (#1234)
- Clamp bilateral kernel radius to raster extent (#1236) (#1238)
- Fix CPU fp_predictor_decode for multi-band predictor=3 TIFFs (#1247) (#1250)
- Guard natural_breaks against oversize Jenks matrices (#1246) (#1248)
- Handle degenerate input in equal_interval (#1244) (#1245)
- Reject oversize convolution kernels before allocation (#1241) (#1243)
- Guard contour segment buffers against oversize allocation (#1240) (#1242)
v0.9.6
New features
- Multi-observer viewshed and line-of-sight profiles (#1145) (#1160)
- Sieve filter for removing small raster clumps (#1159)
Bug fixes and improvements
- Faster sieve labeling, with convergence warning (#1163)
- Dask laziness docs and regression tests (#1164) (#1165)
- Fix README feature matrix to match codebase (#1155) (#1158)
- Fix 196 test-suite warnings (#1148) (#1157)
- ASV benchmarks for 6 modules changed in v0.9.5 (#1156)
- Caveat and assumption admonitions in docs (#1134)
- Miscellaneous code sweeps (#1161)
v0.9.5
Bug fixes and improvements
- Add GPU memory guard to reproject dask+cupy path (#1131)
- Add memory guard to surface_distance geodesic dd_grid (#1129)
- Add memory guard to dasymetric validate_disaggregation (#1127)
- Replace boolean indexing with lazy reductions in normalize dask paths (#1125)
- Keep northness/eastness lazy on dask arrays (#1123)
- Add memory guard to erosion dask paths (#1121)
- Add memory guard to cost_distance iterative Dijkstra and da.block assembly (#1119)
- Fix diffusion dask OOM by passing scalar diffusivity directly to chunks (#1117)
- Fix balanced_allocation OOM with lazy source extraction and memory guard (#1115)
- Fix zonal dask memory guards and stats filtering (#1112)
v0.9.4
New features
- Streaming TIFF write for dask inputs (#1084) (#1108)
- Add dtype, compression_level, and VRT output to geotiff I/O (#1083) (#1085)
Bug fixes and improvements
- Use float64 in Jenks natural breaks internals (#1100) (#1101)
- Fix multi-metric output mislabeling in glcm_texture (#1106) (#1107)
- Fix inverted decay and off-by-one in bump spread (#1102) (#1103)
- Propagate NaN from curve_number in curve_number_runoff (#1104) (#1105)
- Fix target_elev contaminating horizon in dask viewshed distance sweep (#1098) (#1099)
- Preserve float64 precision in convolve_2d (#1096) (#1097)
- Fix SAVI formula: (1+L) was in denominator instead of numerator (#1094) (#1095)
- Fix NaN handling in focal_stats CUDA kernels (#1092) (#1093)
- Fix three accuracy bugs in zonal stats dask backend (#1090) (#1091)
- Add longitude normalization to CUDA inverse projection kernels (#1089)
- Fix three accuracy bugs in reproject resampling kernels (#1087)
- Fix three accuracy bugs in open_geotiff/to_geotiff (#1081) (#1082)
v0.9.3
New features
- GeoTIFF/COG reader and writer with GPU acceleration and datum transforms (#1035) (#1062)
- nvJPEG GPU acceleration for JPEG-compressed GeoTIFFs (#1050) (#1055)
- LZ4 and LERC compression codecs for GeoTIFF (#1063)
- Dask-native out-of-core reproject and merge module (#1031)
- MCDA module for spatial multi-criteria decision analysis (#1030) (#1058)
- Edge detection filters: Sobel, Laplacian, Prewitt (#1042)
- Focal variety statistic (#1040) (#1043)
- NDSI, NDBI, BAI, MSAVI2, and OSAVI spectral indices (#1044)
- Northness and eastness aspect functions (#1039) (#1041)
- Rescale and standardize normalization utilities (#1028)
- Morphological gradient, white top-hat, and black top-hat operators (#1026)
- D-inf and MFD variants of flow_path, watershed, and HAND (#1020)
- D-infinity flow length computation (#1012) (#1013)
- MFD flow length computation (#1011)
- Vegetation-aware flood modeling: roughness, curve number, and depth from land cover (#1029)
- Lightweight CRS parser, removes hard pyproj dependency (#1072)
- plot() accessors for DataArray and Dataset (#1074)
- fused_overlap and multi_overlap dask graph utilities (#1071)
- rechunk_no_shuffle utility (#1068)
Bug fixes and improvements
- Fix D-inf flow direction odd facet decomposition per Tarboton 1997 (#1005)
- Fix CuPy uint8 overflow and CUDA cubic NaN fallback (#1054) (#1064)
- Fix stale full pipeline benchmark numbers in README (#1077) (#1079)
- Fix duplicate prefix numbers in user guide notebooks (#1076) (#1078)
- Memory-safe rechunk, preview chunk budget, plot improvements (#1075)
- Reduce dask graph size for large raster reprojection (#1065)
- Speed up cost_distance iterative tile Dijkstra 2-4x (#1023)
- Faster polygonize: single-pass tracing, JIT merge helpers, batch shapely (#1010)
- Rename GeoTIFF API to xarray conventions (#1047) (#1061)
- Section index in README feature matrix (#1033) (#1034)
- Dask example for reproject (#1066)
- Porto taxi trajectory rasterization example (#1022)
- Polygonize benchmark comparing xrspatial vs rasterio (#1006) (#1007)
v0.9.2
New features
- Vector rasterize function for polygons, lines, and points (#989) (#990)
- preview() for memory-safe raster downsampling (#987)
- D-inf and MFD stream ordering and link segmentation (#983) (#984)
- Zonal functions accept vector zones directly (#999)
- Dask backends for rasterize() (#997)
Bug fixes and improvements
- Fix rasterize accuracy: GPU ceil, half-open fill, all_touched pairing (#995) (#996)
- Fix scanline row gaps, speed up rasterize, add resolution/like/merge params (#991)
- Rasterization fixes (#992)
- Fix cupy failures in balanced_allocation and corridor (#985)
- Refactor preview to avoid rechunking (#988)
- Replace datashader with matplotlib in user guide notebooks (#1002)
- Refactor user guide notebooks 10-31 to standard structure (#1003)
- Water/land classification example in GLCM notebook (#994)
- Source/reference column in README feature matrix (#977) (#978)
- Small notebook fixes