Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5d2caef
upgrade to Jupyter book 2
jo-mueller Oct 20, 2025
ec8f66e
correctly mark examples
jo-mueller Oct 20, 2025
75913fe
bump mystmd dependency
jo-mueller Oct 20, 2025
992aac0
pin mystmd
jo-mueller Oct 20, 2025
278c97f
hashpin template
jo-mueller Oct 20, 2025
6a4fd87
remove legacy dependencies
jo-mueller Oct 20, 2025
d5b63af
Create README.md for OME-NGFF specification
jo-mueller Oct 21, 2025
066145d
remove legacy files
jo-mueller Oct 21, 2025
deb17ef
use auto-built footer for copyright
jo-mueller Oct 21, 2025
a55a8e3
Merge branch 'upgrade-to-jupyter-book-2' of https://github.com/jo-mue…
jo-mueller Oct 21, 2025
e320b22
Update `coordinateSystems` metadata
jo-mueller Oct 21, 2025
a542576
Updated `axes` metadata and moved under `coordinateSystems` header level
jo-mueller Oct 21, 2025
599cb2e
Update array coordinate systems metadata and merge existing examples
jo-mueller Oct 21, 2025
0c3cb9d
Update coordinate convention metadata
jo-mueller Oct 21, 2025
9f8bed0
Updated coordinate transformations metadata
jo-mueller Oct 21, 2025
5c2c39f
updated matrix transformations
jo-mueller Oct 21, 2025
46e7e1c
update transformation types
jo-mueller Oct 21, 2025
d74cd54
update transformation types metadata
jo-mueller Oct 21, 2025
3ff61cf
harmonize link syntax
jo-mueller Oct 21, 2025
004ddf4
removed deprecated statement about `byDimension` transform
jo-mueller Oct 21, 2025
98dae14
harmonized indendations and json style
jo-mueller Oct 21, 2025
144f837
fixed `byDimension` metadata
jo-mueller Oct 21, 2025
1c6038d
make examples collapsible
jo-mueller Oct 21, 2025
1297598
renamed example folder
jo-mueller Oct 21, 2025
80011bb
add orcid logo to editor info
jo-mueller Oct 21, 2025
dee0b98
fix reference
jo-mueller Oct 22, 2025
a75d512
change precedence
jo-mueller Oct 22, 2025
e52f1fb
added examples for transformations with discrete axes
jo-mueller Oct 22, 2025
2faa956
fix link to example
jo-mueller Oct 22, 2025
8fb8ac1
untrack autogenerated files
jo-mueller Oct 22, 2025
7ad14ba
update affine examples and fix variable ordering
jo-mueller Oct 22, 2025
ad495b6
Fixed scale examples
jo-mueller Oct 22, 2025
51c8809
removed example from additional details
jo-mueller Oct 22, 2025
5d99680
specify affines/rotations as 2D matrices in parameter table
jo-mueller Oct 22, 2025
938fbce
renamed coordinate transformations schema
jo-mueller Oct 22, 2025
776b164
Refactor rotation property to use `mtxFlatOrNested`
jo-mueller Oct 22, 2025
b1d8b28
Merge remote-tracking branch 'upstream/main' into RFC5
jo-mueller Oct 22, 2025
b3b7e24
Delete schemas.md
jo-mueller Oct 22, 2025
dce4659
remove `mtxFloatOrNested`
jo-mueller Oct 24, 2025
bb63455
"zarr array" instead of "binary data"
jo-mueller Oct 29, 2025
fc7fef0
WIP: Update rfc5 schemas (#1)
jo-mueller Nov 3, 2025
ecec30b
sync PR with latest RFC5 proposal (#2)
jo-mueller Nov 3, 2025
06309d4
fix links
jo-mueller Nov 5, 2025
f4fbb96
fix schema resolution
jo-mueller Nov 5, 2025
2ac4b93
split tests into separate files; add conformance test script
clbarnes Nov 18, 2025
e248081
Conformance testing docs
clbarnes Nov 18, 2025
d5a054d
Add $schema to strict schemas
clbarnes Nov 18, 2025
48387fc
Add jsonschema_dingus
clbarnes Nov 18, 2025
5ba1a7f
replaced `0.6dev2` by `0.6.dev2`
jo-mueller Dec 15, 2025
9c14f74
Merge branch 'splash-ngff_spec' into fix-version-parsing
jo-mueller Dec 15, 2025
8945fd1
Merge pull request #1 from jo-mueller/fix-version-parsing
clbarnes Dec 15, 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
74 changes: 73 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,78 @@ address issues of scalability and interoperability.

This repository contains the central [specification text](./ngff_spec/specification.md),
a comprehensive list of [metadata examples](./ngff_spec/examples)
as well as [json schemas](./ngff_spec/schemas) to validate written ome-zarr image data.
as well as [json schemas](./ngff_spec/schemas) to validate written ome-zarr image data.

The built documentation including contribution hints can be found **[here](https://ngff-spec.readthedocs.io/en/latest/specification.html)**.

## Conformance tests

Conformance can be tested at several levels.

1. Validating that individual fields of a zarr attributes object are valid.
2. Validating a single zarr attributes object (i.e. containing OME-Zarr metadata)

- Validates that correct data can be represented, and that internally inconsistent data can be caught
- Cannot validate references to other objects in the zarr hierarchy
- Cannot validate conformance to other zarr metadata e.g. array data type, dimensionality

3. Validating a metadata-only zarr hierarchy

- Can validate references to other objects and other zarr metadata
- Cannot validate values e.g. the invertibility of an affine matrix defined as a zarr array

4. Validating a zarr hierarchy with data

This repository contains

- JSON schemas which handle level 1
- a set of test zarr attributes JSON for level 2 ([`./tests/attributes`](./tests/attributes/))
- a set of metadata-only zarr hierarchies for level 3 ([`./tests/zarr`](./tests/zarr/))

as well as a tool for feeding these test cases into an external validator.

### Testing tool

See [`ome_zarr_conformance.py`](./ome_zarr_conformance.py).

Run it in either `attributes` or `zarr` mode, optionally with filters for test names or types.

Wrap your own OME-Zarr implementation in a
["dingus"](https://talk.commonmark.org/t/origin-of-the-usage-for-dingus/1226) CLI,
which takes as its last argument the path to either

- attributes mode: a JSON file representing zarr attributes (i.e. containing OME-Zarr metadata)
- zarr mode: a zarr hierarchy root on the file system (i.e. a directory containing `zarr.json`)

The dingus should print to STDOUT a JSON object with the keys:

- `"valid"`: boolean, whether this is valid
- optionally `"message"`: string, free text describing the success/ failure

Call the tool like

```sh
python3 ./ome_zarr_conformance.py attributes -- path/to/my/dingus -dingusArg +argValue 10
```

Each call to the dingus will then look like

```sh
>>> path/to/my/dingus -dingusArg +argValue 10 /home/you/ngff-spec/tests/attributes/spec/valid/custom_type_axes.json

{"valid": true}
```

`ome_zarr_conformance.py` will parse the JSON output and format the results of all requested tests in a tab-separated table.

Full usage information is available with `./ome_zarr_conformance.py --help`.

### JSON Schema tests

You can use the conformance testing tool to test JSON Schema-based validation with

```sh
>>> ./ome_zarr_conformance.py attributes -- uv run jsonschema_dingus.py attributes
```

Some failures are expected as JSON Schema can only handle level 1 validation.
96 changes: 96 additions & 0 deletions jsonschema_dingus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env python3
# /// script
# dependencies = [
# "jsonschema",
# "referencing",
# ]
# ///
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
import json
from argparse import ArgumentParser
from typing import Any, Self

from referencing import Registry, Resource
from jsonschema import Draft202012Validator as Validator
from jsonschema.exceptions import ValidationError

HERE = Path(__file__).resolve().parent
SCHEMA_DIR = HERE / "ngff_spec" / "schemas"


@dataclass
class SchemasInfo:
generic_id: str
base_url: str
registry: Registry

@classmethod
def load(cls) -> Self:
"""Get the ID of the top-level schema, and the mapping of schema IDs to objects"""
registry = Registry()
generic = None
base_url = None
for p in SCHEMA_DIR.glob("*.schema*"):
schema = json.loads(p.read_text())
resource = Resource.from_contents(schema)
registry = resource @ registry

schema_id = resource.id()
if schema_id is None:
raise RuntimeError("schema has no ID")
if p.stem == "ome_zarr":
generic = schema_id
base_url = generic.split("/schemas/")[0]

if generic is None or base_url is None:
raise RuntimeError("Could not find generic ome_zarr schema")

return cls(generic, base_url, registry)


def main(raw_args=None):
parser = ArgumentParser()
parser.add_argument("mode", choices=["attributes", "zarr"])
parser.add_argument("path", type=Path)

args = parser.parse_args(raw_args)

p: Path = args.path
attrs: None | dict[str, Any] = None
match args.mode:
case "attributes":
attrs = json.loads(p.read_text())
case "zarr":
attrs = json.loads(p.joinpath("zarr.json").read_text())["attributes"]
case _:
raise RuntimeError("unreachable")

if attrs is None:
raise RuntimeError("unreachable")

schemas = SchemasInfo.load()

generic_schema = schemas.registry.get(schemas.generic_id)
if generic_schema is None:
raise RuntimeError("could not find generic schema")

validator = Validator(
generic_schema.contents,
registry=schemas.registry,
)

result = dict()
try:
validator.validate(attrs)
result["valid"] = True
except ValidationError as e:
result["valid"] = False
result["message"] = str(e)

print(json.dumps(result))


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions ngff_spec/pre_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def build_json_examples():
def build_json_schemas():
from json_schema_for_humans.generate import generate_from_filename
from json_schema_for_humans.generation_configuration import GenerationConfiguration
import json

schema_source_dir = 'schemas'
output_directory = '_generated/schemas'
Expand Down
1 change: 1 addition & 0 deletions ngff_spec/schemas/strict_coordinate_systems.schema
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_coordinate_systems.schema",
"allOf" : [
{
Expand Down
1 change: 1 addition & 0 deletions ngff_spec/schemas/strict_image.schema
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_image.schema",
"allOf": [
{
Expand Down
1 change: 1 addition & 0 deletions ngff_spec/schemas/strict_label.schema
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_label.schema",
"allOf": [
{
Expand Down
24 changes: 24 additions & 0 deletions ngff_spec/schemas/strict_ome_zarr.schema
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_ome_zarr.schema",
"anyOf": [
{
"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/bf2raw.schema"
},
{
"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_image.schema"
},
{
"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_label.schema"
},
{
"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/ome.schema"
},
{
"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_plate.schema"
},
{
"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_well.schema"
}
]
}
1 change: 1 addition & 0 deletions ngff_spec/schemas/strict_plate.schema
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_plate.schema",
"allOf": [
{
Expand Down
1 change: 1 addition & 0 deletions ngff_spec/schemas/strict_well.schema
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_well.schema",
"allOf": [
{
Expand Down
Loading