Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
60fddbc
add: create specifications for Projection Attribute Extension and its…
emmanuelmathot Sep 8, 2025
f09f67a
fix: update attribute naming from `proj` to `geo` in Projection Attri…
emmanuelmathot Sep 9, 2025
83a5f93
fix: remove `shape` field from Projection Attribute Extension schema …
emmanuelmathot Sep 9, 2025
77bae32
fix: rename `spatial_dims` to `spatial_dimensions` in README and sche…
emmanuelmathot Sep 9, 2025
caee06b
fix: enhance spatial dimension identification section in README with …
emmanuelmathot Sep 9, 2025
9daf0d3
fix: clarify inheritance model for `geo:proj` attribute in README
emmanuelmathot Sep 9, 2025
7e77fa1
fix: clarify spatial dimension identification section in README with …
emmanuelmathot Sep 9, 2025
01537ec
fix: add version field to geo:proj schema and update README for compa…
emmanuelmathot Sep 11, 2025
17a0700
fix: update geo:proj schema to include version field and restructure …
emmanuelmathot Sep 14, 2025
289f774
Update attributes/geo:proj/README.md
emmanuelmathot Sep 14, 2025
cd14f53
Update attributes/README.md
emmanuelmathot Sep 14, 2025
0932243
Update attributes/README.md
emmanuelmathot Sep 14, 2025
cd58d28
Update attributes/geo:proj/README.md
emmanuelmathot Sep 14, 2025
c317a4a
Update attributes/geo:proj/README.md
emmanuelmathot Sep 14, 2025
8a60696
Remove redundant examples for irregular grid and update WKT2 represen…
emmanuelmathot Sep 14, 2025
96b5db1
Refine spatial dimension identification section to focus on regular g…
emmanuelmathot Sep 14, 2025
e9e754e
Refactor inheritance model section for clarity and remove redundant r…
emmanuelmathot Sep 14, 2025
1893b7b
Update examples in geo:proj README.md to enhance clarity and provide …
emmanuelmathot Sep 14, 2025
a244d90
Clarify spatial dimension interpretation in geo:proj README.md to emp…
emmanuelmathot Sep 14, 2025
1cffe00
Clarify terminology and improve consistency in geo:proj README.md reg…
emmanuelmathot Sep 14, 2025
d903aa7
Remove the Registered Extensions section from attributes README.md to…
emmanuelmathot Sep 14, 2025
f4364e4
Update attributes/geo:proj/README.md
emmanuelmathot Sep 14, 2025
cc9f913
Enhance README.md and schema.json for geo:proj extension by adding de…
emmanuelmathot Sep 14, 2025
21b0d1c
Refine validation rules in geo:proj README.md to clarify shape infere…
emmanuelmathot Sep 14, 2025
1bde1bc
Update attributes/README.md
emmanuelmathot Sep 17, 2025
190ad60
Update versioning in geo:proj README.md and schema.json to 0.1.0
emmanuelmathot Sep 17, 2025
a4b2bef
Update attributes/geo:proj/README.md
emmanuelmathot Sep 17, 2025
544687d
Update attributes/geo:proj/README.md
emmanuelmathot Sep 17, 2025
4582d2a
Enhance README.md with projection authority examples and clarify CRS …
emmanuelmathot Sep 17, 2025
1c0134f
Remove redundant emphasis on spatial dimensions interpretation in geo…
emmanuelmathot Sep 17, 2025
ac841d8
Add algorithm for resolving spatial dimensions in group-level geo:proj
emmanuelmathot Sep 17, 2025
803f269
Clarify flexibility in spatial dimension ordering in geo:proj README.md
emmanuelmathot Sep 17, 2025
27a1123
Refactor Geo Projection Attribute Extension
emmanuelmathot Sep 21, 2025
eeb64ae
Update attributes/geo/proj/README.md
emmanuelmathot Sep 22, 2025
22b277d
Merge branch 'main' into proj-crs
emmanuelmathot Sep 28, 2025
c84a05e
Update README.md for Geo Projection Attribute Extension and remove sc…
emmanuelmathot Sep 28, 2025
5132326
Remove link to Attributes section in README.md
emmanuelmathot Sep 28, 2025
b13da42
Update attributes/geo/proj/README.md
emmanuelmathot Sep 29, 2025
f9ffc2f
Update attributes/geo/proj/README.md
emmanuelmathot Sep 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 57 additions & 47 deletions attributes/geo:proj/README.md → attributes/geo/proj/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Projection Attribute Extension for Zarr
# Geo Projection Attribute Extension for Zarr

- **Extension Name**: Projection Attribute Extension
- **Extension Name**: Geo Projection Attribute Extension
- **Version**: 0.1.0
- **Extension Type**: Attribute
- **Status**: Proposed
- **Owners**: @emmanuelmathot

## Description

This specification defines a JSON object that encodes datum and coordinate reference system (CRS) information for geospatial data. Additionally, this specification defines a convention for storing this object under the `"geo:proj"` key in the attributes of Zarr groups or arrays.
This specification defines a JSON object that encodes datum and coordinate reference system (CRS) information for geospatial data. Additionally, this specification defines a convention for storing this object under the `proj` key within the `geo` dictionary in the attributes of Zarr groups or arrays.

**Recommended usage**: Define `geo:proj` at the **group level** to apply CRS information to all arrays within that group. This matches the common geospatial pattern of storing multiple arrays with the same coordinates in a single group. Array-level definitions are supported for override cases but are less common.
**Recommended usage**: Define the `proj` key under the `geo` dictionary at the **group level** to apply CRS information to all arrays within that group. This matches the common geospatial pattern of storing multiple arrays with the same coordinates in a single group. Array-level definitions are supported for override cases but are less common.

## Motivation

Expand All @@ -20,22 +20,22 @@ This specification defines a JSON object that encodes datum and coordinate refer

## Inheritance Model

The `geo:proj` attribute follows a simple group-to-array inheritance model that should be understood first:
The `proj` key under the `geo` dictionary follows a simple group-to-array inheritance model that should be understood first:

### Inheritance Rules

1. **Group-level definition** (recommended): When `geo:proj` is defined at the group level, it applies to all arrays that are direct children of that group. It does not apply to groups or arrays deeper in the hierarchy (e.g., grandchildren).
2. **Array-level override**: An array can completely override the group's `geo:proj` attribute with its own definition
3. **Complete replacement only**: Partial inheritance (overriding only some fields while inheriting others) is not allowed
1. **Group-level definition** (recommended): When `proj` is defined under the `geo` dictionary at the group level, it applies to all arrays that are direct children of that group. It does not apply to groups or arrays deeper in the hierarchy (e.g., grandchildren).
2. **Array-level override**: An array can completely override the group's `proj` key with its own definition.
3. **Complete replacement only**: Partial inheritance (overriding only some fields while inheriting others) is not allowed.

Most use cases will use group-level definitions without array overrides.

## Specification

The `geo:proj` attribute can be added to Zarr arrays or groups to define projection information.
The `proj` key under the `geo` dictionary can be added to Zarr arrays or groups to define projection information.

<!-- GENERATED_SCHEMA_DOCS_START -->
**`geo:proj` Properties**
**`geo -> proj` Properties**

| |Type|Description|Required|
|---|---|---|---|
Expand All @@ -51,16 +51,15 @@ The `geo:proj` attribute can be added to Zarr arrays or groups to define project

Additional properties are allowed.

#### geo:proj.version
#### geo -> proj.version

Projection metadata version

* **Type**: `string`
* **Required**: &#10003; Yes
* **Allowed values**:
* `"0.1"`
* **Allowed values**: `0.1`

#### geo:proj.code
#### geo -> proj.code

Authority:code identifier (e.g., EPSG:4326)

Expand All @@ -80,13 +79,13 @@ clients are likely to support are listed in the following table.
| Open Geospatial Consortium (OGC) | <http://www.opengis.net/def/crs/OGC> |
| ESRI | <https://spatialreference.org/ref/esri/> |

The `geo:proj.code` field SHOULD be set to `null` in the following cases:
The `proj.code` field SHOULD be set to `null` in the following cases:

- The data does not have a CRS, such as in the case of non-rectified imagery with Ground Control Points.
- A CRS exists, but there is no valid EPSG code for it. In this case, the CRS should be provided in `geo:proj.wkt2` and/or `geo:proj.projjson`.
- A CRS exists, but there is no valid EPSG code for it. In this case, the CRS should be provided in `proj.wkt2` and/or `proj.projjson`.
Clients can prefer to take either, although there may be discrepancies in how each might be interpreted.

#### geo:proj.wkt2
#### geo -> proj.wkt2

WKT2 (ISO 19162) CRS representation

Expand All @@ -101,7 +100,7 @@ This field SHOULD be set to `null` in the following cases:
- The asset data does not have a CRS, such as in the case of non-rectified imagery with Ground Control Points.
- A CRS exists, but there is no valid WKT2 string for it.

#### geo:proj.projjson
#### geo -> proj.projjson

PROJJSON CRS representation

Expand All @@ -117,22 +116,22 @@ This field SHOULD be set to `null` in the following cases:
- The asset data does not have a CRS, such as in the case of non-rectified imagery with Ground Control Points.
- A CRS exists, but there is no valid PROJJSON for it.

#### geo:proj.bbox
#### geo -> proj.bbox

Bounding box in CRS coordinates

* **Type**: `number` `[]`
* **Required**: No

Bounding box of the assets represented by this Item in the asset data CRS. Specified as 4 coordinates
based on the CRS defined in the `proj:code`, `proj:projjson` or `proj:wkt2` fields. First two numbers are coordinates
based on the CRS defined in the `proj.code`, `proj.projjson` or `proj.wkt2` fields. First two numbers are coordinates
of the lower left corner, followed by coordinates of upper right corner, , e.g., \[west, south, east, north],
\[xmin, ymin, xmax, ymax], \[left, down, right, up], or \[west, south, lowest, east, north, highest].
The length of the array must be 2\*n where n is the number of dimensions. The array contains all axes of the southwesterly
most extent followed by all axes of the northeasterly most extent specified in Longitude/Latitude
based on [WGS 84](http://www.opengis.net/def/crs/OGC/1.3/CRS84).

#### geo:proj.transform
#### geo -> proj.transform

Affine transformation coefficients

Expand All @@ -155,8 +154,7 @@ To get it on the command line you can use the [Rasterio CLI](https://rasterio.re

If the transform is defined in Item Properties, it is used as the default transform for all assets that don't have an overriding transform.

Note that `GetGeoTransform` and `rasterio` use different formats for reporting transform information. Order expected in `geo:proj.transform` is the
same as reported by `rasterio`. When using GDAL method you need to re-order in the following way:
Note that `GetGeoTransform` and `rasterio` use different formats for reporting transform information. Order expected in `proj.transform` is the same as reported by `rasterio`. When using GDAL method you need to re-order in the following way:

```python
g = GetGeoTransform(...)
Expand All @@ -165,7 +163,7 @@ proj_transform = [g[1], g[2], g[0],
0, 0, 1]
```

#### geo:proj.spatial_dimensions
#### geo -> proj.spatial_dimensions

Names of spatial dimensions [y_name, x_name]

Expand All @@ -191,8 +189,10 @@ The extension identifies these array dimensions through:

```json
{
"geo:proj": {
"spatial_dimensions": ["latitude", "longitude"]
"geo": {
"proj": {
"spatial_dimensions": ["latitude", "longitude"]
}
}
}
```
Expand All @@ -208,9 +208,9 @@ If `spatial_dimensions` is not provided, implementations should scan `dimension_

The first matching pair determines the spatial dimensions.

#### Group-Level geo:proj with Array-Level dimension_names
#### Group-Level geo -> proj with Array-Level dimension_names

When `geo:proj` is defined at the group level but `spatial_dimensions` is not explicitly provided, implementations must handle the fact that `dimension_names` are defined at the individual array level in Zarr v3. The following algorithm defines how to resolve spatial dimensions:
When `proj` is defined under the `geo` dictionary at the group level but `spatial_dimensions` is not explicitly provided, implementations must handle the fact that `dimension_names` are defined at the individual array level in Zarr v3. The following algorithm defines how to resolve spatial dimensions:

**For Explicit Declaration (when `spatial_dimensions` is provided):**

Expand All @@ -233,9 +233,11 @@ When `geo:proj` is defined at the group level but `spatial_dimensions` is not ex
"zarr_format": 3,
"node_type": "group",
"attributes": {
"geo:proj": {
"code": "EPSG:4326",
"transform": [0.1, 0.0, -180.0, 0.0, -0.1, 90.0]
"geo": {
"proj": {
"code": "EPSG:4326",
"transform": [0.1, 0.0, -180.0, 0.0, -0.1, 90.0]
}
}
}
}
Expand Down Expand Up @@ -278,10 +280,12 @@ This approach avoids redundancy and ensures consistency by using each array's ow
"zarr_format": 3,
"node_type": "group",
"attributes": {
"geo:proj": {
"code": "EPSG:3857",
"transform": [156543.03392804097, 0.0, -20037508.342789244, 0.0, -156543.03392804097, 20037508.342789244],
"bbox": [-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244]
"geo": {
"proj": {
"code": "EPSG:3857",
"transform": [156543.03392804097, 0.0, -20037508.342789244, 0.0, -156543.03392804097, 20037508.342789244],
"bbox": [-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244]
}
}
}
}
Expand All @@ -295,11 +299,13 @@ This approach avoids redundancy and ensures consistency by using each array's ow
"shape": [4, 2048, 2048],
"dimension_names": ["band", "y", "x"],
"attributes": {
"geo:proj": {
"code": "EPSG:32633",
"spatial_dimensions": ["y", "x"],
"transform": [30.0, 0.0, 500000.0, 0.0, -30.0, 5000000.0],
"bbox": [500000.0, 4900000.0, 561440.0, 4961440.0]
"geo": {
"proj": {
"code": "EPSG:32633",
"spatial_dimensions": ["y", "x"],
"transform": [30.0, 0.0, 500000.0, 0.0, -30.0, 5000000.0],
"bbox": [500000.0, 4900000.0, 561440.0, 4961440.0]
}
}
}
}
Expand All @@ -313,10 +319,12 @@ This approach avoids redundancy and ensures consistency by using each array's ow
"shape": [1800, 3600],
"dimension_names": ["lat", "lon"],
"attributes": {
"geo:proj": {
"code": "EPSG:4326",
"transform": [0.1, 0.0, -180.0, 0.0, -0.1, 90.0],
"bbox": [-180.0, -90.0, 180.0, 90.0]
"geo": {
"proj": {
"code": "EPSG:4326",
"transform": [0.1, 0.0, -180.0, 0.0, -0.1, 90.0],
"bbox": [-180.0, -90.0, 180.0, 90.0]
}
}
}
}
Expand All @@ -330,9 +338,11 @@ This approach avoids redundancy and ensures consistency by using each array's ow
"shape": [1000, 1000],
"dimension_names": ["northing", "easting"],
"attributes": {
"geo:proj": {
"wkt2": "PROJCRS[\"WGS 84 / UTM zone 33N\",BASEGEOGCRS[\"WGS 84\",DATUM[\"World Geodetic System 1984\",ELLIPSOID[\"WGS 84\",6378137,298.257223563,LENGTHUNIT[\"metre\",1]]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433]]],CONVERSION[\"UTM zone 33N\",METHOD[\"Transverse Mercator\",ID[\"EPSG\",9807]],PARAMETER[\"Latitude of natural origin\",0,ANGLEUNIT[\"degree\",0.0174532925199433]],PARAMETER[\"Longitude of natural origin\",15,ANGLEUNIT[\"degree\",0.0174532925199433]],PARAMETER[\"Scale factor at natural origin\",0.9996,SCALEUNIT[\"unity\",1]],PARAMETER[\"False easting\",500000,LENGTHUNIT[\"metre\",1]],PARAMETER[\"False northing\",0,LENGTHUNIT[\"metre\",1]]],CS[Cartesian,2],AXIS[\"easting\",east,ORDER[1],LENGTHUNIT[\"metre\",1]],AXIS[\"northing\",north,ORDER[2],LENGTHUNIT[\"metre\",1]]]",
"transform": [30.0, 0.0, 500000.0, 0.0, -30.0, 5000000.0]
"geo": {
"proj": {
"wkt2": "PROJCRS[\"WGS 84 / UTM zone 33N\",BASEGEOGCRS[\"WGS 84\",DATUM[\"World Geodetic System 1984\",ELLIPSOID[\"WGS 84\",6378137,298.257223563,LENGTHUNIT[\"metre\",1]]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433]]],CONVERSION[\"UTM zone 33N\",METHOD[\"Transverse Mercator\",ID[\"EPSG\",9807]],PARAMETER[\"Latitude of natural origin\",0,ANGLEUNIT[\"degree\",0.0174532925199433]],PARAMETER[\"Longitude of natural origin\",15,ANGLEUNIT[\"degree\",0.0174532925199433]],PARAMETER[\"Scale factor at natural origin\",0.9996,SCALEUNIT[\"unity\",1]],PARAMETER[\"False easting\",500000,LENGTHUNIT[\"metre\",1]],PARAMETER[\"False northing\",0,LENGTHUNIT[\"metre\",1]]],CS[Cartesian,2],AXIS[\"easting\",east,ORDER[1],LENGTHUNIT[\"metre\",1]],AXIS[\"northing\",north,ORDER[2],LENGTHUNIT[\"metre\",1]]]",
"transform": [30.0, 0.0, 500000.0, 0.0, -30.0, 5000000.0]
}
}
}
}
Expand Down
Loading