Skip to content
Open
Show file tree
Hide file tree
Changes from 31 commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ It is the normative source for registering names of Zarr v3 extensions.

To register an extension, open a new PR with a new extension directory under the relevant extension point:

* [Attributes](./attributes/README.md)
* [Codecs](./codecs/README.md)
* [Data Types](./data-types/README.md)
* [Chunk Key Encoding](./chunk-key-encodings/README.md)
Expand Down
25 changes: 25 additions & 0 deletions attributes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Attributes Extensions

This directory contains specifications for Zarr v3 attribute extensions.

## What are Attribute Extensions?

Attribute extensions define standardized schemas and semantics for metadata stored in the attributes of Zarr arrays and groups. These extensions enable interoperability by establishing common conventions for domain-specific metadata.


## Creating an Attribute Extension

When creating an attribute extension, consider:

1. **Namespace**: Use a unique prefix to avoid conflicts (e.g., `proj` for projection). Choose namespace characters that are compatible with all operating systems by avoiding special characters like colons (:)
2. **Schema**: Provide a JSON schema for validation
3. **Inheritance**: Define behavior when attributes are set at group vs array level
4. **Compatibility**: Consider interoperability with existing tools and standards
5. **Example data**: Where possible, consider including a complete Zarr hierarchy that implements the extension.
## Extension Requirements

Each attribute extension MUST:
- Define the attribute key(s) and structure
- Provide a JSON schema for validation
- Include examples of usage
- Document any inheritance or precedence rules
347 changes: 347 additions & 0 deletions attributes/geo:proj/README.md

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If more than 1 of the 3 is provided, they have to be semantically identical (i.e. describe the same CRS).

Original file line number Diff line number Diff line change
@@ -0,0 +1,347 @@
# Projection Attribute Extension for Zarr

- **Extension Name**: 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.

**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.

## Motivation

- Provides simple, standardized CRS encoding without complex nested structures
- Compatible with existing geospatial tools (GDAL, rasterio, pyproj)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Compatible with existing geospatial tools (GDAL, rasterio, pyproj)
- Future cross-compatibility with existing geospatial tools (GDAL, rasterio, pyproj)

I think this better reflects the current status and goals

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We know the data model is compatible. We can a section about the tooling implementation status but I'd avoid putting assumptions in the motivation section.

- Based on the proven STAC Projection Extension model

## Inheritance Model

The `geo:proj` attribute 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use-case for array-level overrides?

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.

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

| |Type|Description|Required|
|---|---|---|---|
|**version**|`string`|Projection metadata version| &#10003; Yes|
|**code**|`["string", "null"]`|Authority:code identifier (e.g., EPSG:4326)|No|
|**wkt2**|`["string", "null"]`|WKT2 (ISO 19162) CRS representation|No|
|**projjson**|`any`|PROJJSON CRS representation|No|
|**bbox**|`number` `[]`|Bounding box in CRS coordinates|No|
|**transform**|`number` `[]`|Affine transformation coefficients|No|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
|**transform**|`number` `[]`|Affine transformation coefficients|No|
|**affine**|`number` `[]`|Affine transformation coefficients|No|

Could we use affine instead of transform since that's more specific and leaves an option for other transforms to be added?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively something like

"transform": {"name": "affine", "configuration": {...}}

so it is clear that only one transform is allowed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transform is the correct general mathematical term here. According to standard mathematical definitions, 'geometric transformation' is the broader concept, while 'affine transformation' is a specific subset. Using 'transform' maintains consistency with established geospatial standards (GDAL's GetGeoTransform, rasterio's Transform) and leaves room for potential future extensions to support other transformation types.
This follows the principle of "optimize for the common case" - use terminology that works for both the 80% majority and the 20% edge cases, rather than terminology that's precise for 80% but excludes future possibilities.

|**spatial_dimensions**|`string` `[2]`|Names of spatial dimensions [y_name, x_name]|No|

### Field Details

Additional properties are allowed.

#### geo:proj.version

Projection metadata version

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

#### geo:proj.code

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

* **Type**: `["string", "null"]`
* **Required**: No
* **Pattern**: `^[A-Z]+:[0-9]+$`

Projection codes are identified by a string. The [proj](https://proj.org/) library defines projections
using "authority:code", e.g., "EPSG:4326" or "IAU_2015:30100". Different projection authorities may define
different string formats. Examples of known projection authorities, where when can find well known codes that
clients are likely to support are listed in the following table.

| Authority Name | URL |
| --------------------------------------- | ---------------------------------------------------------- |
| European Petroleum Survey Groups (EPSG) | <http://www.opengis.net/def/crs/EPSG> or <http://epsg.org> |
| International Astronomical Union (IAU) | <http://www.opengis.net/def/crs/IAU> |
| 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 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`.
Clients can prefer to take either, although there may be discrepancies in how each might be interpreted.

#### geo:proj.wkt2

WKT2 (ISO 19162) CRS representation

* **Type**: `["string", "null"]`
* **Required**: No

A Coordinate Reference System (CRS) is the data reference system (sometimes called a 'projection')
used by the asset data. This value is a [WKT2](http://docs.opengeospatial.org/is/12-063r5/12-063r5.html) string.

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

PROJJSON CRS representation

* **Type**: `any`
* **Required**: No

A Coordinate Reference System (CRS) is the data reference system (sometimes called a 'projection')
used by the asset data. This value is a [PROJJSON](https://proj.org/specifications/projjson.html) object,
see the [JSON Schema](https://proj.org/schemas/v0.5/projjson.schema.json) for details.

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

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
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

Affine transformation coefficients

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

Linear mapping from pixel coordinate space (Pixel, Line) to projection coordinate space (Xp, Yp). It is
a `3x3` matrix stored as a flat array of 9 elements in row major order. Since the last row is always `0,0,1` it can be omitted,
in which case only 6 elements are recorded. This mapping can be obtained from
GDAL([`GetGeoTransform`](https://gdal.org/api/gdaldataset_cpp.html#_CPPv4N11GDALDataset15GetGeoTransformEPd), requires re-ordering)
or the Rasterio ([`Transform`](https://rasterio.readthedocs.io/en/stable/api/rasterio.io.html#rasterio.io.BufferedDatasetWriter.transform)).
To get it on the command line you can use the [Rasterio CLI](https://rasterio.readthedocs.io/en/latest/cli.html) with the
[info](https://rasterio.readthedocs.io/en/latest/cli.html#info) command: `$ rio info`.

```txt
[Xp] [a0, a1, a2] [Pixel]
[Yp] = [a3, a4, a5] * [Line ]
[1 ] [0 , 0, 1] [1 ]
```

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:

```python
g = GetGeoTransform(...)
proj_transform = [g[1], g[2], g[0],
g[4], g[5], g[3],
0, 0, 1]
```

#### geo:proj.spatial_dimensions

Names of spatial dimensions [y_name, x_name]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does order matter here? If so should it be enforced that all arrays within the group have this order if they have both y and x as dimensions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can have spatial dimaneisons with unconventiona names (e.g. azimuth_time, ground_range), It is better then to have the names with the Y,X order specified here.


* **Type**: `string` `[2]`
* **Required**: No

See the [Spatial Dimension Identification](#spatial-dimension-identification) section below for details on how spatial dimensions are identified.

<!-- GENERATED_SCHEMA_DOCS_END -->

Note: The shape of spatial dimensions is obtained directly from the Zarr array metadata once the spatial dimensions are identified.

### Spatial Dimension Identification

In this extension, "spatial dimensions" refers to the dimension names of 2D/3D arrays within this group to which the projection definition applies. This extension is designed for regular grids where dimensions directly correspond to spatial axes.

The extension identifies these array dimensions through:

1. **Explicit Declaration** (recommended): Use `spatial_dimensions` to specify dimension names
2. **Pattern-Based Detection** (fallback): Automatically detect spatial dimensions using patterns defined by this extension

#### Explicit Declaration

```json
{
"geo:proj": {
"spatial_dimensions": ["latitude", "longitude"]
}
}
```

#### Pattern-Based Detection

If `spatial_dimensions` is not provided, implementations should scan `dimension_names` for these patterns defined by this extension (in order):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dimension_names are specified at the array level whereas this proposal is primarily targeted at the group-level so you would need to scan all the arrays within a group. If you were to look through all the arrays in a group you would encounter some that are the coordinate arrays themselves. Does there maybe need to be a clause that when scanning if you encounter an array where its name matches dimension_names you should ignore it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coordinate arrays are excluded from this specification. the geo:proj attribute and its spatial dimension detection only applies to data arrays and their shapes (basic Zarr concepts). So when scanning dimension_names for spatial patterns, implementations would only examine data arrays and their shape within the group

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are coordinate arrays and data arrays differentiated in Zarr? My understanding was that all arrays are the same and it is the matching of dimension_names on one array with the name of another array that creates the coordinates in xarray.


- ["y", "x"] or ["Y", "X"]
- ["lat", "lon"] or ["latitude", "longitude"]
- ["northing", "easting"]
- ["row", "col"] or ["line", "sample"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be broadened a bit to allow any dimension_names that includes these patterns. That would catch cases where there is also time or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The geo:proj extension specifically scopes to only the spatial dimensions that the CRS applies to (typically 2D: y/x, lat/lon, etc.). Non-spatial dimensions like time, band, or depth are outside the scope of this extension. The pattern matching is designed to identify exactly the spatial dimension pair that corresponds to the CRS, not to handle additional dimensions in the array.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I just got your comments afterwards. This is not a static pattern that dimension_names must exactly match. The pattern matching rule is a set of possible name that must be found together in dimension_names to match a possible combination


The first matching pair determines the spatial dimensions.

#### 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:

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

1. Use the specified `spatial_dimensions` directly
2. Validate that each data array in the group contains these dimension names
3. If any data array lacks the specified spatial dimensions, ignore that array for the purpose of applying `geo:proj`
4. If no data arrays contain the specified spatial dimensions, implementations MUST raise an error

**For Pattern-Based Detection (when `spatial_dimensions` is not provided):**

1. Scan all data arrays within the group
2. For each data array, examine its `dimension_names` for the defined patterns
3. Use the first matching pattern found across all data arrays
4. If no spatial dimension patterns are found in any data array, implementations MUST raise an error

**Example of Valid Group-Level Configuration:**

```json
{
"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]
}
}
}
```

With data arrays:

- `temperature/`: `dimension_names: ["time", "lat", "lon"]` ✅ Contains ["lat", "lon"]
- `precipitation/`: `dimension_names: ["time", "lat", "lon"]` ✅ Same pattern

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding this section! I think it makes things clearer. My questions around ordering essentially boil down to: Would it pass if "lon" and "lat" were flipped?

- `temperature/`: `dimension_names: ["time", "lon", "lat"]`
- `precipitation/`: `dimension_names: ["time", "lon", "lat"]`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

- `lat/`: `dimension_names: ["lat"]` ⚠️ Excluded (coordinate array)
- `lon/`: `dimension_names: ["lon"]` ⚠️ Excluded (coordinate array)

### Validation Rules

- **Shape Inference**: Once spatial dimensions are identified (either explicitly through `spatial_dimensions` or through pattern-based detection), their sizes are obtained from the Zarr array's shape metadata
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain what validation needs to happen using the array shape?

- **Error Handling**: If spatial dimensions cannot be identified through either method, implementations MUST raise an error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **Error Handling**: If spatial dimensions cannot be identified through either method, implementations MUST raise an error
- **Error Handling**: If spatial dimensions cannot be identified through either method, implementations MUST raise an error

Can you be more specific here? "e.g., implementations MUST raise an error if using operations that rely on the "geo:proj" attribute"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also be useful to specify when implementations should raise the error. Ideally the error raises on lazy open (for instance xr.open_dataset).

- **Semantic Identity Requirement**: If more than one CRS representation (`code`, `wkt2`, `projjson`) is provided, they MUST be semantically identical (i.e., describe the same coordinate reference system). Implementations SHOULD validate this consistency and raise an error if the representations describe different CRS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation for allowing more than one? It adds work for implementations to validate the consistency, so if not needed it seems best to only allow one. I am concerned about what will happen if people ask to add lossy additional options, such as PROJ.4.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the crs_type is also interesting, I guess it would simplify implementations


### Shape Reconciliation

The shape of spatial dimensions is determined on a per-array basis:

1. Identifying the spatial dimensions using either `spatial_dimensions` or pattern-based detection (as described above)
2. For each data array that the `geo:proj` applies to, looking up the spatial dimension names in that array's `dimension_names`
3. Using the corresponding sizes from that same array's `shape` attribute

This approach avoids redundancy and ensures consistency by using each array's own metadata rather than duplicating shape information.

## Examples

### Example 1: Simple Web Mercator Raster (Group Level)

```json
{
"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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One point of confusion for me in STAC is whether the bbox refers to the outer bounds of the cells or the coordinate values for raster data? From this, it looks like it's the coordinate values which will always be narrower than the outer bounds of the cells for raster data. Should we specify that in this document?

}
}
}
```

### Example 2: Multi-band Satellite Image

```json
{
"zarr_format": 3,
"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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should transform and bbox be given a type as part of this document (e.g., double precision float)?

}
}
}
```

### Example 3: Geographic Coordinates with Transform

```json
{
"zarr_format": 3,
"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]
}
}
}
```

### Example 4: WKT2 Representation

```json
{
"zarr_format": 3,
"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]
}
}
}
```

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these examples are for arrays even though it is recommended that this be defined at the group level. Are we sure we want to allow inheritance from the group level?

I very much like @benbovy's suggestion (#21 (comment)) that the "geo:proj" blobs be defined at that group level with an id and then the arrays reference a specific id

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still a bit confused with the "dimension array" term you often use. Are they coordinates? In that case, this is out of scope. We want to keep the spec on top of the base Zarr concepts (arrays and shapes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsignell I think I finally understood your point here and I updated the readme to better describe how the spec should interpret at array-level.


## Compatibility Notes

- The `version` field allows tracking of changes and ensures compatibility with future updates
- The `code` field follows the "authority:code" format used by PROJ library
- The `wkt2` field should conform to OGC WKT2 (ISO 19162) standard
- The `transform` field follows the same ordering as GDAL's GeoTransform and STAC's projection extension

## References

- [STAC Projection Extension v2.0.0](https://github.com/stac-extensions/projection)
- [PROJJSON Specification](https://proj.org/specifications/projjson.html)
- [OGC WKT2 Standard](https://www.ogc.org/standards/wkt-crs)
Loading