Change log#
0.70.0 (2026-10-18)#
Feat#
- ugrid: add a per-timestep active mask and ragged 3-D vertical layers (#1336)
- dataset: add a pyramids.raster_drivers plugin hook for third-party readers (#1335)
Fix#
- remote: make a custom S3 endpoint reach region-discovery (#1339)
- remote: give the VSICurl workers a pathless config's credentials (#1340)
0.69.0 (2026-10-16)#
Feat#
- packaging: build and publish Python 3.15 wheels (#1322)
- ugrid: dispatch a non-UGRID NetCDF to a mesh driver when no topology is found (#1328)
- dataset: add pan-sharpening, histogram matching, and percentile stretch (#1326)
0.68.0 (2026-10-15)#
Feat#
- ugrid: dispatch mesh reads and writes to third-party drivers (#1309)
- grib: enrich GRIB metadata with NWP keys and select by level/number (#1310)
0.67.0 (2026-10-12)#
BREAKING CHANGE#
- six deliberate changes, all aligning the mesh with the raster contract.
- rolling's min_periods now defaults to the full window instead of 1, so a step whose window runs off the min_periods=1 for the old behaviour.
- A concat/merge topology mismatch ra derives from the package error and not from ValueError, so an except ValueError no longer catches
- interpolate_na measures distance along the time coordinate by default (use_coordinate=True). With gap at the middle step it fills 1.0 where it previously filled 5.0.
- to_dataframe gained a layer column,, element, x, y, layer, time, value. Code selecting columns by position will shift.
- from_geodataframe raises ValueError for a frame that declares no CRS; it previously stamped EPSG:432 frame whose CRS has no EPSG code.
- rasterize_like raises ValueError whhe reference raster declares no CRS; it previously sampled the mesh's raw coordinates and stamped the res
- Dataset.to_stac_item and DatasetCollection.from_stac no longer accept their options as flat keywords. with_stats, with_histogram, histogram_bins, stats_approx_ok and with_eo move to bands=BandMetadata(); footprint, footprint_band, footprint_max_samples, simplify_tolerance, densify and precision to footprint=Footprint(); with_proj and with_raster to extensions=StacExtensions(); grid, align and resampling to alignment=Alignment(); skip_missing and errors_as_nodata to tolerance=ReadTolerance(); method and fuse_func to fusion=GroupFusion(); rescale and cfg to read=AssetRead(); properties and eo_band_names to provenance=CubeProvenance(). A call that passed none of these flags is unaffected.
- UgridDataset.stats is removed; use summary(variables=[name]).loc[name] instead.
Feat#
- dataset: add a line-transect sampler (Dataset.transect) (#1305)
- ugrid: complete the UGRID parity surface on UgridDataset (#1283)
- collection: add median, mode, percentile and trend to reduce_time (#1304)
- stac: implement the STAC feature backlog (STAC-00 … STAC-18) (#1279)
- stac: enrich Items and widen asset, cube and catalog reads
- netcdf,ugrid: shared summary, weighted quantile, and spline gap-fill (#1278)
- ugrid: add analysis and along-time API to UgridDataset (#1270)
0.66.0 (2026-10-09)#
BREAKING CHANGE#
- NetCDF.read_array() and Variable.read_array() now return the dimension-preserving (*band_sizes, rows, cols) layout by default instead of the flattened (bands, rows, cols) with a size-1 result squeezed to 2-D. Pass squeeze=True to restore the previous layout; a band= read is unaffected.
Feat#
- netcdf: add curvefit, rolling_exp and the dict round trip (#1269)
- netcdf: add calculus and calendar members, and container selection (#1264)
- dataset,netcdf: broadcast a band axis, write CF coordinate roles (#1255)
- netcdf: add rename_dims, assign_coords, drop_dims and update (#1245)
- geodesy: measure ground distance and area on the ellipsoid (#1243)
- netcdf: compose lazy op-chains over the dask-backed cube surface (#1244)
- netcdf: dimension-preserving read_array default + lazy masked reads (#1240)
- netcdf: lazy dask-backed cube surface and to_dask_dataframe (#1239)
- netcdf: add rank, pad and transpose (last Tier 2c xarray members) (#1218)
- dataset: add to_dataframe/to_geodataframe, consolidate cell exports (#1213)
- netcdf: add interp and interp_like for band-axis interpolation (#1212)
- dataset,feature: array-native point reprojection and gridding (#1204)
- netcdf: add groupby_bins, value-interval grouping over reduce (#1208)
- netcdf: add from_dataframe, the inverse of to_dataframe (#1203)
Fix#
- netcdf: correct lazy read chunking and guard in-process reopen (#1232)
- ci: build the OGR VRT driver into the from-source GDAL (#1215)
0.65.0 (2026-09-26)#
Feat#
- feature: count and inspect vector files without loading geometry (#1202)
- netcdf: isel(drop=) and coordinate-less band-dimension writes (#1201)
- dataset,netcdf: add **, unary - and abs() to the variable operators (#1197)
- wheels: ship self-contained musllinux wheels for Alpine (#1188)
- dataset,netcdf: clip, round and cast cell values; window, drop and sort bands (#1187)
Fix#
- netcdf: carry a text-coordinate band dimension through a rebuild (#1196)
- netcdf: preserve a rebuild's axis names and CF units, reuse the store's own axes (#1195)
0.64.0 (2026-09-21)#
BREAKING CHANGE#
- an operator between two NetCDF variables on the same grid with the same band count, whose band dimension names or sizes differ, now raises ValueError instead of returning a result without band dimensions whose planes were paired by position.
Feat#
- analysis: compose vector fields onto an axes, add solid color= (#1175)
- netcdf: add the missing-data, join and interchange members (#1167)
- dataset: let read_array combine masked=True with out_shape= and boundless=True (#1166)
- netcdf: add rolling, diff, cumsum, shift, the extremum locators and weighted (#1161)
- cog: let read_part return the geotransform of the window it read (#1157)
- netcdf: keep band dimensions through operators, extend reduce, and add coarsen (#1150)
- netcdf: add isel(), let sel() take several dimensions, and fix the band order it declares (#1145)
- netcdf: make the container a mapping, and add the xarray-compatible aliases (#1141)
Fix#
- dataset,netcdf: compare a variable's own tags in identical, not the store's (#1177)
- dataset: honor the signed geotransform in the y axis and bbox
- plot: adapt the plot engine to cleopatra 0.39 and restore wheel CI (#1151)
- netcdf: decode a CF time origin with a single-digit seconds field, on the right calendar (#1139)
0.63.0 (2026-09-13)#
BREAKING CHANGE#
to_xarray()returns adatetime64[ns]time coordinate where it returnedfloat64, andunits/calendarmove from that coordinate'sattrsto itsencoding, soxds.time.attrs["units"]raisesKeyError.from_xarraywrites the CF units the encoding names instead ofseconds since 1970-01-01, producing a byte-for-byte different file for the same input. Passdecode_times=Falsefor the previous output.
Feat#
- netcdf: read any dimension's coordinates, and select by label or nearest (#1133)
Fix#
- dataset,netcdf: accept scalar operands and decode the time axis in to_xarray (#1134)
0.62.0 (2026-09-11)#
BREAKING CHANGE#
- get_variable and variables[name] return a LabeledArray instead of a gdal.MDArray for a variable with no raster plane. Replace ReadAsArray() with .values, GetDimensions() with .dims / .shape, GetUnit() with .unit, GetNoDataValueAsDouble() with .no_data_value and GetScale() / GetOffset() with .scale / .offset. crop_variable, reproject_variable, resample_variable, plot(variable=) and open_mfdataset(variable=) raise ValueError for such a variable instead of AttributeError. A compound variable with a string field raises ValueError, since GDAL's Python bindings cannot read it. The array behind variables[name] is read-only; take .copy() to modify it
Fix#
- dataset,netcdf: unpack CF-packed data by default, on one keyword (#1130)
- netcdf: materialise a non-raster variable instead of leaking a gdal.MDArray (#1131)
- netcdf: materialise a non-raster variable instead of leaking a gdal.MDArray
get_variable returned the raw gdal.MDArray whenever GDAL could not expose a variable as a raster plane -- a 1-D array, or a string or compound one. That handle has none of pyramids' API, and its Read() returns an undecoded buffer for numeric data, so the only route to the values was ReadAsArray(): raw osgeo in a package meant to hide it.
- return a LabeledArray, carrying the values with their dims, shape, name, unit, no_data_value, scale, offset and attributes
- read each dtype class with the reader it needs: strings via Read() into object (a NULL entry stays None), numeric and compound via ReadAsArray(); build an empty array for a zero-length extent, and keep a 64-bit integer fill value exact
- correct the return annotation to NetCDF | LabeledArray and route the raster-only callers through _require_raster_variable, which refuses a non-raster variable by name instead of raising AttributeError
- decide raster-ness from the array's declaration, not by reading it, so a CRS lookup no longer materialises a large non-raster array
- carry a string or compound array on (y, x) as an auxiliary rather than refusing the whole container crop, to_crs or reduce
- drop an auxiliary the carry cannot write instead of failing the operation or leaving an empty array behind, and keep a string auxiliary's unit and spatial reference
- reuse the resolved values in read_array, reading once rather than twice, and freeze the entry the variables cache shares
- document the change in the migration guide, the concepts page and the NetCDF reference
Closes #1126
0.61.0 (2026-09-09)#
BREAKING CHANGE#
- a mosaic whose sources declare no no-data value no longer stamps 0. It declares NaN on a floating output, a storable value the data does not use on a gapped integer one, and nothing at all when the sources leave no gap. Pass no_data_value=0 to keep the old declaration, no_data_value=None for no marker, and init= alongside an explicit no_data_value to keep the old gap fill. min, max and sum over integer sources return different -- and correct -- pixels.
Dataset.count_domain_cellsraisesValueErrorinstead ofIndexErrorwhenbandis past the last band. Code catchingIndexErroraround it must catchValueError. A negative band already raised the sameValueErrorfrom the read layer, so only the too-large case changes; callers passing a valid band are unaffected. See docs/migration.md.- a transposed longitude pair is no longer caught. A network reader has no grid to measure a bbox against, so (6, 51, 5, 52) now reads as a 359 degree wrap rather than raising; check the bbox yourself if you relied on that ValueError. An inverted latitude range still raises, because there is no seam in latitude. Separately, from_wms(resolution=...) is now capped at 25,000 px per axis, including on ordinary non-wrapping reads; size=(width, height) is not capped, because a stated size cannot be amplified by a mistake in bbox. Both are documented in docs/migration.md.
bool(ds)raises; useif ds is not None:. A comparison between two rasters is a raster, soif a >= b:,sorted,minandmaxcannot answer it. BREAKING CHANGE:np.<ufunc>(ds, ...)raises;Datasetsets__array_ufunc__ = Noneso numpy defers instead of building an object array. BREAKING CHANGE:pyramids calcrefuses inputs that do not share the first input's grid, where it previously let them broadcast.
Feat#
- dataset: answer the ground area of cells and of the domain (#1123)
- dataset: combine, fold and compare two rasters (#1113)
Fix#
- merge: inherit the sources' no-data instead of defaulting to 0 (#1122)
- dataset: stop inventing a no-data sentinel a band cannot store (#1118)
- merge: name the source that could not be opened (#1120)
- base: serve an antimeridian bbox in the OGC readers (#1119)
- netcdf: decode a CF time axis honestly instead of wrapping it (#1115)
- netcdf: summarize the store in Container.str, not a raster (#1112)
0.60.0 (2026-09-06)#
Fix#
- tests: gate the xarray tests on the interop extra (#1108)
- consolidate duplicated logic and repair the defects it exposed (#1084)
0.59.0 (2026-09-01)#
BREAKING CHANGE#
Dataset.create_from_array,NetCDF.create_from_arrayandDatasetCollection.create_from_arrayare renamed tofrom_array, andUgridDataset.create_from_arraystofrom_arrays. All three constructors --from_array,createandcreate_empty-- now take a single requiredgeo_ref: GeoReferencein place of the previousgeo,epsg,top_left_cornerandcell_sizekeyword subsets, anddriver_typeis removed fromfrom_arrayandcreate_empty. Writers resolve the driver from the path extension, so a destination whose extension names a format other than GeoTIFF now produces that format, and a.vrtdestination raisesFileFormatNotSupportedError. See docs/migration.md.
Fix#
- dataset: accept fig and ax as declared parameters on every plot facade (#1080)
- netcdf: read CF units through one reader, so every consumer sees them (#1079)
Refactor#
- dataset,netcdf: rename create_from_ to from_ and converge on GeoReference (#1076)
0.58.1 (2026-08-30)#
Fix#
- netcdf: georeference and window CF-named coordinates on the HDF5 path (#1072)
- netcdf: return the MDArray for a non-numeric variable instead of raising (#1069)
0.58.0 (2026-08-29)#
Feat#
- merge: restrict merge_rasters to a bbox instead of the full extent (#1065)
0.57.1 (2026-08-27)#
Fix#
- netcdf: declare a CF _FillValue from the streaming cube writer (#1062)
0.57.0 (2026-08-26)#
Feat#
- dataset: consolidate subdataset parsing and warn on container opens (#1056)
Fix#
- io: stop re-wrapping already-resolved /vsi paths on subdataset reopen (#1060)
- netcdf: resolve in-memory (from_bytes) reads via _vsimem_path (#1051)
0.56.0 (2026-08-25)#
Feat#
- spatial: let align choose its resampling method (#1044)
0.55.0 (2026-08-23)#
Feat#
- dataset: add scaled reads, band select, geolocation warp, and an accessor hook (#1041)
- dataset: add subdataset enumeration/open and dataset-level metadata domains (#1040)
- dataset: expose per-band metadata via band_meta_data (#1038)
- dataset: pass GDAL open options through the raster read stack (#1037)
- dataset: warn on outside-template rasterize + add snap_to_template mode (#46) (#1026)
- dataset: add snap_to_template rasterize mode and warn on out-of-template features
Fix#
- netcdf: georeference curvilinear variables to their real lon/lat extent (#1042)
- cog: gate the predictor on sample width and promote sub-byte NBITS (#1035)
- dataset: preserve category names, RAT, and metadata across warp and align (#1036)
- netcdf: copy the in-memory backing store before mutating variables (#1020)
- netcdf: write CF-complete coordinates and grid_mapping from the multidim writers (#1018)
Refactor#
- io: decompose read_array into ReadRequest and ReadStrategy (#1022)
0.54.0 (2026-08-21)#
BREAKING CHANGE#
- Dataset.to_cog(), to_cog_bytes(), and DatasetCollection.to_cog_stack() no longer accept the flat COG option keyword arguments (compress, level, quality, blocksize, predictor, overview_resampling, tiling_scheme, indexes, out_dtype, nodata, band_tags, colormap, ...). Pass the grouped cog.* dataclasses instead, e.g. ds.to_cog("out.tif", compression="zstd", layout=cog.Layout(blocksize=256)).
Feat#
- feature: add from_vectortileserver (ArcGIS VectorTileServer reader) (#994)
Fix#
- netcdf: geotransform x-spacing + animate no-data/exclude/time labels (#1015)
- feature: stage remote https GeoJSON locally instead of streaming over /vsicurl/ (#1011)
Refactor#
- plot: decompose render_array to clear python:S107 and python:S3776 (#1007)
- netcdf: decompose _resolve_curvilinear_coords to clear SonarCloud python:S3776 (#1003)
- netcdf: decompose _cf_coordinates_pair to clear SonarCloud python:S3776 (#1000)
- collection: decompose to_netcdf into TimeAxis + CubeNetCDFWriter (S3776) (#998)
- netcdf: decompose _read_variable to clear SonarCloud python:S3776 (#996)
- netcdf: mirror NetCDF.plot signature on Dataset.plot (#995)
- netcdf: group create_from_array's parameters into typed option dataclasses (#989)
- cog: move grouped-option logic onto the option dataclasses (#988)
- cog: group to_cog's 29 parameters into typed option dataclasses (#986)
Perf#
- collection: skip GDAL's per-open directory scan in from_files for sidecar-free folders (#1012)
0.53.0 (2026-08-14)#
Fix#
- remote: make cloud credentials reach VSICurl worker threads, per bucket (#984)
- cell: label cell polygons/points with the CRS spec, not the EPSG code (#981)
Perf#
- netcdf: bound peak memory — stream from_xarray, container crop/to_crs/resample, and UGRID reads (#980)
0.52.0 (2026-08-12)#
Fix#
- crs: resolve CRSes with the database that produced them (#959)
Refactor#
- plot: adopt cleopatra 0.31 RgbBands for the ArrayGlyph constructor (#972)
Perf#
- dataset: stream the remaining eager full-array Dataset methods (#971)
- dataset: block-streaming helpers for the eager full-array methods (#968)
0.51.0 (2026-08-12)#
BREAKING CHANGE#
- the loose plot / animate styling keywords are removed. Pass the typed cleopatra groups instead — color_scale= becomes color=ColorScaling(...), style= / hillshade= become data_style=DataStyle(...), levels= becomes contour=Contour(...), point_= becomes points=PointOverlay(...), and cbar_= / ticks_spacing= become colorbar=ColorBar(...). Requires cleopatra >=0.30.0.
- DatasetCollection.create_cube is renamed to from_dataset, and from_stac no longer accepts like/crs/resolution/bounds/ anchor keyword arguments — pass grid=Grid(...) instead.
Feat#
- plot: adopt cleopatra 0.30 typed render groups across all plot methods (#946)
- spatial: windowed crop(bbox=) that avoids full reads of huge/remote rasters (#966)
- dataset: generate a color table from a color ramp (#958)
Refactor#
- collection: consolidate the DatasetCollection constructor API (#951)
Perf#
- collection: stream to_netcdf instead of materialising the full cube (#961)
0.50.0 (2026-08-09)#
BREAKING CHANGE#
- read_multiple_files'
extensionparameter is replaced by aglobfnmatch filter (e.g.extension="tif"becomesglob="*.tif").
Feat#
- collection: consolidate the DatasetCollection readers into from_files and harden the dunders (#942)
Fix#
- ci: pin build-time setuptools <84 for the GDAL bindings build (#950)
Refactor#
- netcdf: write to_netcdf through GDAL, no xarray outside the interop methods (#945)
0.49.0 (2026-08-05)#
BREAKING CHANGE#
- create_overviews and recreate_overviews now raise OverviewTargetError for a plain VRT whose description is not a path, and recreate_overviews raises it for levels a VRT computes rather than stores. Code catching ReadOnlyError around recreate_overviews on such a handle must catch OverviewTargetError instead. Dataset.wrap_longitude() on a file-backed source and Dataset.to_zarr(overview_factors=...) are affected through the same guard.
Feat#
- plot: render paletted rasters through their GDAL colour table (#939)
- plot: finish the typed plot-spec migration on .plot/.animate (#930)
- plot: adopt cleopatra 0.28 and its typed plot + basemap API (#920)
Fix#
- netcdf: round-trip no-data and sub-second time units on read (#937)
- dataset: refuse overview targets a dataset cannot hold (#921)
- remote: recognise ADLS Gen2 and complete the VSI handler tables (#924)
Perf#
- spatial: bound the cutline crop warp to the output window (#938)
- collection: stream DatasetCollection.to_file per timestep (#925)
0.48.0 (2026-08-02)#
BREAKING CHANGE#
- gdal.RegenerateOverviews cascades, filling each deeper level from the level above rather than from the full-resolution band, so overviews at level 1 and deeper change. Level 0 is unaffected. Values survive only for nearest, and for average/rms on a floating-point band with no no-data; every other method differs, and mode can move by whole classes. Nothing warns, and there is no way back -- create_overviews cascades too. See docs/migration.md.
Feat#
- processing: add declarative geoprocessing pipeline + batch runner (#912)
- dataset: expose an overview level as a Dataset (#915)
Fix#
- dataset: don't treat a paletted band as RGB imagery in plot() (#914)
- dataset: report every recreate_overviews outcome (#895)
Perf#
- dataset: regenerate a band's overviews in one GDAL pass (#919)
0.47.0 (2026-08-01)#
BREAKING CHANGE#
Dataset.epsgandNetCDF.epsgreturnNonefor a raster with no CRS, and for a CRS that carries no EPSG authority, where both previously returned 4326.read_part(bbox=)andpoint()defaultbbox_crs/point_crsto the raster's own coordinates instead of EPSG:4326; passbbox_crs=4326to restore the old reading. Read.crs, orcrs_spec(ds.epsg, ds.crs), where a specification rather than a code is needed.- DatasetCollection.tail(n) now returns the last abs(n) timesteps for a positive n too (previously a positive n skipped the first n); the default tail(-n) is unchanged and tail(0) returns an empty array.
- COG_READ_DEFAULTS no longer sets CPL_VSIL_CURL_ALLOWED_EXTENSIONS. The option made GDAL refuse any URL whose path does not end in .tif or .tiff, which excluded extensionless object keys, presigned S3 links carrying a query string, and most STAC asset hrefs. BREAKING CHANGE: slope, aspect and hillshade emit the band's sentinel at no-data cells and their immediate neighbours, outside the documented [0, 360) and [0, 255] ranges, because a centred difference straddling a void has no defined derivative. Mask on the no-data value before feeding the result to a colour ramp or a fixed-range cast. BREAKING CHANGE: focal_apply hands the caller's callable a NaN-blanked window, so a NaN-blind reducer now blanks every window touching a void. Use the np.nan* reducers.
Closes #841, #842, #843, #844, #845, #846, #847 Closes #848, #849, #850, #851, #852, #853, #855 Closes #856, #857, #858, #859, #860, #861, #862
Feat#
- netcdf: lazy to_xarray(chunks=) and shared NETCDF: prefix helper(#864)
- stac: fix credential loss, silent VRT drops, and untuned remote reads (#839)
Fix#
- crs: stop fabricating EPSG:4326 for rasters that have no CRS (#893)
- io: consolidate resource detection and fix handle, temp-dir, and JSON defects (#868)
- dataset: resolve the engines architecture review findings (#840)
- netcdf: resolve architecture-review findings across core and ugrid (#816)
- dataset: resolve arc-dataset-core access, leak, and perf findings (#798)
- docs: make the shipped docstring examples collect and run under doctest (#776)
Refactor#
- feature: resolve the arc-feature architecture-review findings (#867)
- base: rework handle caching, logging and dtype conversion (#797)
Perf#
- collection: harden the datacube for out-of-core use (#866)
0.46.0 (2026-07-14)#
Feat#
- wcs: surface the HTTP response body in WCSError on GetCoverage errors (#746)
- plot: adopt cleopatra 0.25 and surface apply_style on returned glyphs (#745)
0.45.0 (2026-07-13)#
Feat#
- plot: expose cleopatra style presets and hillshade across all raster and mesh plot paths (#740)
- bbox: add estimate_pixel_dims and read_bbox_dict helpers (#736)
- dataset: add bbox_rounding and fix bbox/polygon window resolution (#732)
- crs: add a public UTM zone/EPSG helper (#734)
Fix#
- netcdf: orient lazy reads on the resolved plane, not the trailing axes (#741)
- netcdf: release lazy read GDAL handles on array drop and on NetCDF.close() (#738)
- io: drop misleading 7z mention from gzip error message (#733)
Refactor#
- sonar: cut python:S3776 cognitive complexity in 34 functions (#739)
0.44.0 (2026-07-11)#
Feat#
- dataset: let direct from_wcs override built-in KVP keys for shims (#725)
Fix#
- netcdf: orient NetCDF reads from the scaled coordinate, not the raw geotransform (#722)
- dataset: enforce types across the dataset subpackage (#721)
0.43.0 (2026-07-09)#
Feat#
- dataset: add a discovery-less direct GetCoverage mode to from_wcs (#718)
0.42.0 (2026-07-08)#
Feat#
- dataset: add WMS/WMTS raster readers via GDAL native drivers (#698)
Fix#
- ci: pin wheel-build checkouts to the triggering commit, not the branch ref (#716)
- netcdf: window-safe fast geostationary reads and no-EPSG CRS (#709)
- netcdf: stop mislabeling a geostationary CRS as EPSG:4326 (#707)
Refactor#
- collection: replace flox with a local single-pass grouped reduction (#714)
0.41.0 (2026-07-06)#
Feat#
- wheels: publish win_arm64 wheels with a vendored vector stack (#695)
- collection: add a time axis and label animation frames by it (#694)
- crop: support antimeridian-crossing (west>east) bbox (#692)
- grib: add grib_to_cog to convert a GRIB message to a COG (#690)
Fix#
- ci: verify-alpine test paths broken by the test-suite reorg (#689)
0.40.0 (2026-07-05)#
Fix#
- plot: auto-detect RASM xc/yc curvilinear coordinates (#682)
- dataset: correct footprint on NetCDF views and all nodata fills (#679)
0.39.0 (2026-07-01)#
Feat#
- dataset: add Dataset.from_ogc_coverages and finish the OGC reader family (#663)
- feature: add FeatureCollection.from_ogc_api_features reader (#656)
Fix#
- netcdf: stop curvilinear plots smearing across the antimeridian (#670)
- netcdf: stop curvilinear plots smearing across the antimeridian
Curvilinear NetCDF grids whose longitude crosses the 0/360 antimeridian rendered as a full-width smear, because pcolormesh read the 359->0 wrap as one giant cell. render_array now makes a wrapping degree-geographic longitude continuous before it reaches cleopatra, gated so projected, unknown-CRS, and non-wrapping grids are left untouched.
Plotting fix: - NaN-safe, degrees-only, dtype-preserving, single-return unwrap - unit tests for the unwrap and CRS gate, plus an end-to-end regression on a real wrapping curvilinear file - cover multi-wrap rows, single-column grids, and interior-NaN edges
Documentation: - correct the basemap claims in the CF/COARDS explore notebooks: they plot in the data's own CRS with a Natural Earth coastline overlay, not a reprojected OpenStreetMap / Web Mercator basemap - drop the redundant crs= from add_features across the explore and anatomy notebooks; the returned glyph already carries the CRS - plot the anatomy examples via NetCDF.plot() instead of raw matplotlib - add a NetCDF class anatomy & reference notebook - add mermaid diagrams across the NetCDF reference: container/variable object model, engines, the metadata pipeline and dataclass aggregation, the plot pipeline, the CF capability map, and the ugrid class model, conversion bridges, and submodule diagrams
Documentation accuracy & hygiene: - fix the UgridMetadata data_variables edge (it is a dict[str,str] name->location map, not MeshVariable records) - clarify the metadata serializers are module-level functions, not methods on NetCDFMetadata - list representative CF classification roles instead of a partial set - remove the object-model flowchart's subgraph self-loop - scrub committed notebook output: drop an INFO log line and sanitize an ipykernel temp path that leaked a local username
Test quality: - assert unwrapped values with np.isclose instead of float == - pass an unresolvable EPSG code, not a str, to the CRS-gate test
Closes #669
Refactor#
- typing: make the netCDF subpackage and engine layer pass mypy (#657)
0.38.0 (2026-06-28)#
BREAKING CHANGE#
- opening a store now returns a Container and extracting a variable returns a Variable (both NetCDF subclasses, so isinstance(x, NetCDF) still holds); type(x) is NetCDF is no longer true for these. Directly constructing NetCDF(...) is deprecated and emits a DeprecationWarning — use NetCDF.read_file(...) / NetCDF.create_from_array(...) (-> Container) and container.get_variable(...) (-> Variable). NetCDF remains an isinstance-compatible base for one major version.
Feat#
- base: RasterLike protocol + numpy.typing array-return typing (ARC-18/ARC-19) (#648)
- netcdf: zero-copy lazy get_group view (ARC-12) (#642)
- netcdf: read remote NetCDF over OPeNDAP/THREDDS via dods:// URLs (#644)
- netcdf: stream create_from_array writes for dask inputs (ARC-11) (#637)
- feature: add FeatureCollection.from_wfs OGC Web Feature Service reader (#635)
- wcs: add Dataset.from_wcs OGC Web Coverage Service reader (#632)
- wcs: add Dataset.from_wcs OGC Web Coverage Service reader
Add a version-normalising OGC WCS reader exposed as the Dataset.from_wcs classmethod (implementation in dataset/_wcs.py), backed by GDAL's native WCS driver so the 1.0.0 vs 2.0.x GetCoverage dialect fork is handled inside GDAL rather than hand-written.
- Caller supplies one lon/lat bbox plus optional resolution and output_crs; the reader issues the version-correct GetCoverage.
- CRS shim: attach a caller-supplied coverage_crs when the server's advertised CRS is absent from PROJ (e.g. SoilGrids EPSG:152160).
- Client-side bbox reprojection into the coverage's native CRS via pyproj, densified with transform_bounds so distorted or large windows stay covered.
- GetCapabilities fetched once per endpoint (LRU-cached); an unknown coverage raises ValueError, server errors raise the new WCSError.
- The windowed read goes through an in-memory dataset, so a non-raster ExceptionReport body can never be written to a .tif.
- No new dependencies: GDAL handles transport and decode, pyproj (core) the CRS transform, and Dataset the warp/IO.
- Tests: pure helpers, the CRS shim, the capabilities cache, and a protocol-faithful mock server that drives GDAL end-to-end for both WCS dialects (asserting each call shape), plus gated live SoilGrids tests; 100% line and branch coverage on the new module.
Closes #626 - netcdf: split NetCDF into Container + Variable types (API-1) (#625)
Fix#
- netcdf: drop xarray interop tests duplicated in test_xarray_interop (#636)
Refactor#
- netcdf: extract engine subpackage from the NetCDF god-object (STR-1) (#627)
- netcdf: consolidate duplicated MDIM/CF/UGRID logic behind the stable API (#612)
0.36.0 (2026-06-23)#
Feat#
- netcdf: add exploration example notebooks and supporting grid work (#581)
- feature: FeatureCollection GIS gaps — fishnet, IDW interpolation, PMTiles/MVT, GPX, FeatureServer and a native H3 engine(#591)
- dataset: add Dataset.to_terrain_rgb (terrain-RGB encoding + XYZ tiles) (#590)
Fix#
- test: skip optional-dependency tests on the bare-wheel core CI run (#610)
- packaging: bundle the JP2OpenJPEG driver so JP2-packed GRIB2 reads (#601)
0.35.0 (2026-06-16)#
Feat#
- feature: add voronoi and quadtree tessellation ops to FeatureCollection (#562)
Fix#
- clear SonarCloud main quality gate (reliability, security, hotspots) (#577)
- netcdf: path-style S3 addressing for anonymous LabeledDataset reads (#569)
- dataset: array_to_map_coordinates honours non-square and rotated grids (#568)
- netcdf: carry string aux variables through container spatial ops (#567)
- netcdf: release the GDAL handle on close() so the file unlocks immediately (#566)
- netcdf: release the GDAL handle on close() so the file unlocks immediately
- netcdf: build kerchunk manifests natively to kill the zarr-v3 deadlock (#561)
0.34.0 (2026-06-14)#
Feat#
- collection: RGB true-colour animation in DatasetCollection.plot (#557)
- dataset: GCP/RPC georeferencing + mask, window, CLI & parallel-read ergonomics (#536)
Fix#
- netcdf: resolve S3 bucket region for anonymous LabeledDataset reads (#537)
0.33.0 (2026-06-14)#
Feat#
- NetCDF GDAL-multidim LabeledDataset rewrite, extras consolidation, wheel/CLI hardening (#520)
- dataset: decimated (out_shape) reads in the core read_array (#512)
- dataset: boundless windowed reads with fill values (#511)
- dataset: thread-safe parallel reads via per-thread GDAL handles (#510)
- dataset: add read_array(masked=True) returning a MaskedArray (#503)
- dataset: add first-class Window object with block iteration (#504)
- dataset: add warped_view - a lazy VRT-backed reprojected view (#508)
- dataset: expand resampling methods to the full GDAL set (#501)
- dataset: add Dataset.to_bytes for in-memory serialization (#502)
- cli: add info/bounds/clip/warp/merge/overview/sample/convert subcommands (#509)
- dataset: add xy()/rowcol() aliases and a GeoTransform object (#506)
Fix#
- netcdf: carry non-spatial aux variables through container spatial ops (#514)
0.32.0 (2026-06-08)#
Feat#
- dataset: add create_empty / empty_like out-of-core raster allocators (#473)
- netcdf: surface time coord/length and window interleaved-layer variables (#468)
Fix#
- collection: render DatasetCollection.plot() when rasters have no nodata (#481)
Refactor#
- remove out-of-scope domain surfaces (grids, EO signers, natural_earth/relief) (#476)
- remove out-of-scope domain surfaces; deprecate the rest
Perf#
- wheels: trim niche GDAL_DATA and add wheel size/leak guardrails (#475)
- wheels: shrink the bundled platform wheel 18-27% and make wheel CI deterministic (#471)
0.31.0 (2026-06-03)#
Fix#
- bootstrap: force GDAL_DRIVER_PATH to the bundled plugins (#465)
0.30.0 (2026-06-02)#
Feat#
- netcdf: add NetCDF.subset for windowed gridded cloud-cube reads (#462)
- basemap: add relief() low-res global relief raster for offline backdrops (#461)
0.29.0 (2026-06-01)#
Feat#
- netcdf: add LabeledDataset reader for label-indexed NetCDF/Zarr stores (#455)
0.28.0 (2026-05-31)#
Feat#
- plot: upgrade cleopatra integration to 0.12.0 API and adopt new capabilities (#451)
- io: add decompress-aware resource reader (sniff → Dataset / FeatureCollection / DataFrame) (#448)
Fix#
- netcdf: georeference geostationary (GOES) reads via the classic driver (#452)
0.27.0 (2026-05-28)#
Feat#
- dataset: accept arbitrary CRS in Dataset.to_crs (#444)
0.26.0 (2026-05-28)#
Refactor#
- zarr: GeoZarr geobox, lazy read, cube round-trip, codecs, append + foreign/STAC reads (#417)
0.25.1 (2026-05-27)#
Fix#
- wheels: vendor curl CA bundle so vendored-GDAL HTTPS reads work (#414)
0.25.0 (2026-05-26)#
Feat#
- add grid adapters, unit conversion, and Natural Earth features (#407)
0.24.1 (2026-05-26)#
Fix#
- crs: resolve un-authority-tagged CRSes instead of returning child codes (#404)
0.24.0 (2026-05-26)#
Feat#
- cog: unify write policy and add inspection, reads, profiles, and CLI (#402)
0.23.0 (2026-05-25)#
Feat#
- stac: add GDAL-native STAC subpackage and fix no-data/windowed-read bugs (#363)
0.22.0 (2026-05-23)#
Feat#
- dataset: extend merge_rasters and add DatasetCollection.reduce_time (#360)
0.21.0 (2026-05-21)#
Feat#
- add cloud-provider readers and GDAL-native raster operations (#339)
0.20.0 (2026-05-19)#
Feat#
- wheels: bundle GDAL into pip-installable platform wheels (#243)
Fix#
- wheels: only force platform tag in setup.py when PACKAGE_DATA=1
0.19.0 (2026-05-15)#
Feat#
- add bytes/archive/band-stack/bbox/NetCDF/HTTP-knob entry points (#322)
0.18.0 (2026-05-11)#
Feat#
- plot: xarray-aligned NetCDF.plot API and unified plotting layer (#316)
0.17.0 (2026-05-10)#
Feat#
- netcdf: support 4-D+ NetCDFs and fix CDS-Beta metadata path (#313)
0.16.0 (2026-05-09)#
Fix#
- wheel-test: unblock core matrix; add branch input to dispatch (#308)
Refactor#
- re-evaluate package architecture; close audit(#289)
0.15.0 (2026-04-24)#
Feat#
- dask: integrate Dask across dataset, netcdf, collection, and feature paths (#253)
Fix#
- wheel-test fails for plot tests (#261)
Refactor#
- feature: modernize feature subpackage and expand I/O surface (#252)
0.14.0 (2026-04-14)#
Feat#
- cog: add Cloud Optimized GeoTIFF support (write, validate, cloud I/O, stack export) (#249)
0.13.0 (2026-04-12)#
Feat#
- basemap: add web tile basemap plotting support (#231)
0.12.0 (2026-04-11)#
Feat#
- delegate UGRID plotting to cleopatra and add dunder methods to FeatureCollection (#230)
- netcdf: add UGRID unstructured mesh support (#224)
0.11.0 (2026-04-05)#
Feat#
- netcdf: add CF conventions support and xarray interop (#198)
Fix#
- resolve architectural issues across dataset, netcdf, and feature modules (#197)
0.10.0 (2026-04-04)#
Feat#
- netcdf: add variable operations, metadata refinement, and rename ArrayInfo to VariableInfo (#172)
- netcdf: add variable operations, metadata refinement, and rename ArrayInfo to VariableInfo
Refactor#
- dataset: resolve 20 design issues from architectural review (#175)
- restructure package layout and decompose Dataset into mixins (#170)
0.9.1 (2026-03-29)#
Fix#
- packaging: add GDAL to PyPI deps and fix missing YAML files in wheel (#162)
Refactor#
- api: replace os module with pathlib across all public APIs (#157)
0.9.0 (2026-03-27)#
Feat#
- logging: Centralized logging via
LoggerManagerwith colored console and optional file logging; reduced third‑party log noise. (#135) - logging: Centralized logging via
LoggerManagerwith colored console and optional file logging; reduced third‑party log noise. (#135)
Refactor#
- typing: modernize type annotations and add mypy (#146)
- netcdf: extract into subpackage with MDIM round-trip support (#91)
0.8.0 (2025-09-06)#
Feat#
- plot: add to_xyz method and improve plotting integration with Cleopatra
- docker: add Docker support with workflow and documentation
CI#
- docker: fix docker-release workflow configuration
Docs#
- update badges and improve formatting in README and index files
- fix typo in dev container setup steps
- migrate to MkDocs with Google-style docstrings and diagrams
Chore#
- deps: disable changelog autoupdate - Disabled
update_changelog_on_bumpin pyproject settings - Updated styles in pyproject for improved terminal prompts - Simplified release workflow by removing unnecessary debug steps - release: enhance debug visibility and tag handling in workflow
- release: ensure tags are fetched for release workflow
- deps: update sha256 checksum for
pyramids-gisto match new version 0.7.3 - pyproject: remove
major_version_zeroconfiguration - release: add Commitizen and automated release workflow
- update dependencies, workflows, and docs
- dev: add dev container and docs
- ci: update workflow permissions and group publishing dependencies
0.7.3 (2025-08-02)#
Dev#
- add pixi configuration to the pyproject.toml file.
- relax the limits for the dependencies in the pyproject.toml file.
- gdal is installed from conda-forge channel.
- update the workflow to use the new pixi configuration.
0.7.2 (2025-01-12)#
Dev#
- replace the setup.py with pyproject.toml
- automatic search for the gdal_plugins_path in the conda environment, and setting the
GDAL_DRIVER_PATHenvironment variable. - add python 3.12 to CI.
0.7.1 (2024-12-07)#
- update
cleopatrapackage version to 0.5.1 and update the api to use the new version. - update the miniconda workflow in ci.
- update gdal to 3.10 and update the DataSource to Dataset in the
FeatureCollection.file_name. - add
libgdal-netcdfandlibgdal-hdf4to the conda dependencies.
0.7.0 (2024-06-01)#
- install viz, dev, all packages through pip.
- create a separate module for the netcdf files.
- add configuration file and module for setting gdal configurations.
AbstractDataset#
- add
meta_dataproperty to return the metadata of the dataset. - add
accessproperty to indicate the access mode of the dataset.
Dataset#
- add extra parameter
file_ito theread_filemethod to read a specific file in a compressed file. - initialize the
GDAL_TIFF_INTERNAL_MASKconfiguration toNo - the add the
accessparameter to the constructor to set the access mode of the dataset. - add the
band_unitsproperty to return the units of the bands. - the
__str__and the__repr__methods return string numpy like data type (instead of the gdal constant) of the dataset. - add
meta_dataproperty setter to set any key:value as a metadata of the dataset. - add
scaleandoffsetproperties to set the scale and offset of the bands. - add
copymethod to copy the dataset to memory. - add
get_attribute_tableset_attribute_table` method to get/set the attribute table of a specific band. - the
plotmethod uses the rgb bands defined in the dataset plotting (if exist). - add
createmethod to create a new dataset from scratch. - add
write_arraymethod to write an array to an existing dataset. - add
get_maskmethod to get the mask of a dataset band. - add
band_colormethod to get the color assigned to a specific band (RGB). - add
get_band_by_colormethod to get the band index by its color. - add
get_histogrammethod to get/calculate the histogram of a specific band. - the
read_arraymethod takes and extra parameterwindowto lazily read awindowof the raster, the window is [xoff, yoff, x-window, y-window], thewindowcan also be a geodataframe. - add
get_block_arrangementmethod divide the raster into tiles based on the block size. - add tiff file writing options (compression/tile/tile_length)
- add
closemethod to flush to desk and close a dataset. - add
add_bandmethod to add an array as a band to an existing dataset. - rename
pivot_pointtotop_left_cornerin thecreatemethod. - the
to_filemethod return aDatasetobject pointing to the saved dataset rather than the need to re-read the saved dataset after you save it.
Datacube#
- the
Datacubeis moved to a separate moduledatacube.
NetCDF#
- move all the netcdf related functions to a separate module
netcdf.
FeatureCollection#
- rename the
pivot_pointtotop_left_corner
Deprecated#
*Cropping a raster using a polygon is done now directly using gdal.wrap nand the the _crop_with_polygon_by_rasterizing
is deprecated.
* rename the interpolation method nearest neighbour to nearest neighbor.
0.6.0 (2024-02-24)#
- move the dem module to a separate package "digital-rivers".
0.5.6 (2024-01-09)#
Dataset#
- create
create_overviews,recreate_overview,read_overview_arraymethods, andoverview_countattribute to handle overviews. - The
plotmethod takes an extra parametersoverviewsandoverview_indexto enable plotting overviews instead of the real values in the bands.
0.5.5 (2024-01-04)#
Dataset#
- Count domain cells for a specific band.
0.5.4 (2023-12-31)#
Dataset#
- fix the un-updated array dimension bug in the crop method when the mask is a vector mask and the touch parameter is True.
0.5.3 (2023-12-28)#
Dataset#
- Introduce a new parameter touch to the crop method in the Dataset to enable considering the cells that most of the cell lies inside the mask, not only the cells that lie entirely inside the mask.
- Introduce a new parameter inplace to the crop method in the Dataset to enable replacing the dataset object with the new cropped dataset.
- Adjust the stats method to take a mask to calculate the stats inside this mask.
0.5.2 (2023-12-27)#
Dataset#
- add _iloc method to get the gdal band object by index.
- add stats method to calculate the statistics of the raster bands.
0.5.1 (2023-11-27)#
Dataset#
- revert the convert_longitude method to not use the gdal_wrap method as it is not working with the new version of gdal (newer tan 3.7.1).
- bump up versions.
0.5.0 (2023-10-01)#
Dataset#
- The dtype attribute is not initialized in the init, but initialized when using the dtype property.
- Create band_names setter method.
- add gdal_dtype, numpy_dtype, and dtype attribute to change between the dtype (data type general name), and the corresponding data type in numpy and gdal.
- Create color_table attribute, getter & setter property to set a symbology (assign color to different values in each band).
- The read_array method returns array with the same type as the dtype of the first band in the raster.
- add a setter method to the band_names property.
- The methods (create_driver_from_scratch, get_band_names) is converted to private method.
- The no_data_value check the dtype before setting any value.
- The convert_longitude used the gdal.Wrap method instead of making the calculation step by step.
- The to_polygon is converted to _band_to_polygon private method used in the clusters method.
- The to_geodataframe is converted to to_feature_collection. change the backend of the function to use the crop function is a vector mask is given.
- the to_crs takes an extra parameter "inplace".
- The locate_points is converted to map_to_array_coordinates.
- Create array_to_map_coordinates to translate the array indices into real map coordinates.
DataCube#
- rename the read_separate_files to read_multiple_files, and enable it to use regex strings to filter files in a given directory.
- rename read_dataset to open_datacube.
- rename the data attribute to values
FeatureCollection#
- Add a pivot_point attribute to return the top left corner/first coordinates of the polygon.
- Add a layers_count property to return the number of layers in the file.
- Add a layer_names property to return the layers names.
- Add a column property to return column names.
- Add the file_name property to store the file name.
- Add the dtypes property to retrieve the data types of the columns in the file.
- Rename bounds to total_bounds.
- The _gdf_to_ds can convert the GeoDataFrame to a ogr.DataSource and to a gdal.Dataset.
- The create_point method returns a shapely point object or a GeoDataFrame if an epsg number is given.
0.4.2 (2023-04-27)#
- fix bug in plotting dataset without specifying the band
- fix bug in passing ot not passing band index in case of multi band rasters
- change the bounds in to_dataset method to total_bounds tp get the bbox of the whole geometries in the gdf
- add convert_longitude method to convert longitude to range between -180 and 180
0.4.1 (2023-04-23)#
- adjust all spatial operation functions to work with multi-band rasters.
- use gdal exceptions to capture runtime error of not finding the the file.
- add cluster method to dataset class.
- time_stamp attribute returns None if there is no time_stamp.
- restructure the no_data_value related functions.
- plot function can plot rgb image for multi-band rasters.
- to_file detect the driver type from the extension in the path.
0.4.0 (2023-04-11)#
- Restructure the whole package to two main objects Dataset and FeatureCollection
- Add class for multiple Dataset "DataCube".
- Link both Dataset and FeatureCollection to convert between raster and vector data types.
- Remove rasterio and netcdf from dependencies and depend only on gdal.
- Test read rasters/netcdf from virtual file systems (aws, compressed)
- Add dunder methods for all classes.
- add plotting functionality and cleopatra (plotting package) as an optional package.
- remove loops and replace it with ufunc from numpy.
0.3.3 (2023-02-06)#
- fix bug in reading the ogr drivers catalog for the vector class
- fix bug in creating rasterLike in the asciiToRaster method
0.3.2 (2023-01-29)#
- refactor code
- add documentation
- fix creating memory driver with compression in _createDataset
0.3.1 (2023-01-25)#
- add pyarrow to use parquet data type for saving dataframes and geodataframes
- add H3 indexing package, and add new module indexing with functions to convert geometries to indices back and forth.
- fix bug in calculating pivot point of the netcdf file
- rasterToDataFrame function will create geometries of the cells only based on the add_geometry parameter.
0.3.0 (2023-01-23)#
- add array module to deal with any array operations.
- add openDataset, getEPSG create SpatialReference, and setNoDataValue utility function, getCellCoords, ...
- add rasterToPolygon, PolygonToRaster, rasterToGeoDataFrame, conversion between ogr DataSource and GeoDataFrame.
0.2.11 (2023-01-14)#
- add utils module for functions dealing with compressing files, and others utility functions
0.2.11 (2022-12-27)#
- fix bug in pypi package names in requirements.txt file
0.2.10 (2022-12-25)#
- lock numpy version to 1.23.5 as conda-forge can not install 1.24.0
0.2.9 (2022-12-19)#
- Use environment.yaml and requirements.txt instead of pyproject.toml and replace poetry env by conda env
0.1.0 (2022-05-24)#
- First release on PyPI.