You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+20Lines changed: 20 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
8
+
## 0.9.0 (2026-04-02)
9
+
10
+
## What's Changed
11
+
* Add site_url to the mkdocs config by @maxrjones in https://github.com/EOPF-Explorer/data-model/pull/121
12
+
* Update GeoZarr mini-spec to EOPF V1 by @emmanuelmathot in https://github.com/EOPF-Explorer/data-model/pull/129
13
+
* use zarr-cm for defining zarr conventions metadata by @d-v-b in https://github.com/EOPF-Explorer/data-model/pull/131
14
+
* chore/fill value consistency by @d-v-b in https://github.com/EOPF-Explorer/data-model/pull/135
15
+
* Set the minimum supported python version to 3.12 by @d-v-b in https://github.com/EOPF-Explorer/data-model/pull/141
16
+
* add titiler integration test by @d-v-b in https://github.com/EOPF-Explorer/data-model/pull/137
17
+
* Pin GitHub Actions to commit SHAs (coordination#239) by @lhoupert in https://github.com/EOPF-Explorer/data-model/pull/143
18
+
* ci: add permissions block and make security checks blocking by @lhoupert in https://github.com/EOPF-Explorer/data-model/pull/145
19
+
* enh: clarify CF metadata scope in GeoZarr mini-spec and update attribute definitions by @emmanuelmathot in https://github.com/EOPF-Explorer/data-model/pull/133
20
+
* feat: include b08 in resolution groups by @d-v-b in https://github.com/EOPF-Explorer/data-model/pull/152
21
+
22
+
## New Contributors
23
+
*@maxrjones made their first contribution in https://github.com/EOPF-Explorer/data-model/pull/121
24
+
*@lhoupert made their first contribution in https://github.com/EOPF-Explorer/data-model/pull/143
Copy file name to clipboardExpand all lines: docs/geozarr-minispec.md
+106-5Lines changed: 106 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,6 +49,107 @@ and their attributes before moving to higher-level structures like groups and th
49
49
50
50
This specification targets **Zarr V3** exclusively. The geo-proj, spatial, and multiscales conventions are all Zarr V3.
51
51
52
+
## Store Root
53
+
54
+
A GeoZarr Store is the outermost Zarr group of a dataset — the group located at the root of the Zarr store (e.g. `my_dataset.zarr/zarr.json`). It sits above any [Dataset](#dataset) or [Multiscale Dataset](#multiscale-dataset) nodes in the hierarchy and is intended to give clients a single place to read a **summary spatial footprint** for the whole store without having to walk into child groups.
55
+
56
+
> [!Note]
57
+
> The hierarchy and identification rules below are local choices made for this implementation. They are subject to revision once the OGC GeoZarr Standards Working Group decides on canonical wording. A follow-up to surface these rules upstream is tracked in [zarr-developers/geozarr-spec#132](https://github.com/zarr-developers/geozarr-spec/issues/132). See also [GeoZarr Specification Contribution](geozarr-specification-contribution.md).
58
+
59
+
### Hierarchy & Identification
60
+
61
+
A GeoZarr hierarchy has these properties:
62
+
63
+
-**Single root**: every GeoZarr store has exactly one root group.
64
+
-**Root naming**: the root group is stored under a prefix ending with `.zarr` (e.g. `my_dataset.zarr/`). Clients given any sub-path inside a GeoZarr store MAY recover the root by walking up the path until they hit a segment ending in `.zarr`.
65
+
-**No nested stores**: the `.zarr` suffix SHOULD occur exactly once in any path within the hierarchy. Nesting GeoZarr stores (e.g. `a.zarr/b/c.zarr/`) is strongly discouraged because it breaks the root-recovery rule above.
66
+
-**Terminal paths**: a path `p` within the hierarchy is *terminal* (a leaf) when any of the following holds:
67
+
- an array node is reached at `p`,
68
+
- a group with no members is reached at `p`,
69
+
-`p` ends with a `zarr.json` file.
70
+
71
+
### Attributes
72
+
73
+
The store root carries a top-level spatial footprint. This is **informative**: it helps clients place the store spatially (STAC-style discovery) but is not authoritative — per-Dataset / per-Multiscale Dataset `spatial:` and `proj:` attributes remain the source of truth for reading individual variables.
74
+
75
+
| key | type | required | notes |
76
+
| --- | ---- | -------- | ----- |
77
+
|`zarr_conventions`| array | yes | MUST declare the `spatial:` and `proj:` conventions used at the root |
78
+
|`spatial:bbox`| number[4]| yes | Bounding box `[xmin, ymin, xmax, ymax]` covering the union of all spatial assets in the store, expressed in the CRS named by `proj:code` (or `proj:wkt2` / `proj:projjson`) |
79
+
|`proj:code`| string | conditional*| Authority:code identifier of the bbox CRS, e.g. `"EPSG:4326"`|
80
+
|`proj:wkt2`| string | conditional*| WKT2 representation of the bbox CRS |
81
+
|`proj:projjson`| object | conditional*| PROJJSON representation of the bbox CRS |
82
+
83
+
\* At least one of `proj:code`, `proj:wkt2`, `proj:projjson` MUST be provided. Use `"EPSG:4326"` (longitude/latitude, degrees) when no other CRS is meaningful — the store-root CRS is always declared explicitly; there is no implicit default.
84
+
85
+
> [!Note]
86
+
> The store-root `spatial:bbox` is **a summary** — e.g. the union of footprints from all nested Datasets / Multiscale Datasets. It is not a substitute for the per-group `spatial:bbox` defined by the [spatial convention](https://github.com/zarr-conventions/spatial).
87
+
88
+
> [!Note]
89
+
> A future extension may carry a list-of-bboxes at the root (one global + one per child group), STAC-style. This is tracked in [zarr-developers/geozarr-spec#133](https://github.com/zarr-developers/geozarr-spec/issues/133).
@@ -244,7 +345,7 @@ The `zarr_conventions` array at the Multiscale Dataset's root group MUST declare
244
345
|`multiscales`|[MultiscalesMetadata](#multiscalesmetadata)| yes | Pyramid layout for this group |
245
346
|`proj:code`| string | conditional*| CRS for all resolution levels (group-level inheritance) |
246
347
|`spatial:dimensions`| string[]| yes | Names of spatial dimensions, e.g. `["Y", "X"]`|
247
-
|`spatial:bbox`| number[]|no| Overall bounding box in the CRS coordinate space |
348
+
|`spatial:bbox`| number[4]|yes| Overall bounding box `[xmin, ymin, xmax, ymax]`in the CRS coordinate space, covering every level in the pyramid|
248
349
249
350
\* At least one of `proj:code`, `proj:wkt2`, or `proj:projjson` must be provided for geospatial datasets.
250
351
@@ -267,8 +368,8 @@ Each object in the `layout` array represents one resolution level:
267
368
|`derived_from`| string | no | Path to the source level from which this level was generated. Required to define the transform |
268
369
|`transform`|[TransformObject](#transformobject)| conditional | Required when `derived_from` is present. Describes the relative coordinate transformation from the source level |
269
370
|`resampling_method`| string | no | Per-level override of the default resampling method |
270
-
|`spatial:shape`| integer[]|no| Shape of the spatial dimensions at this level `[height, width]`|
271
-
|`spatial:transform`| number[6]|no|Affine transform coefficients for this level, in Rasterio/Affine ordering `[a, b, c, d, e, f]`|
371
+
|`spatial:shape`| integer[2]|yes| Shape of the spatial dimensions at this level `[height, width]`|
372
+
|`spatial:transform`| number[6]|yes|Absolute affine transform coefficients for this level, in Rasterio/Affine ordering `[a, b, c, d, e, f]`|
272
373
273
374
#### TransformObject
274
375
@@ -496,8 +597,8 @@ Key aspects:
496
597
|`derived_from`| string | no | Relative path to the source level |
497
598
|`transform`| TransformObject | conditional | Required when `derived_from` is present |
498
599
|`resampling_method`| string | no | Per-level resampling override |
499
-
|`spatial:shape`| integer[]|no| Spatial dimensions shape `[height, width]` at this level |
500
-
|`spatial:transform`| number[6]|no| Absolute affine transform for this level (Rasterio/Affine ordering) |
600
+
|`spatial:shape`| integer[2]|yes| Spatial dimensions shape `[height, width]` at this level |
601
+
|`spatial:transform`| number[6]|yes| Absolute affine transform for this level (Rasterio/Affine ordering) |
**Impact:** This approach prevents chunk overlap issues with Dask while optimizing for actual data dimensions rather than arbitrary tile sizes, significantly improving performance.
**Problem:** The current draft does not define how a GeoZarr store is bounded as a set of paths. The base Zarr spec treats the `.zarr` suffix as advisory only, so two implementations can disagree on whether nested stores (e.g. `a.zarr/b/c.zarr/`) are allowed, how a client given a deep URL recovers the root, and where a traversal should stop.
56
+
57
+
**Our Solution:** We adopted an explicit set of rules in our [Store Root section](geozarr-minispec.md#hierarchy--identification): single root, root prefix ends with `.zarr`, the suffix occurs at most once in the hierarchy, and an enumerated list of terminal-path conditions.
58
+
59
+
**Impact:** Clients reading a sub-path like `https://example.org/foo.zarr/measurements/reflectance/r10m` can now reliably recover the store root and read its summary `spatial:bbox` + `proj:code`. This also resolves a recurring URL-parsing question raised in [EOPF-Explorer/data-model#124](https://github.com/EOPF-Explorer/data-model/issues/124) without needing fragment-based URL workarounds.
**Issue:**[EOPF-Explorer/data-model#156](https://github.com/EOPF-Explorer/data-model/issues/156) — to be surfaced upstream once [#132](https://github.com/zarr-developers/geozarr-spec/issues/132) lands.
64
+
65
+
**Problem:** Without a top-level summary footprint, clients have to walk into child groups to discover where a store sits geographically. That is expensive over network, and prevents STAC-style discovery patterns.
66
+
67
+
**Our Solution:** A mandatory `spatial:bbox` plus an explicit CRS (one of `proj:code`, `proj:wkt2`, or `proj:projjson`) at the store root, defined in the [Store Root section](geozarr-minispec.md#store-root). The CRS is always declared explicitly — there is no implicit default.
68
+
69
+
**Impact:** A single read of the root `zarr.json` is enough for catalogues and viewers to place a store on a map, without disturbing per-group `spatial:` attributes which remain authoritative for individual variables.
70
+
71
+
### 5. STAC-style `spatial:extent` (multi-bbox at root)
**Problem:** A single union `spatial:bbox` at the store root loses per-asset footprint information. Stores that mix several Datasets / Multiscale Datasets cannot expose individual extents without forcing clients to walk every child group.
76
+
77
+
**Our Solution (proposed):** Mirror STAC's `extent.spatial.bbox` by introducing `spatial:extent` as a list of bboxes — first entry is the global union, subsequent entries are per-child extents. Suggested by @vincentsarago during review of #4 above; deferred until the upstream `spatial:` convention adopts it.
78
+
79
+
**Impact:** Lets clients fetch all per-child footprints in one request, aligning Zarr discovery with STAC conventions.
0 commit comments