From 5d2caefef9456e2594e4bce887580062c6e028b0 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 20 Oct 2025 17:39:37 +0200
Subject: [PATCH 01/47] upgrade to Jupyter book 2
---
.readthedocs.yaml | 25 +++----
_toc.yml | 17 -----
_config.yml => ngff_spec/._config.yml.bak | 0
ngff_spec/._toc.yml.bak | 17 +++++
ngff_spec/contribute.md | 10 +--
ngff_spec/examples.md | 60 +++++++++++++++-
ngff_spec/footer.md | 6 ++
ngff_spec/myst.yml | 32 +++++++++
pre_build.py => ngff_spec/pre_build.py | 49 ++++++++-----
references.bib => ngff_spec/references.bib | 0
ngff_spec/schemas.md | 20 +++---
ngff_spec/specification.md | 82 +++++++++-------------
pyproject.toml | 33 +++++++++
requirements.txt | 11 ---
14 files changed, 242 insertions(+), 120 deletions(-)
delete mode 100644 _toc.yml
rename _config.yml => ngff_spec/._config.yml.bak (100%)
create mode 100644 ngff_spec/._toc.yml.bak
create mode 100644 ngff_spec/footer.md
create mode 100644 ngff_spec/myst.yml
rename pre_build.py => ngff_spec/pre_build.py (78%)
rename references.bib => ngff_spec/references.bib (100%)
create mode 100644 pyproject.toml
delete mode 100644 requirements.txt
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index cc67767f..5ccf6dd5 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -1,19 +1,20 @@
version: 2
-
build:
os: ubuntu-22.04
tools:
- python: "3.13"
+ python: "3.12"
+ nodejs: "22"
jobs:
+ post_install:
+ - pip install uv
+ - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --link-mode=copy
+
pre_build:
- # Generate the Sphinx configuration for this Jupyter Book so it builds.
- - "jupyter-book config sphinx ."
- - "python ./docs/pre_build.py"
-
-python:
- install:
- - requirements: docs/requirements.txt
-
+ # Run the script that autogenerates content before building the docs
+ - "uv run python ngff_spec/pre_build.py"
-sphinx:
- configuration: conf.py
\ No newline at end of file
+ build:
+ html:
+ - cd ngff_spec/ && jupyter book build --html --ci
+ - mkdir -p $READTHEDOCS_OUTPUT
+ - mv ./ngff_spec/_build/html $READTHEDOCS_OUTPUT
diff --git a/_toc.yml b/_toc.yml
deleted file mode 100644
index 5fd9bc4b..00000000
--- a/_toc.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# Table of contents
-# Learn more at https://jupyterbook.org/customize/toc.html
-
-format: jb-book
-root: ngff_spec/specification
-
-chapters:
-- file: ngff_spec/examples
- sections:
- - glob: ngff_spec/_generated/examples/*
-- file: ngff_spec/schemas
- sections:
- - glob: ngff_spec/_generated/schemas/markdown/*
-
-- file: ngff_spec/contribute
-- file: ngff_spec/citing
-- file: ngff_spec/version_history
\ No newline at end of file
diff --git a/_config.yml b/ngff_spec/._config.yml.bak
similarity index 100%
rename from _config.yml
rename to ngff_spec/._config.yml.bak
diff --git a/ngff_spec/._toc.yml.bak b/ngff_spec/._toc.yml.bak
new file mode 100644
index 00000000..765b91a1
--- /dev/null
+++ b/ngff_spec/._toc.yml.bak
@@ -0,0 +1,17 @@
+# Table of contents
+# Learn more at https://jupyterbook.org/customize/toc.html
+
+format: jb-book
+root: specification
+
+chapters:
+- file: examples
+ sections:
+ - glob: _generated/examples/*
+- file: schemas
+ sections:
+ - glob: _generated/schemas/markdown/*
+
+- file: contribute
+- file: citing
+- file: version_history
\ No newline at end of file
diff --git a/ngff_spec/contribute.md b/ngff_spec/contribute.md
index 52c70522..7caa418e 100644
--- a/ngff_spec/contribute.md
+++ b/ngff_spec/contribute.md
@@ -13,7 +13,7 @@ Build and inspect changes to the documentation before submitting a PR.
To do so, you first need to install the necessary dependecies:
```bash
-pip install -r requirements.txt
+pip install .
```
This document uses [jupyter-book](https://jupyterbook.org) to generate the pages
@@ -22,8 +22,8 @@ After installing these via the dependencies,
navigate into the repository on your machine and build the book using the following command:
```bash
-python pre_build.py
-jupyter-book build .
+python ngff_spec/pre_build.py
+jupyter book build ngff_spec
```
You'll find the built webpages under `_build/html`.
@@ -48,7 +48,7 @@ It is recommended to use the following syntax in this document for consitency:
```
anchor: (your-reference-name)=
-reference: [This is a reference](your-reference-name)
+reference: [This is a reference](#your-reference-name)
```
#### Admonitions
@@ -85,6 +85,8 @@ use this syntax:
Some informative text about your example
```{literalinclude} path/to/example.json
:language: json
+:linenos:
+:tab-width: 2
```
````
`````
diff --git a/ngff_spec/examples.md b/ngff_spec/examples.md
index d7c1c369..4f25ecbd 100644
--- a/ngff_spec/examples.md
+++ b/ngff_spec/examples.md
@@ -1,3 +1,59 @@
-# JSON Examples
+---
+title: NGFF metadata JSON Examples
+short_title: JSON Examples
+---
-This document contains JSON examples for ngff-compliant metadata layouts.
\ No newline at end of file
+This section contains JSON examples for various metadata layouts.
+
+## bf2raw
+- [image](#examples:bf2raw:image)
+- [plate](#examples:bf2raw:plate)
+
+## coordSystems
+- [arrayCoordSys](#examples:coordSystems:arrayCoordSys)
+
+## label_strict
+- [colors_properties](#examples:label_strict:colors_properties)
+
+## multiscales_strict
+- [multiscales_example](#examples:multiscales_strict:multiscales_example)
+- [multiscales_example_relative](#examples:multiscales_strict:multiscales_example_relative)
+- [multiscales_transformations](#examples:multiscales_strict:multiscales_transformations)
+
+## ome
+- [series-2](#examples:ome:series-2)
+
+## plate_strict
+- [plate_2wells](#examples:plate_strict:plate_2wells)
+- [plate_6wells](#examples:plate_strict:plate_6wells)
+
+## subspace
+- [subspaceMultidim](#examples:subspace:subspaceMultidim)
+- [subspacePermute](#examples:subspace:subspacePermute)
+
+## transformations
+- [affine2d2d](#examples:transformations:affine2d2d)
+- [affine2d3d](#examples:transformations:affine2d3d)
+- [bijection](#examples:transformations:bijection)
+- [bijection_verbose](#examples:transformations:bijection_verbose)
+- [byDimension1](#examples:transformations:byDimension1)
+- [byDimension2](#examples:transformations:byDimension2)
+- [byDimensionInvalid1](#examples:transformations:byDimensionInvalid1)
+- [byDimensionInvalid2](#examples:transformations:byDimensionInvalid2)
+- [byDimensionXarray](#examples:transformations:byDimensionXarray)
+- [coordinates1d](#examples:transformations:coordinates1d)
+- [displacement1d](#examples:transformations:displacement1d)
+- [identity](#examples:transformations:identity)
+- [inverseOf](#examples:transformations:inverseOf)
+- [mapAxis1](#examples:transformations:mapAxis1)
+- [mapAxis2](#examples:transformations:mapAxis2)
+- [rotation](#examples:transformations:rotation)
+- [scale](#examples:transformations:scale)
+- [sequence](#examples:transformations:sequence)
+- [sequenceSubspace1](#examples:transformations:sequenceSubspace1)
+- [translation](#examples:transformations:translation)
+- [xarrayLike](#examples:transformations:xarrayLike)
+
+## well_strict
+- [well_2fields](#examples:well_strict:well_2fields)
+- [well_4fields](#examples:well_strict:well_4fields)
diff --git a/ngff_spec/footer.md b/ngff_spec/footer.md
new file mode 100644
index 00000000..132338a7
--- /dev/null
+++ b/ngff_spec/footer.md
@@ -0,0 +1,6 @@
+
+ Copyright © 2020-{{ year }}
+
OME®
+ (
U. Dundee).
+ OME trademark rules apply.
+
\ No newline at end of file
diff --git a/ngff_spec/myst.yml b/ngff_spec/myst.yml
new file mode 100644
index 00000000..0b02aa47
--- /dev/null
+++ b/ngff_spec/myst.yml
@@ -0,0 +1,32 @@
+version: 1
+project:
+ title: Next-generation file format specification
+ authors:
+ - name: NGFF-community
+ github: ome/ngff-spec
+ bibliography:
+ - references.bib
+ exports:
+ - format: pdf
+ template: plain_latex_book
+ output: exports/book.pdf
+ toc:
+ - file: specification.md
+ - file: examples.md
+ children:
+ - pattern: _generated/examples/*
+ - file: schemas.md
+ children:
+ - pattern: _generated/schemas/markdown/*
+ - file: contribute.md
+ - file: citing.md
+ - file: version_history.md
+site:
+ options:
+ logo: https://www.openmicroscopy.org/img/logos/ome-logomark.svg
+ folders: true
+ hide_myst_branding: true
+ parts:
+ footer: footer.md
+
+ template: book-theme
diff --git a/pre_build.py b/ngff_spec/pre_build.py
similarity index 78%
rename from pre_build.py
rename to ngff_spec/pre_build.py
index 41bf22a8..3db43173 100644
--- a/pre_build.py
+++ b/ngff_spec/pre_build.py
@@ -11,15 +11,25 @@
def build_json_examples():
"""Build markdown files from json examples."""
# glob recursively to find all json files
- input_directory = 'ngff_spec/examples'
- output_directory = 'ngff_spec/generated/examples'
+ input_directory = 'examples'
+ output_directory = '_generated/examples'
os.makedirs(output_directory, exist_ok=True)
example_types = os.listdir(input_directory)
+ index_md = """---
+title: NGFF metadata JSON Examples
+short_title: JSON Examples
+---
+
+This section contains JSON examples for various metadata layouts.
+"""
+
for example in example_types:
json_files = glob.glob(os.path.join(input_directory, example, '*.json'), recursive=True)
markdown_file_name = os.path.join(output_directory, f'{example}.md')
+ index_md += f"\n## {example}\n"
+
# add header
markdown_content = f"""# {example}\n\n
@@ -27,43 +37,48 @@ def build_json_examples():
"""
+
# append each json file content
for json_file in json_files:
print(f'Processing {json_file}...')
- with open(json_file, 'r') as file:
- json_data = json.load(file)
- json_str = json.dumps(json_data, indent=4)
+
+ crossref = f"examples:{example}:{Path(json_file).stem}"
+ index_md += f"- [{Path(json_file).stem}](#{crossref})\n"
+
json_file_name = Path(json_file).stem
# Create the Markdown content
markdown_content += f"""
## {os.path.splitext(json_file_name)[0]}
-(examples:{example}:{Path(json_file).stem})=
+({crossref})=
-```{{code-block}} json
-:caption: {json_file_name}
+```{{literalinclude}} {os.path.abspath(json_file)}
:linenos:
+:tab-width: 2
+:language: json
-{json_str}
```
"""
# create
with open(markdown_file_name, 'w') as md_file:
md_file.write(markdown_content)
+ with open(os.path.join("examples.md"), 'w') as index_file:
+ index_file.write(index_md)
+
def build_json_schemas():
from json_schema_for_humans.generate import generate_from_filename
from json_schema_for_humans.generation_configuration import GenerationConfiguration
- schema_source_dir = 'ngff_spec/schemas'
- output_directory = 'ngff_spec/generated/schemas'
+ schema_source_dir = 'schemas'
+ output_directory = '_generated/schemas'
os.makedirs(output_directory, exist_ok=True)
schema_files = glob.glob(os.path.join(schema_source_dir, '*.schema'), recursive=True)
index_markdown = """# JSON Schemas
This section contains JSON schemas for various metadata layouts.
-Find below links to autogenerated markdown pages or interactive HTML pages for each schema.
+Find below links to auto_generated markdown pages or interactive HTML pages for each schema.
| Schema | Markdown | HTML |
|--------|----------|------|
@@ -95,12 +110,12 @@ def build_json_schemas():
# insert mySt crossreference at top of markdown files
with open(output_path_md, 'r') as md_file:
md_content = md_file.read()
- crossref = f"(schemas:{Path(schema_file).stem})"
- md_content = f"{crossref}\n\n{md_content}"
+ crossref = f"schemas:{Path(schema_file).stem}"
+ md_content = f"({crossref})=\n\n{md_content}"
with open(output_path_md, 'w') as md_file:
md_file.write(md_content)
-
- link_markdown = f"[{Path(schema_file).stem}]{crossref}"
+
+ link_markdown = f"[{Path(schema_file).stem}](#{crossref})"
except Exception:
link_markdown = ""
@@ -123,7 +138,7 @@ def build_json_schemas():
index_markdown += f"| {Path(schema_file).stem} | {link_markdown} | {link_html} |\n"
- with open(os.path.join("ngff_spec/schemas.md"), 'w') as index_file:
+ with open(os.path.join("schemas.md"), 'w') as index_file:
index_file.write(index_markdown)
build_json_examples()
diff --git a/references.bib b/ngff_spec/references.bib
similarity index 100%
rename from references.bib
rename to ngff_spec/references.bib
diff --git a/ngff_spec/schemas.md b/ngff_spec/schemas.md
index 7a402be0..da86063d 100644
--- a/ngff_spec/schemas.md
+++ b/ngff_spec/schemas.md
@@ -1,19 +1,19 @@
# JSON Schemas
This section contains JSON schemas for various metadata layouts.
-Find below links to autogenerated markdown pages or interactive HTML pages for each schema.
+Find below links to auto_generated markdown pages or interactive HTML pages for each schema.
| Schema | Markdown | HTML |
|--------|----------|------|
-| axes | [axes](schemas:axes) | [axes](ngff_spec/generated/schemas\html\axes.html) |
-| bf2raw | | [bf2raw](ngff_spec/generated/schemas\html\bf2raw.html) |
-| coordinate_systems | [coordinate_systems](schemas:coordinate_systems) | [coordinate_systems](ngff_spec/generated/schemas\html\coordinate_systems.html) |
+| axes | [axes](#schemas:axes) | [axes](_generated/schemas\html\axes.html) |
+| bf2raw | | [bf2raw](_generated/schemas\html\bf2raw.html) |
+| coordinate_systems | [coordinate_systems](#schemas:coordinate_systems) | [coordinate_systems](_generated/schemas\html\coordinate_systems.html) |
| coordinate_systems_and_transforms | | |
| coordinate_transformation | | |
| image | | |
-| label | | [label](ngff_spec/generated/schemas\html\label.html) |
-| ome | | [ome](ngff_spec/generated/schemas\html\ome.html) |
-| ome_zarr | | [ome_zarr](ngff_spec/generated/schemas\html\ome_zarr.html) |
-| plate | | [plate](ngff_spec/generated/schemas\html\plate.html) |
-| well | | [well](ngff_spec/generated/schemas\html\well.html) |
-| _version | [_version](schemas:_version) | [_version](ngff_spec/generated/schemas\html\_version.html) |
+| label | | [label](_generated/schemas\html\label.html) |
+| ome | | [ome](_generated/schemas\html\ome.html) |
+| ome_zarr | | [ome_zarr](_generated/schemas\html\ome_zarr.html) |
+| plate | | [plate](_generated/schemas\html\plate.html) |
+| well | | [well](_generated/schemas\html\well.html) |
+| _version | [_version](#schemas:_version) | [_version](_generated/schemas\html\_version.html) |
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index d4140c9e..140f4678 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -1,13 +1,12 @@
-# {{ title }}
+---
+title: Next-generation file format specification
+short_title: OME-Zarr
+---
-**Version**: {{version}}
-**Shortname:** {{ shortname }}
-**Level:** {{ level }}
-**Status:** {{ status }}
-**Feedback:** {{ issue_tracking }}
+**Feedback:** [Forum](https://forum.image.sc/tag/ome-ngff), [Github](https://github.com/ome/ngff/issues)
-**Editor:** {{ editor_name }}, ({{ editor_affiliation }}), {{ editor_orcid }}
+**Editor:** Josh Moore, ([German BioImaging e.V.](https://gerbi-gmb.de)), [https://orcid.org/0000-0003-4028-811X](https://orcid.org/0000-0003-4028-811X)
## Abstract
@@ -59,7 +58,7 @@ but could equally be stored on a web server to be accessed via HTTP or in object
## Images
The following layout describes the expected Zarr hierarchy for images with multiple levels of resolutions and optionally associated labels.
-Note that the number of dimensions is variable between 2 and 5 and that axis names are arbitrary, see [multiscales metadata](multiscales-md) for details.
+Note that the number of dimensions is variable between 2 and 5 and that axis names are arbitrary, see [multiscales metadata](#multiscales-md) for details.
```text
├── 123.zarr # One OME-Zarr image (id=123).
@@ -105,11 +104,11 @@ Note that the number of dimensions is variable between 2 and 5 and that axis nam
The following specification defines the hierarchy for a high-content screening
dataset. Three groups MUST be defined above the images:
-- the group above the images defines the well and MUST implement the [well specification](well-md).
+- the group above the images defines the well and MUST implement the [well specification](#well-md).
All images contained in a well are fields of view of the same well
- the group above the well defines a row of wells
- the group above the well row defines an entire plate i.e. a two-dimensional collection of wells organized in rows and columns.
- It MUST implement the [plate specification](plate-md)
+ It MUST implement the [plate specification](#plate-md)
A well row group SHOULD NOT be present if there are no images in the well row.
A well group SHOULD NOT be present if there are no images in the well.
@@ -163,7 +162,7 @@ The OME-Zarr Metadata version MUST be consistent within a hierarchy.
(axes-md)=
"axes" describes the dimensions of a coordinate systems and adds an interpretation to the data along that dimension.
-A named collection of axes forms a [coordinate system](coord-sys-md).
+A named collection of axes forms a [coordinate system](#coord-sys-md).
It is a list of dictionaries, where each dictionary describes a dimension (axis) and:
- MUST contain the field "name" that gives the name for this dimension.
@@ -180,7 +179,7 @@ It is a list of dictionaries, where each dictionary describes a dimension (axis)
- MAY contain the field "longName".
The value MUST be a string, and can provide a longer name or description of an axis and its properties.
-The "axes" are used as part of [multiscales metadata](multiscales-md).
+The "axes" are used as part of [multiscales metadata](#multiscales-md).
The length of "axes" MUST be equal to the number of dimensions of the arrays that contain the image data.
The "dimension_names" attribute MUST be included in the `zarr.json` of the Zarr array of a multiscale level and MUST match the names in the "axes" metadata.
@@ -290,7 +289,7 @@ a measurement by instrument 1 at the point with coordinates (x,y,z) may not corr
(i.e., it may not be the same physical location in the sample).
To analyze both images together, they must be in the same coordinate system.
-The set of [coordinate transformations](trafo-md) encodes relationships between coordinate systems, specifically, how to
+The set of [coordinate transformations](#trafo-md) encodes relationships between coordinate systems, specifically, how to
convert points and images to different coordinate systems.
Implementations can apply the coordinate transform to images or points in coordinate system "sampleA_instrument2" to bring them into the "sampleA_instrument1" coordinate system.
In this case, the ROI should be transformed to the "sampleA_image1" coordinate system,
@@ -448,7 +447,7 @@ The OME-Zarr Metadata in the top-level `zarr.json` file must contain the `biofor
```
If the top-level group represents a plate, the `bioformats2raw.layout` metadata will be present
-but the "plate" key MUST also be present, takes precedence and parsing of such datasets should follow (see [plate metadata](plate-md)).
+but the "plate" key MUST also be present, takes precedence and parsing of such datasets should follow (see [plate metadata](#plate-md)).
It is not possible to mix collections of images with plates at present.
```{literalinclude} examples/bf2raw/plate.json
@@ -561,7 +560,7 @@ Conforming readers:
- SHOULD be able to apply transformations to points;
- SHOULD be able to apply transformations to images;
-Coordinate transformations from array to physical coordinates MUST be stored in [multiscales](multiscales-md).
+Coordinate transformations from array to physical coordinates MUST be stored in [multiscales](#multiscales-md).
Transformations between different images MUST be stored in the attributes of a parent zarr group.
For transformations that store data or parameters in a zarr array, those zarr arrays SHOULD be stored in a zarr group `"coordinateTransformations"`.
@@ -684,15 +683,14 @@ Inverse transformations used for image rendering may be specified using the `inv
```
Implementations SHOULD be able to compute and apply the inverse of some coordinate transformations when they are computable in closed-form
-(as the [Transformation types](transformation-types) section below indicates).
+(as the [Transformation types](#trafo-types-md) section below indicates).
If an operation is requested that requires the inverse of a transformation that can not be inverted in closed-form,
implementations MAY estimate an inverse, or MAY output a warning that the requested operation is unsupported.
#### Matrix transformations
+(matrix-trafo-md)=
-(matrix-transformations)=
-
-Two transformation types ([affine](affine) and [rotation](rotation)) are parametrized by matrices.
+Two transformation types ([affine](#affine-md) and [rotation](#rotation-md)) are parametrized by matrices.
Matrices are applied to column vectors that represent points in the input coordinate system.
The first (last) axis in a coordinate system is the top (bottom) entry in the column vector.
Matrices are stored as two-dimensional arrays, either as json or in a zarr array.
@@ -736,8 +734,7 @@ because it is computed with the matrix-vector multiplication:
````
### Transformation types
-
-(transformation-types)=
+(trafo-types-md)=
Input and output dimensionality may be determined by the value of the "input" and "output" fields, respectively.
If the value of "input" is an array, its shape gives the input dimension,
@@ -746,8 +743,7 @@ If the value of "output" is an array, its shape gives the output dimension,
otherwise it is given by the length of "axes" for the coordinate system with the name of the "output".
#### identity
-
-(identity)=
+(identity-md)=
`identity` transformations map input coordinates to output coordinates without modification.
The position of the ith axis of the output coordinate system is set to the position of the ith axis of the input coordinate system.
@@ -769,8 +765,7 @@ y = j
````
#### mapAxis
-
-(mapAxis)=
+(mapAxis-md)=
`mapAxis` transformations describe axis permutations as a mapping of axis names.
Transformations MUST include a `mapAxis` field whose value is an object, all of whose values are strings.
@@ -823,8 +818,7 @@ z = b
````
#### translation
-
-(translation)=
+(translation-md)=
`translation` transformations are special cases of affine transformations.
When possible, a translation transformation should be preferred to its equivalent affine.
@@ -854,8 +848,7 @@ y = j - 1.42
````
#### scale
-
-(scale)=
+(scale-md)=
`scale` transformations are special cases of affine transformations.
When possible, a scale transformation SHOULD be preferred to its equivalent affine.
@@ -885,10 +878,9 @@ y = 2 * j
````
#### affine
+(affine-md)=
-(affine)=
-
-`affine`s are [matrix transformations](matrix-transformations) from N-dimensional inputs to M-dimensional outputs
+`affine`s are [matrix transformations](#matrix) from N-dimensional inputs to M-dimensional outputs
are represented as the upper `(M)x(N+1)` sub-matrix of a `(M+1)x(N+1)` matrix in
[homogeneous coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates) (see examples).
This transformation type may be (but is not necessarily) invertible when `N` equals `M`.
@@ -960,10 +952,9 @@ where the last row `[0 0 1]` is omitted in the JSON representation.
````
#### rotation
+(rotation-md)=
-(rotation)=
-
-`rotation`s are [matrix transformations](matrix-transformations) that are special cases of affine transformations.
+`rotation`s are [matrix transformations](#matrix-trafo-md) that are special cases of affine transformations.
When possible, a rotation transformation SHOULD be preferred to its equivalent affine.
Input and output dimensionality (N) MUST be identical.
Rotations are stored as `NxN` matrices, see below, and MUST have determinant equal to one, with orthonormal rows and columns.
@@ -994,8 +985,7 @@ y = 1*i + 0*j
````
#### inverseOf
-
-(inverseOf)=
+(inverseOf-md)=
An `inverseOf` transformation contains another transformation (often non-linear),
and indicates that transforming points from output to input coordinate systems is possible using the contained transformation.
@@ -1017,8 +1007,7 @@ a choice that many users and developers find intuitive.
````
#### sequence
-
-(sequence)=
+(sequence-md)=
A `sequence` transformation consists of an ordered array of coordinate transformations,
and is invertible if every coordinate transform in the array is invertible
@@ -1081,8 +1070,7 @@ and is invertible.
````
#### coordinates and displacements
-
-(coordinates-displacements)=
+(coordinates-displacements-md)=
`coordinates` and `displacements` transformations store coordinates or displacements in an array
and interpret them as a vector field that defines a transformation.
@@ -1277,7 +1265,7 @@ That value gives us the displacement of the input point,
hence the output is `1.0 + (-0.5) = 0.5`.
#### byDimension
-(byDimension)=
+(byDimension-md)=
`byDimension` transformations build a high dimensional transformation using lower dimensional transformations on subsets of dimensions.
@@ -1337,7 +1325,7 @@ This transformation is invalid because the output axis `x` appears in more than
#### bijection
-(bijection)=
+(bijection-md)=
A bijection transformation is an invertible transformation
in which both the `forward` and `inverse` transformations are explicitly defined.
@@ -1378,7 +1366,7 @@ It is stored in a multiple resolution representation.
"multiscales" contains a list of dictionaries where each entry describes a multiscale image.
-Each "multiscales" dictionary MUST contain the field "coordinateSystems", see [coordinateSystems metadata](coord-sys-md), with the following constraints.
+Each "multiscales" dictionary MUST contain the field "coordinateSystems", see [coordinateSystems metadata](#), with the following constraints.
The length of "axes" must be between 2 and 5 and MUST be equal to the dimensionality of the zarr arrays storing the image data (see "datasets:path").
The "axes" MUST contain 2 or 3 entries of "type:space" and MAY contain one additional entry of "type:time" and MAY contain one additional entry of "type:channel" or a null / custom type.
The order of the entries MUST correspond to the order of dimensions of the zarr arrays.
@@ -1396,7 +1384,7 @@ The number of dimensions and order MUST correspond to number and order of "axes"
Each dictionary in "datasets" MUST contain the field "coordinateTransformations",
which contains a list of transformations that map the data coordinates to the physical coordinates
(as specified by "axes") for this resolution level.
-The transformations are defined according to [coordinateTransformations metadata](trafo-md).
+The transformations are defined according to [coordinateTransformations metadata](#trafo-md).
They MUST contain exactly one `scale` transformation that specifies the pixel size in physical units or time duration.
If scaling information is not available or applicable for one of the axes,
@@ -1575,7 +1563,7 @@ The `plate` dictionary MAY contain an `acquisitions` key
whose value MUST be a list of JSON objects defining the acquisitions for a given plate to which wells can refer to.
Each acquisition object MUST contain an `id` key
whose value MUST be an unique integer identifier greater than or equal to 0 within the context of the plate
-to which fields of view can refer to (see [well metadata](well-md)).
+to which fields of view can refer to (see [well metadata](#well-md)).
Each acquisition object SHOULD contain a `name` key whose value MUST be a string
identifying the name of the acquisition.
Each acquisition object SHOULD contain a `maximumfieldcount` key
@@ -1663,7 +1651,7 @@ whose value MUST be a string specifying the path to the field of view.
The `path` MUST contain only alphanumeric characters, MUST be case-sensitive, and MUST NOT be a duplicate of any other `path` in the `images` list.
If multiple acquisitions were performed in the plate,
it MUST contain an `acquisition` key whose value MUST be an integer identifying the acquisition
-which MUST match one of the acquisition JSON objects defined in the [plate metadata](plate-md).
+which MUST match one of the acquisition JSON objects defined in the [plate metadata](#plate-md).
The `well` dictionary SHOULD contain a `version` key
whose value MUST be a string specifying the version of the well specification.
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..1966502c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,33 @@
+[project]
+name = "ngff-spec"
+dynamic = ["version"]
+description = "Next-generation file format specification"
+license = {file = "LICENSE"}
+requires-python = ">=3.10"
+
+dependencies = [
+ "sphinx",
+ "sphinx-book-theme",
+ "sphinx-proof",
+ "sphinx-inline-tabs",
+ "sphinx-examples",
+ "json-schema-for-humans",
+ "myst-parser",
+ "json_with_comments",
+ "jupyter-book==2.0.0b3",
+ "jsonschema_markdown"
+]
+
+[project.optional-dependencies]
+testing = [
+ "tox",
+ "pytest", # https://docs.pytest.org/en/latest/contents.html
+]
+
+[tool.setuptools_scm]
+write_to = "ngff_spec/_version.py"
+fallback_version = "0.0.1+nogit"
+
+[build-system]
+requires = ["setuptools >= 77.0.3", "setuptools-scm"]
+build-backend = "setuptools.build_meta"
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index a68bd648..00000000
--- a/requirements.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-sphinx
-sphinx-book-theme
-sphinx-proof
-sphinx-inline-tabs
-sphinx-examples
-json-schema-for-humans
-myst-parser
-json_with_comments
-jupyter-book
-jsonschema_markdown
-pytest
From ec8f66ea9e15dd613725b8bd043fdc82a5d9e705 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 20 Oct 2025 18:00:33 +0200
Subject: [PATCH 02/47] correctly mark examples
---
ngff_spec/specification.md | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 140f4678..eb995f35 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -217,7 +217,7 @@ As such, label images may be interpolated using "nearest neighbor" to obtain lab
For the coordinate system:
-```
+```json
{
"name" : "index and interpolation",
"axes" : [
@@ -316,8 +316,8 @@ then used for quantification with the instrument 1 image.
],
"coordinateTransformations": [
{
- "type": "affine":
- "path": "../sampleA_instrument2-to-instrument1"
+ "type": "affine",
+ "path": "../sampleA_instrument2-to-instrument1",
"input": "sampleA_instrument2",
"output": "sampleA_instrument1"
}
@@ -368,7 +368,7 @@ the last dimension of an array in "C" order are stored contiguously on disk or i
For example, if `0/zarr.json` contains:
-```
+```json
{
"zarr_format": 3,
"node_type": "array",
@@ -678,7 +678,9 @@ Inverse transformations used for image rendering may be specified using the `inv
"transformation" : {
"type": "displacements",
"path": "path/to/displacements",
- }
+ },
+ "input": "input_image",
+ "output": "output_image"
}
```
From 75913febf0a9855081f8ebb0474cf30ac587ce20 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:24:24 +0200
Subject: [PATCH 03/47] bump mystmd dependency
---
pyproject.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyproject.toml b/pyproject.toml
index 1966502c..35f5be17 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -16,6 +16,7 @@ dependencies = [
"json_with_comments",
"jupyter-book==2.0.0b3",
"jsonschema_markdown"
+ "mystmd>=1.6.3",
]
[project.optional-dependencies]
From 992aac0b22999e40a04871f36c1dcddeb754527f Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:26:53 +0200
Subject: [PATCH 04/47] pin mystmd
---
pyproject.toml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 35f5be17..5c328c38 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,8 +15,8 @@ dependencies = [
"myst-parser",
"json_with_comments",
"jupyter-book==2.0.0b3",
- "jsonschema_markdown"
- "mystmd>=1.6.3",
+ "jsonschema_markdown",
+ "mystmd==1.6.3",
]
[project.optional-dependencies]
From 278c97fede75cce1e3f24baa1ba14cb07ba90780 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:29:05 +0200
Subject: [PATCH 05/47] hashpin template
---
ngff_spec/myst.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/ngff_spec/myst.yml b/ngff_spec/myst.yml
index 0b02aa47..9f5d92be 100644
--- a/ngff_spec/myst.yml
+++ b/ngff_spec/myst.yml
@@ -29,4 +29,6 @@ site:
parts:
footer: footer.md
- template: book-theme
+ # Temporarily hash-pin the theme.
+ # See: https://github.com/jupytercon/jupytercon2025-developingextensions/issues/6
+ template: "https://github.com/myst-templates/book-theme/archive/de4c1e9c09c6cd12fc529c1f22e8abf8e7f35381.zip"
From 6a4fd8781eab2ddc5e3f96dacc6d40fb4885543d Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 20 Oct 2025 22:32:20 +0200
Subject: [PATCH 06/47] remove legacy dependencies
---
pyproject.toml | 6 ------
1 file changed, 6 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 5c328c38..f9e7d114 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,13 +6,7 @@ license = {file = "LICENSE"}
requires-python = ">=3.10"
dependencies = [
- "sphinx",
- "sphinx-book-theme",
- "sphinx-proof",
- "sphinx-inline-tabs",
- "sphinx-examples",
"json-schema-for-humans",
- "myst-parser",
"json_with_comments",
"jupyter-book==2.0.0b3",
"jsonschema_markdown",
From d5b63afa2b2ac09589d95fc521b700fa0efb30ad Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:33:12 +0200
Subject: [PATCH 07/47] Create README.md for OME-NGFF specification
---
README.md | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 README.md
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..bf33850a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# OME-NGFF file format specification
+
+NGFF is an initiative by the bioimaging community to develop imaging format specifications to
+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.
+
+The built including contribution hints can be found **[here]([url](https://ngff-spec.readthedocs.io/en/latest/specification.html))**.
From 066145da5981628d7010637c49f667dc2bd64456 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:34:37 +0200
Subject: [PATCH 08/47] remove legacy files
---
ngff_spec/._config.yml.bak | 83 --------------------------------------
ngff_spec/._toc.yml.bak | 17 --------
2 files changed, 100 deletions(-)
delete mode 100644 ngff_spec/._config.yml.bak
delete mode 100644 ngff_spec/._toc.yml.bak
diff --git a/ngff_spec/._config.yml.bak b/ngff_spec/._config.yml.bak
deleted file mode 100644
index 8feb92b1..00000000
--- a/ngff_spec/._config.yml.bak
+++ /dev/null
@@ -1,83 +0,0 @@
-# Book settings
-# Learn more at https://jupyterbook.org/customize/config.html
-# Comprehensive example: https://github.com/executablebooks/jupyter-book/blob/master/docs/_config.yml
-
-title: Next-generation file format specification
-author: NGFF-community
-logo: https://www.openmicroscopy.org/img/logos/ome-logomark.svg
-
-# Force re-execution of notebooks on each build.
-# See https://jupyterbook.org/content/execute.html
-# execute:
-# execute_notebooks: off
-
-# Define the name of the latex output file for PDF builds
-latex:
- latex_documents:
- targetname: book.tex
-
-# Add a bibtex file so that we can create citations
-bibtex_bibfiles:
- - references.bib
-
-# Information about where the book exists on the web
-repository:
- url: https://github.com/ome/ngff-spec # Online location of your book
- path_to_book: docs # Optional path to your book, relative to the repository root
- branch: main # Which branch of the repository should be used when creating links (optional)
-
-# Add GitHub buttons to your book
-# See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository
-html:
- use_issues_button: true
- use_repository_button: true
- extra_footer: |
-
- Copyright © 2020-
-
OME®
- (
U. Dundee).
- OME trademark rules apply.
-
-
-
-parse:
- myst_heading_anchors: 3
-
-myst:
- enable_extensions:
- - colon_fence
- - deflist
- - dollarmath
- - linkify
- - substitution
-
-
-sphinx:
- extra_extensions:
- - sphinx.ext.autosummary
- - sphinx.ext.autodoc
- - sphinx.ext.napoleon # Enable support for NumPy and Google style docstrings
- - sphinx.ext.intersphinx
- - sphinx_inline_tabs
- - sphinx_proof
- - sphinx_examples
- config:
- html_show_copyright: false
- add_module_names: True
- autosummary_generate: True
-
- myst_substitutions:
- title: "OME-Zarr specification"
- shortname: "ome-zarr"
- level: "1"
- status: "CG-FINAL"
- tr_url: "https://ngff.openmicroscopy.org/0.5/"
- url: "https://ngff.openmicroscopy.org/0.6-dev/"
- issue_tracking: "[Forum](https://forum.image.sc/tag/ome-ngff), [Github](https://github.com/ome/ngff/issues)"
- logo: "http://www.openmicroscopy.org/img/logos/ome-logomark.svg"
- editor_name: "[Josh Moore](https://gerbi-gmb.de/)"
- editor_affiliation: "German BioImaging e.V."
- editor_orcid: "[https://orcid.org/0000-0003-4028-811X](https://orcid.org/0000-0003-4028-811X)"
- version: "0.6.dev1"
\ No newline at end of file
diff --git a/ngff_spec/._toc.yml.bak b/ngff_spec/._toc.yml.bak
deleted file mode 100644
index 765b91a1..00000000
--- a/ngff_spec/._toc.yml.bak
+++ /dev/null
@@ -1,17 +0,0 @@
-# Table of contents
-# Learn more at https://jupyterbook.org/customize/toc.html
-
-format: jb-book
-root: specification
-
-chapters:
-- file: examples
- sections:
- - glob: _generated/examples/*
-- file: schemas
- sections:
- - glob: _generated/schemas/markdown/*
-
-- file: contribute
-- file: citing
-- file: version_history
\ No newline at end of file
From deb17effc67fec8662bf69f2c1d58777d43f3c13 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:34:51 +0200
Subject: [PATCH 09/47] use auto-built footer for copyright
---
ngff_spec/footer.md | 6 ------
ngff_spec/pre_build.py | 16 ++++++++++++++++
2 files changed, 16 insertions(+), 6 deletions(-)
delete mode 100644 ngff_spec/footer.md
diff --git a/ngff_spec/footer.md b/ngff_spec/footer.md
deleted file mode 100644
index 132338a7..00000000
--- a/ngff_spec/footer.md
+++ /dev/null
@@ -1,6 +0,0 @@
-
- Copyright © 2020-{{ year }}
-
OME®
- (
U. Dundee).
- OME trademark rules apply.
-
\ No newline at end of file
diff --git a/ngff_spec/pre_build.py b/ngff_spec/pre_build.py
index 3db43173..b6bb8e28 100644
--- a/ngff_spec/pre_build.py
+++ b/ngff_spec/pre_build.py
@@ -141,5 +141,21 @@ def build_json_schemas():
with open(os.path.join("schemas.md"), 'w') as index_file:
index_file.write(index_markdown)
+def build_footer():
+ """Build footer file."""
+ from datetime import datetime
+ year = datetime.now().year
+ footer_content = f"""
+
+ Copyright © 2020-{year}
+
OME®
+ (
U. Dundee).
+ OME trademark rules apply.
+
+"""
+ with open('footer.md', 'w') as footer_file:
+ footer_file.write(footer_content)
+
build_json_examples()
build_json_schemas()
+build_footer()
From e320b223c14f4022b2ee5becf330028196fce2f7 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:39:32 +0200
Subject: [PATCH 10/47] Update `coordinateSystems` metadata
---
ngff_spec/specification.md | 80 +++++++-------------------------------
1 file changed, 15 insertions(+), 65 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index eb995f35..92517969 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -235,20 +235,23 @@ Indexing an image at the point `(1, 0.2, 0.3, 0.4)` is valid.
````
-## "coordinateSystems" metadata
-
-(coord-sys-md)=
+### "coordinateSystems" metadata
A "coordinate system" is a collection of "axes" / dimensions with a name.
Every coordinate system:
-
- MUST contain the field "name".
- The value MUST be a non-empty string that is unique among `coordinateSystem`s.
-- MUST contain the field "axes", whose value is an array of valid "axes".
+ The value MUST be a non-empty string that is unique among all entries under `coordinateSystems`.
+- MUST contain the field "axes", whose value is an array of valid "axes" (see below).
+
+The order of the `"axes"` list matters
+and defines the index of each array dimension and coordinates for points in that coordinate system.
+For the above example, the `"x"` dimension is the last dimension.
+The "dimensionality" of a coordinate system is indicated by the length of its "axes" array.
+The "volume_micrometers" example coordinate system above is three dimensional (3D).
````{admonition} Example
-Example of valid `coordinateSystems` metadata:
+Coordinate Systems metadata example
```json
{
@@ -262,70 +265,17 @@ Example of valid `coordinateSystems` metadata:
```
````
-The order of the `"axes"` list matters and defines the index of each array dimension and coordinates for points in that coordinate system.
-For the above example, the `"x"` dimension is the last dimension.
-The "dimensionality" of a coordinate system is indicated by the length of its "axes" array.
-The "volume_micrometers" example coordinate system above is three dimensional (3D).
-
-The axes of a coordinate system (see below) give information about the types, units, and other properties of the coordinate system's dimensions.
+The axes of a coordinate system (see below) give information
+about the types, units, and other properties of the coordinate system's dimensions.
Axis `name`s may contain semantically meaningful information, but can be arbitrary.
-As a result, two coordinate systems that have identical axes in the same order may not be "the same"
-in the sense that measurements at the same point refer to different physical entities and therefore should not be analyzed jointly.
+As a result, two coordinate systems that have identical axes in the same order
+ay not be "the same" in the sense that measurements at the same point
+refer to different physical entities and therefore should not be analyzed jointly.
Tasks that require images, annotations, regions of interest, etc.,
SHOULD ensure that they are in the same coordinate system (same name, with identical axes)
or can be transformed to the same coordinate system before doing analysis.
See the example below.
-````{admonition} Example
-
-Two instruments simultaneously image the same sample from two different angles,
-and the 3D data from both instruments are calibrated to "micrometer" units.
-Two samples are collected ("sampleA" and "sampleB").
-An analysis of sample A requires measurements from both instruments' images at certain points in space.
-Suppose a region of interest (ROI) is determined from the image obtained from instrument 2,
-but quantification from that region is needed for instrument 1.
-Since measurements were collected at different angles,
-a measurement by instrument 1 at the point with coordinates (x,y,z) may not correspond to the measurement at the same point in instrument 2
-(i.e., it may not be the same physical location in the sample).
-To analyze both images together, they must be in the same coordinate system.
-
-The set of [coordinate transformations](#trafo-md) encodes relationships between coordinate systems, specifically, how to
-convert points and images to different coordinate systems.
-Implementations can apply the coordinate transform to images or points in coordinate system "sampleA_instrument2" to bring them into the "sampleA_instrument1" coordinate system.
-In this case, the ROI should be transformed to the "sampleA_image1" coordinate system,
-then used for quantification with the instrument 1 image.
-
-```json
-"coordinateSystems" : [
- {
- "name" : "sampleA-instrument1",
- "axes" : [
- {"name": "z", "type": "space", "unit": "micrometer"},
- {"name": "y", "type": "space", "unit": "micrometer"},
- {"name": "x", "type": "space", "unit": "micrometer"}
- ]
- },
- {
- "name" : "sampleA-instrument2",
- "axes" : [
- {"name": "z", "type": "space", "unit": "micrometer"},
- {"name": "y", "type": "space", "unit": "micrometer"},
- {"name": "x", "type": "space", "unit": "micrometer"}
- ]
- }
-],
-"coordinateTransformations": [
- {
- "type": "affine",
- "path": "../sampleA_instrument2-to-instrument1",
- "input": "sampleA_instrument2",
- "output": "sampleA_instrument1"
- }
-]
-```
-
-````
-
### Array coordinate systems
The dimensions of an array do not have an interpretation until they are associated with a coordinate system via a coordinate transformation.
From a5425768428eb4d571a1bfe40eacac67d29dba39 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:40:57 +0200
Subject: [PATCH 11/47] Updated `axes` metadata and moved under
`coordinateSystems` header level
---
ngff_spec/specification.md | 118 +++++++++++++------------------------
1 file changed, 41 insertions(+), 77 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 92517969..6dd00743 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -158,83 +158,6 @@ The OME-Zarr Metadata version MUST be consistent within a hierarchy.
}
```
-## "axes" metadata
-(axes-md)=
-
-"axes" describes the dimensions of a coordinate systems and adds an interpretation to the data along that dimension.
-A named collection of axes forms a [coordinate system](#coord-sys-md).
-It is a list of dictionaries, where each dictionary describes a dimension (axis) and:
-
-- MUST contain the field "name" that gives the name for this dimension.
- The values MUST be unique across all "name" fields.
-- SHOULD contain the field "type".
- It SHOULD be one of the strings "array", "space", "time", "channel", "coordinate", or "displacement"
- but MAY take other string values for custom axis types that are not part of this specification yet.
-- SHOULD contain the field "unit" to specify the physical unit of this dimension.
- The value SHOULD be one of the following strings, which are valid units according to UDUNITS-2.
- - Units for "space" axes:
- 'angstrom', 'attometer', 'centimeter', 'decimeter', 'exameter', 'femtometer', 'foot', 'gigameter', 'hectometer', 'inch', 'kilometer', 'megameter', 'meter', 'micrometer', 'mile', 'millimeter', 'nanometer', 'parsec', 'petameter', 'picometer', 'terameter', 'yard', 'yoctometer', 'yottameter', 'zeptometer', 'zettameter'
- - Units for "time" axes:
- 'attosecond', 'centisecond', 'day', 'decisecond', 'exasecond', 'femtosecond', 'gigasecond', 'hectosecond', 'hour', 'kilosecond', 'megasecond', 'microsecond', 'millisecond', 'minute', 'nanosecond', 'petasecond', 'picosecond', 'second', 'terasecond', 'yoctosecond', 'yottasecond', 'zeptosecond', 'zettasecond'
-- MAY contain the field "longName".
- The value MUST be a string, and can provide a longer name or description of an axis and its properties.
-
-The "axes" are used as part of [multiscales metadata](#multiscales-md).
-The length of "axes" MUST be equal to the number of dimensions of the arrays that contain the image data.
-
-The "dimension_names" attribute MUST be included in the `zarr.json` of the Zarr array of a multiscale level and MUST match the names in the "axes" metadata.
-
-````{admonition} Example
-
-Examples of valid axes:
-
-```json
-[
- {"name": "x", "type": "space", "unit": "micrometer"},
- {"name": "t", "type": "time", "unit": "second", "longName": "Unix Epoch time"},
- {"name": "c", "type": "channel", "discrete": true},
- {"name": "i0", "type": "array"},
- {"name": "c", "type": "coordinate", "discrete" : true },
- {"name": "v", "type": "displacement", "discrete": true },
- {"name": "freq", "type": "frequency", "unit": "megahertz"}
-]
-```
-````
-
-Arrays are inherently discrete (see Array coordinate systems, below) but are often used to store discrete samples of a continuous variable.
-The continuous values "in between" discrete samples can be retrieved using an *interpolation* method.
-If an axis is continuous (`"discrete" : false`), it indicates that interpolation is well-defined.
-Axes representing `space` and `time` are usually continuous.
-Similarly, joint interpolation across axes is well-defined only for axes of the same `type`.
-In contrast, discrete axes (`"discrete" : true`) may be indexed only by integers.
-Axes of representing a `channel`, `coordinate`, or `displacement` are usually discrete.
-
-Note: The most common methods for interpolation are "nearest neighbor", "linear", "cubic", and "windowed sinc".
-Here, we refer to any method that obtains values at real valued coordinates using discrete samples as an "interpolator".
-As such, label images may be interpolated using "nearest neighbor" to obtain labels at points along the continuum.
-
-````{admonition} Example
-
-For the coordinate system:
-
-```json
-{
- "name" : "index and interpolation",
- "axes" : [
- {"name": "t", "type": "time"},
- {"name": "c", "type": "channel", "discrete": true},
- {"name": "y", "type": "space"},
- {"name": "x", "type": "space"}
- ]
-}
-```
-
-Indexing an image at the point `(0.1, 0.2, 0.3, 0.4)` is not valid,
-because the value of the first coordinate (`0.1`) refers to the discrete axis `"c"`.
-Indexing an image at the point `(1, 0.2, 0.3, 0.4)` is valid.
-
-````
-
### "coordinateSystems" metadata
A "coordinate system" is a collection of "axes" / dimensions with a name.
@@ -276,6 +199,47 @@ SHOULD ensure that they are in the same coordinate system (same name, with ident
or can be transformed to the same coordinate system before doing analysis.
See the example below.
+#### "axes" metadata
+
+"axes" describes the dimensions of a coordinate systems
+and adds an interpretation to the samples along that dimension.
+
+It is a list of dictionaries,
+where each dictionary describes a dimension (axis) and:
+- MUST contain the field "name" that gives the name for this dimension.
+ The values MUST be unique across all "name" fields.
+- SHOULD contain the field "type".
+ It SHOULD be one of the strings "array", "space", "time", "channel", "coordinate", or "displacement"
+ but MAY take other string values for custom axis types that are not part of this specification yet.
+- MAY contain the field "discrete".
+ The value MUST be a boolean,
+ and is `true` if the axis represents a discrete dimension.
+- SHOULD contain the field "unit" to specify the physical unit of this dimension.
+ The value SHOULD be one of the following strings,
+ which are valid units according to UDUNITS-2.
+ - Units for "space" axes: 'angstrom', 'attometer', 'centimeter', 'decimeter', 'exameter', 'femtometer', 'foot', 'gigameter', 'hectometer', 'inch', 'kilometer', 'megameter', 'meter', 'micrometer', 'mile', 'millimeter', 'nanometer', 'parsec', 'petameter', 'picometer', 'terameter', 'yard', 'yoctometer', 'yottameter', 'zeptometer', 'zettameter'
+ - Units for "time" axes: 'attosecond', 'centisecond', 'day', 'decisecond', 'exasecond', 'femtosecond', 'gigasecond', 'hectosecond', 'hour', 'kilosecond', 'megasecond', 'microsecond', 'millisecond', 'minute', 'nanosecond', 'petasecond', 'picosecond', 'second', 'terasecond', 'yoctosecond', 'yottasecond', 'zeptosecond', 'zettasecond'
+- MAY contain the field "longName".
+ The value MUST be a string,
+ and can provide a longer name or description of an axis and its properties.
+
+If part of metadata, the length of "axes" MUST be equal to the number of dimensions of the arrays that contain the image data.
+
+Arrays are inherently discrete (see Array coordinate systems, below)
+but are often used to store discrete samples of a continuous variable.
+The continuous values "in between" discrete samples can be retrieved using an *interpolation* method.
+If an axis is continuous (`"discrete" : false`), it indicates that interpolation is well-defined.
+Axes representing `space` and `time` are usually continuous.
+Similarly, joint interpolation across axes is well-defined only for axes of the same `type`.
+In contrast, discrete axes (`"discrete" : true`) may be indexed only by integers.
+Axes of representing a `channel`, `coordinate`, or `displacement` are usually discrete.
+
+```{note}
+The most common methods for interpolation are "nearest neighbor", "linear", "cubic", and "windowed sinc".
+Here, we refer to any method that obtains values at real-valued coordinates using discrete samples as an "interpolator".
+As such, label images may be interpolated using "nearest neighbor" to obtain labels at points along the continuum.
+```
+
### Array coordinate systems
The dimensions of an array do not have an interpretation until they are associated with a coordinate system via a coordinate transformation.
From 599cb2e654ea8a791f68639d85c4ded3e7defdcb Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:44:02 +0200
Subject: [PATCH 12/47] Update array coordinate systems metadata and merge
existing examples
---
ngff_spec/specification.md | 50 +++++++++++++-------------------------
1 file changed, 17 insertions(+), 33 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 6dd00743..f0f0a2c6 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -240,26 +240,27 @@ Here, we refer to any method that obtains values at real-valued coordinates usin
As such, label images may be interpolated using "nearest neighbor" to obtain labels at points along the continuum.
```
-### Array coordinate systems
+#### Array coordinate systems
-The dimensions of an array do not have an interpretation until they are associated with a coordinate system via a coordinate transformation.
+The dimensions of an array do not have an interpretation
+until they are associated with a coordinate system via a coordinate transformation.
Nevertheless, it can be useful to refer to the "raw" coordinates of the array.
Some applications might prefer to define points or regions-of-interest in "pixel coordinates" rather than "physical coordinates," for example.
Indicating that choice explicitly will be important for interoperability.
This is possible by using **array coordinate systems**.
Every array has a default coordinate system whose parameters need not be explicitly defined.
-Its name is the path to the array in the container, its axes have `"type":"array"`, are unitless, and have default "name"s.
-The ith axis has `"name":"dim_i"`
-(these are the same default names used by [xarray](https://docs.xarray.dev/en/stable/user-guide/terminology.html)).
+The dimensionality of each array coordinate system equals the dimensionality of its corresponding zarr array.
+Its name is the path to the array in the container,
+its axes have `"type":"array"`, are unitless, and have default `name`s.
+The i-th axis has `"name":"dim_i"` (these are the same default names used by [xarray](https://docs.xarray.dev/en/stable/user-guide/terminology.html)).
+The `dimension_names` must be unique and non-null.
````{admonition} Example
-For example, a 3D array at path `0` defines the coordinate system:
-
```json
{
- "name" : "0",
- "axes" : [
+ "name": "0",
+ "axes": [
{"name": "dim_0", "type": "array"},
{"name": "dim_1", "type": "array"},
{"name": "dim_2", "type": "array"}
@@ -267,21 +268,8 @@ For example, a 3D array at path `0` defines the coordinate system:
}
```
-though this object should not and need not explicitly appear in metadata.
-
-````
-
-The dimensionality of each array coordinate system equals the dimensionality of its corresponding zarr array.
-The axis with name `"dim_i"` is the ith element of the `"axes"` list.
-The axes and their order align with the `shape` attribute in the zarr array attributes,
-and whose data depends on the byte order used to store chunks.
-As described in the [zarr array metadata](https://zarr-specs.readthedocs.io/en/latest/v3/core/v3.0.html#array-metadata),
-the last dimension of an array in "C" order are stored contiguously on disk or in-memory when directly loaded.
-
-````{admonition} Example
For example, if `0/zarr.json` contains:
-
```json
{
"zarr_format": 3,
@@ -290,25 +278,21 @@ For example, if `0/zarr.json` contains:
...
}
```
-
Then `dim_0` has length 4, `dim_1` has length 3, and `dim_2` has length 5.
````
+The dimensionality of each array coordinate system equals the dimensionality of its corresponding zarr array.
+The axis with name `"dim_i"` is the i-th element of the `"axes"` list.
+The axes and their order align with the `shape` attribute in the zarr array attributes (in `.zarray`),
+and whose data depends on the byte order used to store chunks.
+As described in the [zarr array metadata](https://zarr.readthedocs.io/en/stable/spec/v2.html#arrays),
+the last dimension of an array in "C" order are stored contiguously on disk or in-memory when directly loaded.
+
The name and axes names MAY be customized by including a `arrayCoordinateSystem` field
in the user-defined attributes of the array whose value is a coordinate system object.
The length of `axes` MUST be equal to the dimensionality.
The value of `"type"` for each object in the axes array MUST equal `"array"`.
-````{admonition} Example
-
-
-```{literalinclude} examples/coordSystems/arrayCoordSys.json
-```
-
-Note that dimension `i` is contiguous in memory.
-
-````
-
### Coordinate convention
**The pixel/voxel center is the origin of the continuous coordinate system.**
From 0c3cb9df7cac283e9a23c780bae05d6a7752b47d Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:44:33 +0200
Subject: [PATCH 13/47] Update coordinate convention metadata
---
ngff_spec/specification.md | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index f0f0a2c6..e1af11a8 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -293,17 +293,19 @@ in the user-defined attributes of the array whose value is a coordinate system o
The length of `axes` MUST be equal to the dimensionality.
The value of `"type"` for each object in the axes array MUST equal `"array"`.
-### Coordinate convention
+#### Coordinate convention
**The pixel/voxel center is the origin of the continuous coordinate system.**
-It is vital to consistently define relationship between the discrete/array and continuous/interpolated coordinate systems.
-A pixel/voxel is the continuous region (rectangle) that corresponds to a single sample in the discrete array,
-i.e., the area corresponding to nearest-neighbor (NN) interpolation of that sample.
-The center of a 2d pixel corresponding to the origin `(0,0)` in the discrete array is the origin of the continuous coordinate system `(0.0, 0.0)` (when the transformation is the identity).
-The continuous rectangle of the pixel is given by the half-open interval `[-0.5, 0.5) x [-0.5, 0.5)`
-(i.e., -0.5 is included, +0.5 is excluded).
-See chapter 4 and figure 4.1 of the ITK Software Guide [[itk]].
+It is vital to consistently define relationship
+between the discrete/array and continuous/interpolated coordinate systems.
+A pixel/voxel is the continuous region (rectangle) that corresponds to a single sample in the discrete array, i.e.,
+the area corresponding to nearest-neighbor (NN) interpolation of that sample.
+The center of a 2d pixel corresponding to the origin `(0,0)` in the discrete array
+is the origin of the continuous coordinate system `(0.0, 0.0)` (when the transformation is the identity).
+The continuous rectangle of the pixel is given
+by the half-open interval `[-0.5, 0.5) x [-0.5, 0.5)` (i.e., -0.5 is included, +0.5 is excluded).
+See chapter 4 and figure 4.1 of the ITK Software Guide.
## bioformats2raw.layout
From 9f8bed052d2ecb062ba3011cbdc69b677c6c6000 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:46:38 +0200
Subject: [PATCH 14/47] Updated coordinate transformations metadata
---
ngff_spec/specification.md | 177 +++++++++++++++++++++++--------------
1 file changed, 111 insertions(+), 66 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index e1af11a8..a36a3848 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -392,79 +392,60 @@ Conforming readers:
## "coordinateTransformations" metadata
-(trafo-md)=
-
"coordinateTransformations" describe the mapping between two coordinate systems (defined by "axes").
For example, to map an array's discrete coordinate system to its corresponding physical coordinates.
Coordinate transforms are in the "forward" direction.
-They represent functions from *points* in the input space to *points* in the output space.
+They represent functions from *points* in the input space to *points* in the output space.
-- MUST contain the field "type".
+- MUST contain the field "type" (string).
- MUST contain any other fields required by the given "type" (see table below).
-- MUST contain the field "output", unless part of a `sequence` or `inverseOf` (see details).
-- MUST contain the field "input", unless part of a `sequence` or `inverseOf` (see details).
-- MAY contain the field "name". Its value MUST be unique across all "name" fields for coordinate transformations.
+- MUST contain the field "output" (string),
+ unless part of a `sequence` or `inverseOf` (see details).
+- MUST contain the field "input" (string),
+ unless part of a `sequence` or `inverseOf` (see details).
+- MAY contain the field "name" (string).
+ Its value MUST be unique across all "name" fields for coordinate transformations.
- Parameter values MUST be compatible with input and output space dimensionality (see details).
-
- | `identity`
- |
- | The identity transformation is the default transformation and is typically not explicitly defined.
- |
|---|
| `mapAxis`
- | `"mapAxis":Dict[String:String]`
- | A `maxAxis` transformation specifies an axis permutation as a map between axis names.
- |
|---|
| `translation`
- | one of: `"translation":List[number]`, `"path":str`
- | translation vector, stored either as a list of numbers (`"translation"`) or as binary data at a location
- in this container (`path`).
- |
|---|
| `scale`
- | one of: `"scale":List[number]`, `"path":str`
- | scale vector, stored either as a list of numbers (`scale`) or as binary data at a location in this
- container (`path`).
- |
|---|
| `affine`
- | one of: `"affine":List[List[number]]`, `"path":str`
- | affine transformation matrix stored as a flat array stored either with json uing the affine field
- or as binary data at a location in this container (path). If both are present, the binary values at path should be used.
- |
|---|
| `rotation`
- | one of: `"rotation":List[number]`, `"path":str`
- | rotation transformation matrix stored as an array stored either
- with json or as binary data at a location in this container (path).
- If both are present, the binary parameters at path are used.
- |
|---|
| `sequence`
- | `"transformations":List[Transformation]`
- | A sequence of transformations, Applying the sequence applies the composition of all transforms in the list, in order.
- |
|---|
| `displacements`
- | `"path":str` `"interpolation":str`
- | Displacement field transformation located at (path).
- |
|---|
| `coordinates`
- | `"path":str` `"interpolation":str`
- | Coordinate field transformation located at (path).
- |
|---|
| `inverseOf`
- | `"transform":Transform`
- | The inverse of a transformation. Useful if a transform is not closed-form invertible. See Forward and inverse for details and examples.
- |
|---|
| `bijection`
- | `"forward":Transform` `"inverse":Transform`
- | Explicitly define an invertible transformation by providing a forward transformation and its inverse.
- |
|---|
| `byDimension`
- | `"transformations":List[Transformation]`
- | Define a high dimensional transformation using lower dimensional transformations on subsets of
- dimensions.
-
- | type | fields | description
- |
|---|
|
|---|
+The following transformations are supported:
+
+| Type | Fields | Description |
+|------|--------|-------------|
+| `identity` | | The identity transformation is the default transformation and is typically not explicitly defined. |
+| `mapAxis` | `"mapAxis":List[number]` | A `mapAxis` transformation specifies an axis permutation as a transpose array of integer indices that refer to the ordering of the axes in the respective coordinate system. |
+| `translation` | one of:
`"translation":List[number]`,
`"path":str` | translation vector, stored either as a list of numbers (`"translation"`) or as binary data at a location in this container (`path`). |
+| `scale` | one of:
`"scale":List[number]`,
`"path":str` | scale vector, stored either as a list of numbers (`scale`) or as binary data at a location in this container (`path`). |
+| `affine` | one of:
`"affine": List[List[number]]`,
`"path":str` | affine transformation matrix stored as a flat array stored either with json using the affine field or as binary data at a location in this container (path). If both are present, the binary values at path should be used. |
+| `rotation` | one of:
`"rotation":List[List[number]]`,
`"path":str` | rotation transformation matrix stored as an array stored either with json or as binary data at a location in this container (path). If both are present, the binary parameters at path are used. |
+| `sequence` | `"transformations":List[Transformation]` | A sequence of transformations, Applying the sequence applies the composition of all transforms in the list, in order. |
+| `displacements` | `"path":str`
`"interpolation":str` | Displacement field transformation located at (path). |
+| `coordinates` | `"path":str`
`"interpolation":str` | Coordinate field transformation located at (path). |
+| `inverseOf` | `"transformation":Transformation` | The inverse of a transformation. Useful if a transform is not closed-form invertible. See Forward and inverse for details and examples. |
+| `bijection` | `"forward":Transformation`
`"inverse":Transformation` | Explicitly define an invertible transformation by providing a forward transformation and its inverse. |
+| `byDimension` | `"transformations":List[Transformation]`,
`"input_axes": List[str]`,
`"output_axes": List[str]` | Define a high dimensional transformation using lower dimensional transformations on subsets of dimensions. |
Conforming readers:
-
- MUST parse `identity`, `scale`, `translation` transformations;
-- SHOULD parse `mapAxis`, `affine` transformations;
+- SHOULD parse `mapAxis`, `affine`, `rotation` transformations;
+- SHOULD display an informative warning if encountering transformations that cannot be parsed;
- SHOULD be able to apply transformations to points;
- SHOULD be able to apply transformations to images;
-Coordinate transformations from array to physical coordinates MUST be stored in [multiscales](#multiscales-md).
-Transformations between different images MUST be stored in the attributes of a parent zarr group.
-For transformations that store data or parameters in a zarr array, those zarr arrays SHOULD be stored in a zarr group `"coordinateTransformations"`.
-
-```text
+Coordinate transformations can be stored in multiple places to reflect different usecases.
+
+- Multiscale transformations represent a special case of transformations
+ and are explained [below](#multiscales-metadata).
+- Additional transformations for single images MUST be stored under a field `coordinateTransformations`
+ in the multiscales dictionaries.
+ This `coordinateTransformations` field MUST contain a list of valid [transformations](#transformation-types).
+- Transformations between two or more images MUST be stored in the attributes of a parent zarr group.
+ For transformations that store data or parameters in a zarr array,
+ those zarr arrays SHOULD be stored in a zarr group `coordinateTransformations`.
+
+Implementations SHOULD prefer to store transformations as a sequence of less expressive transformations
+(i.e., sequence[translation, rotation] instead of affine transformation with translation/rotation) component.
+
+
store.zarr # Root folder of the zarr store
│
├── zarr.json # coordinate transformations describing the relationship between two image coordinate systems
@@ -476,18 +457,82 @@ store.zarr # Root folder of the zarr store
│ └── zarr.json
│
├── volume
-│ ├── zarr.json # group level attributes (multiscales)
+│ ├── zarr.json # group level attributes (multiscales)
│ └── 0 # a group containing the 0th scale
│ └── image # a zarr array
-│ └── zarr.json # physical coordinate system and transformations here
-│ # the array attributes
+│ └── zarr.json # physical coordinate system and transformations here
└── crop
- ├── .zattrs # group level attributes (multiscales)
+ ├── zarr.json # group level attributes (multiscales)
└── 0 # a group containing the 0th scale
└── image # a zarr array
- └── zarr.json # physical coordinate system and transformations here
- # the array attributes
+ └── zarr.json # physical coordinate system and transformations here
+
+
+````{admonition} Example
+Two instruments simultaneously image the same sample from two different angles,
+and the 3D data from both instruments are calibrated to "micrometer" units.
+Two samples are collected ("sampleA" and "sampleB").
+An analysis of sample A requires measurements from both instruments' images at certain points in space.
+Suppose a region of interest (ROI) is determined from the image obtained from instrument 2,
+but quantification from that region is needed for instrument 1.
+Since measurements were collected at different angles,
+a measurement by instrument 1 at the point with coordinates (x,y,z)
+may not correspond to the measurement at the same point in instrument 2
+(i.e., it may not be the same physical location in the sample).
+To analyze both images together, they must be in the same coordinate system.
+
+The set of coordinate transformations encodes relationships between coordinate systems,
+specifically, how to convert points and images to different coordinate systems.
+Implementations can apply the coordinate transform to images or points
+in coordinate system "sampleA_instrument2" to bring them into the "sampleA_instrument1" coordinate system.
+In this case, the ROI should be transformed to the "sampleA_image1" coordinate system,
+then used for quantification with the instrument 1 image.
+
+The `coordinateTransformations` in the parent-level metadata would contain the following data.
+The transformation parameters are stored in a separate zarr-group
+under `coordinateTransformations/sampleA_instrument2-to-instrument1` as shown above.
+
+```json
+"coordinateTransformations": [
+ {
+ "type": "affine",
+ "path": "coordinateTransformations/sampleA_instrument2-to-instrument1",
+ "input": "sampleA_instrument2",
+ "output": "sampleA_instrument1"
+ }
+]
+```
+
+And the image under `root/sampleA_instrument1` would have the following as the first coordinate system:
+
+```json
+"coordinateSystems": [
+ {
+ "name": "sampleA-instrument1",
+ "axes": [
+ {"name": "z", "type": "space", "unit": "micrometer"},
+ {"name": "y", "type": "space", "unit": "micrometer"},
+ {"name": "x", "type": "space", "unit": "micrometer"}
+ ]
+ },
+]
+```
+
+The image under `root/sampleA_instrument2` would have this as the first listed coordinate system:
+
+```json
+[
+ {
+ "name": "sampleA-instrument2",
+ "axes": [
+ {"name": "z", "type": "space", "unit": "micrometer"},
+ {"name": "y", "type": "space", "unit": "micrometer"},
+ {"name": "x", "type": "space", "unit": "micrometer"}
+ ]
+ }
+],
```
+````
### Additional details
From 5c2c39f83722157edc4cdd0049af6374f37485df Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:48:39 +0200
Subject: [PATCH 15/47] updated matrix transformations
---
ngff_spec/specification.md | 112 ++++++++++++-------------------------
1 file changed, 37 insertions(+), 75 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index a36a3848..3ab00f1e 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -537,71 +537,29 @@ The image under `root/sampleA_instrument2` would have this as the first listed c
### Additional details
Most coordinate transformations MUST specify their input and output coordinate systems
-using `input` and `output` with a string value corresponding to the name of a coordinate system.
-The coordinate system's name may be the path to an array, and therefore may not appear in the list of coordinate systems.
-
-Exceptions are if the the coordinate transformation appears in the `transformations` list of a `sequence` or is the `transformation` of an `inverseOf` transformation.
-In these two cases input and output SHOULD be omitted
-(see below for details).
-
-Transformations in the `transformations` list of a `byDimensions` transformation MUST provide `input` and `output`
-as arrays of strings corresponding to axis names of the parent transformation's input and output coordinate systems
+using `input` and `output` with a string value
+that MUST correspond to the name of a coordinate system or the path to a multiscales group.
+Exceptions are if the coordinate transformation appears in the `transformations` list of a `sequence`
+or is the `transformation` of an `inverseOf` transformation.
+In these two cases input and output could, in some cases, be omitted (see below for details).
+
+If used in a parent-level zarr-group, the `input` field MUST be a path to the input image.
+The authoritative coordinate system for the input image is the first `coordinateSystem` defined therein.
+The `output` field can be a `path` to an output image or the name of a `coordinateSystem` defined in the parent-level zarr group.
+If the names of `input` or `output` can be both a `path` or the name of a `coordinateSystem`, `path` MUST take precedent.
+If unused, the `input` and `output` fields MAY be null.
+
+For usage in multiscales, see [multiscales section](#multiscales-metadata) for details.
+
+Transformations in the `transformations` list of a `byDimensions` transformation
+MUST provide `input` and `output` as arrays of strings
+corresponding to axis names of the parent transformation's input and output coordinate systems
(see below for details).
-````{admonition} Example
-
-The sequence transformation's input corresponds to an array coordinate system at path "my/array".
-
-```json
-"coordinateSystems" : [
- { "name" : "in", "axes" : [{"name" : "j"}, {"name":"i"}] },
- { "name" : "outScale", "axes" : [{"name" : "y"}, {"name":"x"}] },
- { "name" : "outSeq", "axes" : [{"name" : "y"}, {"name":"x"}] },
- { "name" : "outInv", "axes" : [{"name" : "y"}, {"name":"x"}] },
- { "name" : "outByDim", "axes" : [{"name" : "y"}, {"name":"x"}] }
-],
-"coordinateTransformations" : [
- {
- "type": "scale",
- "input" : "in",
- "output" : "outScale",
- "scale" : [ 0.5, 1.2 ]
- },
- {
- "type" : "sequence",
- "input" : "my/array",
- "output" : "outSeq",
- "transformations" : [
- { "type": "scale", "scale" : [ 0.5, 0.6 ] },
- { "type": "translation", "translation" : [ 2, 5 ] }
- ]
- },
- {
- "type": "inverseOf",
- "input" : "in",
- "output" : "outInv",
- "transformation" : {
- "type": "displacements",
- "path": "path/to/displacements"
- }
- },
- {
- "type": "byDimension",
- "input" : "in",
- "output" : "outDim",
- "transformations" : [
- { "type" : "translation", "translation" : [1], "input" : ["i"], "output" : ["x"]},
- { "type" : "scale", "scale" : [2.0], "input" : ["j"], "output" : ["y"]}
- ]
- }
-]
-```
-
-````
-
Coordinate transformations are functions of *points* in the input space to *points* in the output space.
We call this the "forward" direction.
-Points are ordered lists of coordinates, where a coordinate is the location/value of that point along its corresponding axis.
+Points are ordered lists of coordinates,
+where a coordinate is the location/value of that point along its corresponding axis.
The indexes of axis dimensions correspond to indexes into transformation parameter arrays.
For example, the scale transformation above defines the function:
@@ -613,38 +571,42 @@ y = 1.2 * j
i.e., the mapping from the first input axis to the first output axis is determined by the first scale parameter.
When rendering transformed images and interpolating,
-implementations may need the "inverse" transformation - from the output to the input coordinate system.
-Inverse transformations will not be explicitly specified when they can be computed in closed form from the forward transformation.
-Inverse transformations used for image rendering may be specified using the `inverseOf` transformation type, for example:
+implementations may need the "inverse" transformation -
+from the output to the input coordinate system.
+Inverse transformations will not be explicitly specified
+when they can be computed in closed form from the forward transformation.
+Inverse transformations used for image rendering may be specified using
+the `inverseOf` transformation type, for example:
```json
{
"type": "inverseOf",
"transformation" : {
"type": "displacements",
- "path": "path/to/displacements",
+ "path": "/path/to/displacements",
},
"input": "input_image",
- "output": "output_image"
+ "output": "output_image",
}
```
-Implementations SHOULD be able to compute and apply the inverse of some coordinate transformations when they are computable in closed-form
-(as the [Transformation types](#trafo-types-md) section below indicates).
-If an operation is requested that requires the inverse of a transformation that can not be inverted in closed-form,
-implementations MAY estimate an inverse, or MAY output a warning that the requested operation is unsupported.
+Implementations SHOULD be able to compute and apply
+the inverse of some coordinate transformations when they are computable
+in closed-form (as the [Transformation types](#transformation-types) section below indicates).
+If an operation is requested that requires
+the inverse of a transformation that can not be inverted in closed-form,
+implementations MAY estimate an inverse,
+or MAY output a warning that the requested operation is unsupported.
#### Matrix transformations
-(matrix-trafo-md)=
-Two transformation types ([affine](#affine-md) and [rotation](#rotation-md)) are parametrized by matrices.
+Two transformation types ([affine](#affine) and [rotation](#rotation)) are parametrized by matrices.
Matrices are applied to column vectors that represent points in the input coordinate system.
-The first (last) axis in a coordinate system is the top (bottom) entry in the column vector.
+The first and last axes in a coordinate system correspond to the top and bottom entries in the column vector, respectively.
Matrices are stored as two-dimensional arrays, either as json or in a zarr array.
When stored as a 2D zarr array, the first dimension indexes rows and the second dimension indexes columns
(e.g., an array of `"shape":[3,4]` has 3 rows and 4 columns).
-When stored as a 2D json array, the inner array contains rows
-(e.g. `[[1,2,3], [4,5,6]]` has 2 rows and 3 columns).
+When stored as a 2D json array, the inner array contains rows (e.g. `[[1,2,3], [4,5,6]]` has 2 rows and 3 columns).
````{admonition} Example
From 46e7e1c2acfd512d88f040e5452aeca7e419ffb2 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 09:49:05 +0200
Subject: [PATCH 16/47] update transformation types
---
ngff_spec/specification.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 3ab00f1e..083db7d5 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -645,11 +645,11 @@ because it is computed with the matrix-vector multiplication:
### Transformation types
(trafo-types-md)=
-Input and output dimensionality may be determined by the value of the "input" and "output" fields, respectively.
-If the value of "input" is an array, its shape gives the input dimension,
-otherwise it is given by the length of "axes" for the coordinate system with the name of the "input".
-If the value of "output" is an array, its shape gives the output dimension,
-otherwise it is given by the length of "axes" for the coordinate system with the name of the "output".
+Input and output dimensionality may be determined by the value of the `input` and `output` fields, respectively.
+If the value of `input` is an array, its shape gives the input dimension,
+otherwise it is given by the length of `axes` for the coordinate system with the name of the `input`.
+If the value of `output` is an array, its shape gives the output dimension,
+otherwise it is given by the length of `axes` for the coordinate system with the name of the `output`.
#### identity
(identity-md)=
From d74cd540d5973e191e745bb16a9e4c41e16fd3da Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 10:04:34 +0200
Subject: [PATCH 17/47] update transformation types metadata
---
ngff_spec/specification.md | 417 ++++++++++++++++++++++---------------
1 file changed, 245 insertions(+), 172 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 083db7d5..08a32fe2 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -655,9 +655,12 @@ otherwise it is given by the length of `axes` for the coordinate system with the
(identity-md)=
`identity` transformations map input coordinates to output coordinates without modification.
-The position of the ith axis of the output coordinate system is set to the position of the ith axis of the input coordinate system.
+The position of the i-th axis of the output coordinate system
+is set to the position of the ith axis of the input coordinate system.
`identity` transformations are invertible.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+
````{admonition} Example
```{literalinclude} examples/transformations/identity.json
@@ -676,12 +679,16 @@ y = j
#### mapAxis
(mapAxis-md)=
-`mapAxis` transformations describe axis permutations as a mapping of axis names.
-Transformations MUST include a `mapAxis` field whose value is an object, all of whose values are strings.
-If the object contains `"x":"i"`, then the transform sets the value of the output coordinate for axis "x" to the value of the coordinate of input axis "i" (think `x = i`).
-For every axis in its output coordinate system, the `mapAxis` MUST have a corresponding field.
-For every value of the object there MUST be an axis of the input coordinate system with that name.
-Note that the order of the keys could be reversed.
+`mapAxis` transformations describe axis permutations as a transpose vector of integers.
+Transformations MUST include a `mapAxis` field
+whose value is an array of integers that specifies the new ordering in terms of indices of the old order.
+The length of the array MUST equal the number of dimensions in both the input and output coordinate systems.
+Each integer in the array MUST be a valid zero-based index into the input coordinate system's axes
+(i.e., between 0 and N-1 for an N-dimensional input).
+Each index MUST appear exactly once in the array.
+The value at position `i` in the array indicates which input axis becomes the `i`-th output axis.
+
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
````{admonition} Example
@@ -731,16 +738,19 @@ z = b
`translation` transformations are special cases of affine transformations.
When possible, a translation transformation should be preferred to its equivalent affine.
-Input and output dimensionality MUST be identical and MUST equal the the length of the "translation" array (N).
+Input and output dimensionality MUST be identical
+and MUST equal the the length of the "translation" array (N).
`translation` transformations are invertible.
-
- - path
- - The path to a zarr-array containing the translation parameters.
- The array at this path MUST be 1D, and its length MUST be `N`.
- - scale
- - The scale parameters stored as a JSON list of numbers. The list MUST have length `N`.
-
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+
+path
+: The path to a zarr-array containing the translation parameters.
+The array at this path MUST be 1D, and its length MUST be `N`.
+
+translation
+: The translation parameters stored as a JSON list of numbers.
+The list MUST have length `N`.
````{admonition} Example
@@ -761,16 +771,20 @@ y = j - 1.42
`scale` transformations are special cases of affine transformations.
When possible, a scale transformation SHOULD be preferred to its equivalent affine.
-Input and output dimensionality MUST be identical and MUST equal the the length of the "scale" array (N).
-Values in the `scale` array SHOULD be non-zero; in that case, `scale` transformations are invertible.
+Input and output dimensionality MUST be identical
+and MUST equal the the length of the "scale" array (N).
+Values in the `scale` array SHOULD be non-zero;
+in that case, `scale` transformations are invertible.
-
- - path
- - The path to a zarr-array containing the scale parameters.
- The array at this path MUST be 1D, and its length MUST be `N`.
- - scale
- - The scale parameters stored as a JSON list of numbers. The list MUST have length `N`.
-
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+
+path
+: The path to a zarr-array containing the scale parameters.
+The array at this path MUST be 1D, and its length MUST be `N`.
+
+scale
+: The scale parameters are stored as a JSON list of numbers.
+The list MUST have length `N`.
````{admonition} Example
@@ -789,19 +803,23 @@ y = 2 * j
#### affine
(affine-md)=
-`affine`s are [matrix transformations](#matrix) from N-dimensional inputs to M-dimensional outputs
-are represented as the upper `(M)x(N+1)` sub-matrix of a `(M+1)x(N+1)` matrix in
-[homogeneous coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates) (see examples).
-This transformation type may be (but is not necessarily) invertible when `N` equals `M`.
+`affine`s are [matrix transformations](#matrix-transformations) from N-dimensional inputs to M-dimensional outputs.
+They are represented as the upper `(M)x(N+1)` sub-matrix of a `(M+1)x(N+1)` matrix in [homogeneous
+coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates) (see examples).
+This transformation type may be (but is not necessarily) invertible
+when `N` equals `M`.
The matrix MUST be stored as a 2D array either as json or as a zarr array.
-
- - path
- - The path to a zarr-array containing the affine parameters.
- The array at this path MUST be 2D whose shape MUST be `M x (N+1)`.
- - affine
- - The affine parameters stored in JSON. The matrix MUST be stored as 2D nested array where the outer array MUST be length
- `M` and the inner arrays MUST be length `N+1`.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+
+path
+: The path to a zarr-array containing the affine parameters.
+The array at this path MUST be 2D whose shape MUST be `(M)x(N+1)`.
+
+affine
+: The affine parameters stored in JSON.
+The matrix MUST be stored as 2D nested array
+where the outer array MUST be length `M` and the inner arrays MUST be length `N+1`.
````{admonition} Example
A 2D-2D example:
@@ -863,20 +881,24 @@ where the last row `[0 0 1]` is omitted in the JSON representation.
#### rotation
(rotation-md)=
-`rotation`s are [matrix transformations](#matrix-trafo-md) that are special cases of affine transformations.
+`rotation`s are [matrix transformations](#matrix-transformations) that are special cases of affine transformations.
When possible, a rotation transformation SHOULD be preferred to its equivalent affine.
Input and output dimensionality (N) MUST be identical.
-Rotations are stored as `NxN` matrices, see below, and MUST have determinant equal to one, with orthonormal rows and columns.
+Rotations are stored as `NxN` matrices, see below,
+and MUST have determinant equal to one, with orthonormal rows and columns.
The matrix MUST be stored as a 2D array either as json or in a zarr array.
`rotation` transformations are invertible.
-
- - path
- - The path to an array containing the affine parameters.
- The array at this path MUST be 2D whose shape MUST be `N x N`.
- - rotation
- - The parameters stored in JSON. The matrix MUST be stored as a 2D nested array where the outer array MUST be length `N`
- and the inner arrays MUST be length `N`.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+
+path
+: The path to an array containing the affine parameters.
+The array at this path MUST be 2D whose shape MUST be `N x N`.
+
+rotation
+: The parameters stored in JSON.
+The matrix MUST be stored as a 2D nested array where the outer array MUST be length `N`
+and the inner arrays MUST be length `N`.
````{admonition} Example
A 2D example
@@ -896,16 +918,23 @@ y = 1*i + 0*j
#### inverseOf
(inverseOf-md)=
-An `inverseOf` transformation contains another transformation (often non-linear),
-and indicates that transforming points from output to input coordinate systems is possible using the contained transformation.
-Transforming points from the input to the output coordinate systems requires the inverse of the contained transformation (if it exists).
+An `inverseOf` transformation contains another transformation, which is often non-linear.
+It indicates that transforming points from output to input coordinate systems
+is possible using the contained transformation.
+
+The `input` and `output` fields MAY be omitted for `inverseOf` transformations
+if those fields may be omitted for the transformation it wraps.
```{note}
-Software libraries that perform image registration often return the transformation from fixed image coordinates to moving image coordinates,
+Software libraries that perform image registration
+often return the transformation from fixed (output) image coordinates to moving (input) image coordinates,
because this "inverse" transformation is most often required when rendering the transformed moving image.
Results such as this may be enclosed in an `inverseOf` transformation.
-This enables the "outer" coordinate transformation to specify the moving image coordinates as `input` and fixed image coordinates as `output`,
+This enables the "outer" coordinate transformation to specify the moving image coordinates
+as `input` and fixed image coordinates as `output`,
a choice that many users and developers find intuitive.
+At the same time, registration libraries can interpret the wrapped, inverted transformation
+as the correct corresponding transformation from fixed (output) to moving (input) coordinates.
```
````{admonition} Example
@@ -927,6 +956,9 @@ Next, apply the second transformation to the result.
Repeat until every transformation has been applied.
The output of the last transformation is the result of the sequence.
+A sequence transformation MUST NOT be part of another sequence transformation.
+The `input` and `output` fields MUST be included for sequence transformations.
+
````{note}
Considering transformations as functions of points,
@@ -941,24 +973,8 @@ f2(f1(f0(x)))
````
-The transformations included in the `transformations` array may omit their `input` and `output` fields
-under the conditions outlined below:
-
-- The `input` and `output` fields MAY be omitted for the following transformation types:
- - `identity`, `scale`, `translation`, `rotation`, `affine`, `displacements`, `coordinates`
-- The `input` and `output` fields MAY be omitted for `inverseOf` transformations if those fields may be omitted for the
- transformation it wraps
-- The `input` and `output` fields MAY be omitted for `bijection` transformations if the fields may be omitted for
- both its `forward` and `inverse` transformations
-- The `input` and `output` fields MAY be omitted for `sequence` transformations if the fields may be omitted for
- all transformations in the sequence after flattening the nested sequence lists.
-- The `input` and `output` fields MUST be included for transformations of type: `mapAxis`, and `byDimension`, and
- under all other conditions.
-
-
- - transformations
- - A non-empty array of transformations.
-
+transformations
+: A non-empty array of transformations.
````{admonition} Example
@@ -991,72 +1007,35 @@ and treating it either as a position directly (`coordinates`)
or a displacement of the input point (`displacements`).
These transformation types refer to an array at location specified by the `"path"` parameter.
-The input and output coordinate systems for these transformations
-("input / output coordinate systems")
+The input and output coordinate systems for these transformations ("input / output coordinate systems")
constrain the array size and the coordinate system metadata for the array ("field coordinate system").
-- If the input coordinate system has `N` axes, the array at location path MUST have `N+1` dimensions
-- The field coordinate system MUST contain an axis identical to every axis of its input coordinate system in the same order.
-- The field coordinate system MUST contain an axis with type `coordinate` or `displacement` respectively for transformations of type `coordinates` or `displacements`.
- - This SHOULD be the last axis (contiguous on disk when c-order).
-- If the output coordinate system has `M` axes, the length of the array along the `coordinate`/`displacement` dimension MUST be of length `M`.
-
-The `i`th value of the array along the `coordinate` or `displacement` axis refers to the coordinate or displacement of the `i`th output axis.
-See the example below.
-
-````{admonition} Example
-
-In this example, the array located at `"displacementField"` MUST have three dimensions.
-One dimension MUST correspond to an axis with `type : displacement` (in this example, the last dimension),
-the other two dimensions MUST be axes that are identical to the axes of the `"in"` coordinate system.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
-```json
-"coordinateSystems" : [
- { "name" : "in", "axes" : [{"name" : "y"}, {"name":"x"}] },
- { "name" : "out", "axes" : [{"name" : "y"}, {"name":"x"}] }
-],
-"coordinateTransformations" : [
- {
- "type": "displacements",
- "input" : "in",
- "output" : "out",
- "path" : "displacementField"
- }
-]
-```
+* If the input coordinate system has `N` axes,
+ the array at location path MUST have `N+1` dimensions
+* The field coordinate system MUST contain an axis identical to every axis
+ of its input coordinate system in the same order.
+* The field coordinate system MUST contain an axis with type `coordinate` or `displacement`, respectively,
+ for transformations of type `coordinates` or `displacements`.
+ * This SHOULD be the last axis (contiguous on disk when c-order).
+* If the output coordinate system has `M` axes,
+ the length of the array along the `coordinate`/`displacement` dimension MUST be of length `M`.
-The metadata at location `"displacementField"` should have a coordinate system such as:
-
-```json
-"coordinateSystems" : [
- { "name" : "in", "axes" : [
- {"name":"y"}, {"name":"x"},
- {"name":"d", "type":"displacement", "discrete":true} ]
- }
-]
-```
-
-Indexing into this array using c-order, for spatial positions `y` and `x`, the y- and x-displacements would be given by:
-
-```
-y_displacement = displacementField[y][x][0]
-x_displacement = displacementField[y][x][1]
-```
-
-I.e. the y-displacement is first, because the y-axis is the first element of the input and output coordinate systems.
-
-````
+The `i`th value of the array along the `coordinate` or `displacement` axis refers to the coordinate or displacement
+of the `i`th output axis. See the example below.
`coordinates` and `displacements` transformations are not invertible in general,
but implementations MAY approximate their inverses.
-Metadata for these coordinate transforms have the following field:
+Metadata for these coordinate transforms have the following fields:
- path
- The location of the coordinate array in this (or another) container.
- interpolation
- - The `interpolation` attributes MAY be provided. It's value indicates
- the interpolation to use if transforming points not on the array's discrete grid.
+
- The
interpolation attributes MAY be provided.
+ It's value indicates the interpolation to use
+ if transforming points not on the array's discrete grid.
Values could be:
linear (default)
@@ -1065,11 +1044,17 @@ Metadata for these coordinate transforms have the following field:
-For both `coordinates` and `displacements`, the array data at referred to by `path` MUST define coordinate system and coordinate transform metadata:
-* Every axis name in the `coordinateTransform`'s `input` MUST appear in the coordinate system
-* The array dimension corresponding to the `coordinate` or `displacement` axis MUST have length equal to the number of dimensions of the `coordinateTransform` `output`
-* If the input coordinate system `N` axes, then the array data at `path` MUST have `(N + 1)` dimensions.
+For both `coordinates` and `displacements`,
+the array data at referred to by `path` MUST define coordinate system
+and coordinate transform metadata:
+
+* Every axis name in the `coordinateTransform`'s `input`
+ MUST appear in the coordinate system.
+* The array dimension corresponding to the `coordinate` or `displacement` axis
+ MUST have length equal to the number of dimensions of the `coordinateTransform` `output`
+* If the input coordinate system `N` axes,
+ then the array data at `path` MUST have `(N + 1)` dimensions.
* SHOULD have a `name` identical to the `name` of the corresponding `coordinateTransform`.
For `coordinates`:
@@ -1083,6 +1068,7 @@ For `displacements`:
* the shape of the array along the "displacement" axis must be exactly `N`
* `input` and `output` MUST have an equal number of dimensions.
+````{admonition} Example
For example, in 1D:
```json
{
@@ -1126,8 +1112,9 @@ x =
else if ( i >= 0.5 and i < 1.5 ) 9
else if ( i >= 1.5 ) 0
```
+````
-
+````{admonition} Example
A 1D example displacement field:
```json
{
@@ -1172,18 +1159,68 @@ The transformation specifies linear interpolation,
which in this case yields `(0.5 * -1) + (0.5 * 0) = -0.5`.
That value gives us the displacement of the input point,
hence the output is `1.0 + (-0.5) = 0.5`.
+````
+
+````{admonition} Example
+
+In this example, the array located at `"displacementField"` MUST have three dimensions.
+One dimension MUST correspond to an axis with `type : displacement` (in this example, the last dimension),
+the other two dimensions MUST be axes that are identical to the axes of the `"in"` coordinate system.
+
+```json
+"coordinateSystems" : [
+ { "name" : "in", "axes" : [{"name" : "y"}, {"name":"x"}] },
+ { "name" : "out", "axes" : [{"name" : "y"}, {"name":"x"}] }
+],
+"coordinateTransformations" : [
+ {
+ "type": "displacements",
+ "input" : "in",
+ "output" : "out",
+ "path" : "displacementField"
+ }
+]
+```
+
+The metadata at location `"displacementField"` should have a coordinate system such as:
+
+```json
+"coordinateSystems" : [
+ { "name" : "in", "axes" : [
+ {"name":"y"}, {"name":"x"},
+ {"name":"d", "type":"displacement", "discrete":true} ]
+ }
+]
+```
+
+Indexing into this array using c-order, for spatial positions `y` and `x`, the y- and x-displacements would be given by:
+
+```
+y_displacement = displacementField[y][x][0]
+x_displacement = displacementField[y][x][1]
+```
+
+I.e. the y-displacement is first, because the y-axis is the first element of the input and output coordinate systems.
+
+````
#### byDimension
(byDimension-md)=
-`byDimension` transformations build a high dimensional transformation using lower dimensional transformations on subsets of dimensions.
+`byDimension` transformations build a high dimensional transformation
+using lower dimensional transformations on subsets of dimensions.
+The `input` and `output` fields MUST always be included for this transformations type.
- transformations
- - A list of transformations, each of which applies to a (non-strict) subset of input and output dimensions (axes).
- The values of `input` and `output` fields MUST be an array of strings.
- Every axis name in `input` MUST correspond to a name of some axis in this parent object's `input` coordinate system.
- Every axis name in the parent byDimension's `output` MUST appear in exactly one of its child transformations' `output`.
+
- Each child transformation MUST contain
input_axes and output_axes fields
+ whose values are arrays of strings.
+ Every axis name in a child transformation's input_axes
+ MUST correspond to a name of some axis in this parent object's input coordinate system.
+ Every axis name in the parent byDimension's output coordinate system
+ MUST appear in exactly one child transformation's output_axes array.
+ Each child transformation's input_axes and output_axes arrays
+ MUST have the same length as that transformation's parameter arrays.
@@ -1236,17 +1273,21 @@ This transformation is invalid because the output axis `x` appears in more than
#### bijection
(bijection-md)=
-A bijection transformation is an invertible transformation
-in which both the `forward` and `inverse` transformations are explicitly defined.
+A bijection transformation is an invertible transformation in
+which both the `forward` and `inverse` transformations are explicitly defined.
Each direction SHOULD be a transformation type that is not closed-form invertible.
-Its' input and output spaces MUST have equal dimension.
-The input and output dimensions for the both the forward and inverse transformations MUST match bijection's input and output space dimensions.
+Its input and output spaces MUST have equal dimension.
+The input and output dimensions for the both the forward and inverse transformations
+MUST match bijection's input and output space dimensions.
`input` and `output` fields MAY be omitted for the `forward` and `inverse` transformations,
in which case the `forward` transformation's `input` and `output` are understood to match the bijection's,
and the `inverse` transformation's `input` (`output`) matches the bijection's `output` (`input`),
see the example below.
+The `input` and `output` fields MAY be omitted for `bijection` transformations
+if the fields may be omitted for both its `forward` and `inverse` transformations
+
Practically, non-invertible transformations have finite extents,
so bijection transforms should only be expected to be correct / consistent for points that fall within those extents.
It may not be correct for any point of appropriate dimensionality.
@@ -1269,60 +1310,92 @@ the input and output of the `forward` and `inverse` transformations are understo
## "multiscales" metadata
(multiscales-md)=
-Metadata about an image can be found under the "multiscales" key in the group-level OME-Zarr Metadata.
-Here, image refers to 2 to 5 dimensional data representing image or volumetric data with optional time or channel axes.
+Metadata about an image can be found under the `multiscales` key in the group-level OME-Zarr Metadata.
+Here, "image" refers to 2 to 5 dimensional data representing image
+or volumetric data with optional time or channel axes.
It is stored in a multiple resolution representation.
-"multiscales" contains a list of dictionaries where each entry describes a multiscale image.
-
-Each "multiscales" dictionary MUST contain the field "coordinateSystems", see [coordinateSystems metadata](#), with the following constraints.
-The length of "axes" must be between 2 and 5 and MUST be equal to the dimensionality of the zarr arrays storing the image data (see "datasets:path").
-The "axes" MUST contain 2 or 3 entries of "type:space" and MAY contain one additional entry of "type:time" and MAY contain one additional entry of "type:channel" or a null / custom type.
-The order of the entries MUST correspond to the order of dimensions of the zarr arrays.
-In addition, the entries MUST be ordered by "type" where the "time" axis must come first (if present), followed by the "channel" or custom axis (if present) and the axes of type "space".
-If there are three spatial axes where two correspond to the image plane ("yx") and images are stacked along the other (anisotropic) axis ("z"), the spatial axes SHOULD be ordered as "zyx".
-
-Each "multiscales" dictionary MUST contain the field "datasets",
+`multiscales` contains a list of dictionaries where each entry describes a multiscale image.
+
+Each `multiscales` dictionary MUST contain the field "coordinateSystems",
+whose value is an array containing valid coordinate system metadata
+(see [coordinate systems](#coordinatesystems-metadata)).
+The last entry of this array is the "default" coordinate system
+and MUST contain transformations from array to physical coordinates.
+It should be used for viewing and processing unless a use case dictates otherwise.
+It will generally be a representation of the image in its native physical coordinate system.
+
+The following MUST hold for all coordinate systems.
+The length of "axes" must be between 2 and 5
+and MUST be equal to the dimensionality of the Zarr arrays storing the image data (see "datasets:path").
+The "axes" MUST contain 2 or 3 entries of "type:space"
+and MAY contain one additional entry of "type:time"
+and MAY contain one additional entry of "type:channel" or a null / custom type.
+The order of the entries MUST correspond to the order of dimensions of the Zarr arrays.
+In addition, the entries MUST be ordered by "type" where the "time" axis must come first (if present),
+followed by the "channel" or custom axis (if present) and the axes of type "space".
+If there are three spatial axes where two correspond to the image plane ("yx")
+and images are stacked along the other (anisotropic) axis ("z"),
+the spatial axes SHOULD be ordered as "zyx".
+
+Each `multiscales` dictionary MUST contain the field `datasets`,
which is a list of dictionaries describing the arrays storing the individual resolution levels.
-Each dictionary in "datasets" MUST contain the field "path",
-whose value contains the path to the array for this resolution relative to the current zarr group.
-The "path"s MUST be ordered from largest (i.e. highest resolution) to smallest.
-
-Each "datasets" dictionary MUST have the same number of dimensions and MUST NOT have more than 5 dimensions.
-The number of dimensions and order MUST correspond to number and order of "axes".
-Each dictionary in "datasets" MUST contain the field "coordinateTransformations",
-which contains a list of transformations that map the data coordinates to the physical coordinates
-(as specified by "axes") for this resolution level.
-The transformations are defined according to [coordinateTransformations metadata](#trafo-md).
-
-They MUST contain exactly one `scale` transformation that specifies the pixel size in physical units or time duration.
+Each dictionary in `datasets` MUST contain the field `path`,
+whose value is a string containing the path to the Zarr array for this resolution relative to the current Zarr group.
+The `path`s MUST be ordered from largest (i.e. highest resolution) to smallest.
+Every Zarr array referred to by a `path` MUST have the same number of dimensions
+and MUST NOT have more than 5 dimensions.
+The number of dimensions and order MUST correspond to number and order of `axes`.
+
+Each dictionary in `datasets` MUST contain the field `coordinateTransformations`,
+whose value is a list of dictionaries that define a transformation
+that maps Zarr array coordinates for this resolution level to the "default" coordinate system
+(the last entry of the `coordinateSystems` array).
+The transformation is defined according to [transformations metadata](#transformation-types).
+The transformation MUST take as input points in the array coordinate system
+corresponding to the Zarr array at location `path`.
+The value of "input" SHOULD equal the value of `path`,
+but implementations should always treat the value of `input` as if it were equal to the value of `path`.
+The value of the transformation’s `output` MUST be the name of the default [coordinate system](#coordinatesystems-metadata).
+
+This transformation MUST be one of the following:
+
+* A single scale or identity transformation
+* A sequence transformation containing one scale and one translation transformation.
+
+In these cases, the scale transformation specifies the pixel size in physical units or time duration.
If scaling information is not available or applicable for one of the axes,
-the value MUST express the scaling factor between the current resolution and the first resolution for the given axis,
+the value MUST express the scaling factor between the current resolution
+and the first resolution for the given axis,
defaulting to 1.0 if there is no downsampling along the axis.
-It MAY contain exactly one `translation` that specifies the offset from the origin in physical units.
-If `translation` is given it MUST be listed after `scale` to ensure that it is given in physical coordinates.
-The requirements (only `scale` and `translation`, restrictions on order) are in place to provide a simple mapping from data coordinates to physical coordinates
-while being compatible with the general transformation spec.
+This is strongly recommended
+so that the the "default" coordinate system of the imageavoids more complex transformations.
-Each "multiscales" dictionary MAY contain the field "coordinateTransformations",
+If applications require additional transformations,
+each `multiscales` dictionary MAY contain the field `coordinateTransformations`,
describing transformations that are applied to all resolution levels in the same manner.
-The transformations MUST follow the same rules about allowed types, order, etc. as in "datasets:coordinateTransformations"
-and are applied after them.
-They can for example be used to specify the `scale` for a dimension that is the same for all resolutions.
+The value of `input` MUST equal the name of the "default" coordinate system.
+The value of `output` MUST be the name of the output coordinate System
+which is different from the "default" coordinate system.
+
+Each `multiscales` dictionary SHOULD contain the field `name`.
-Each "multiscales" dictionary SHOULD contain the field "name".
+Each `multiscales` dictionary SHOULD contain the field `type`,
+which gives the type of downscaling method used to generate the multiscale image pyramid.
+It SHOULD contain the field "metadata",
+which contains a dictionary with additional information about the downscaling method.
-Each "multiscales" dictionary SHOULD contain the field "type", which gives the type of downscaling method used to generate the multiscale image pyramid.
-It SHOULD contain the field "metadata", which contains a dictionary with additional information about the downscaling method.
````{admonition} Example
+A complete example of json-file for a 5D (TCZYX) multiscales with 3 resolution levels could look like this:
```{literalinclude} examples/multiscales_strict/multiscales_example.json
:language: json
```
````
If only one multiscale is provided, use it.
-Otherwise, the user can choose by name, using the first multiscale as a fallback:
+Otherwise, the user can choose by name,
+using the first multiscale as a fallback:
```python
datasets = []
From 3ff61cffb52899224b0faca52c2a4fe8ff19d7b8 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 10:14:17 +0200
Subject: [PATCH 18/47] harmonize link syntax
---
ngff_spec/specification.md | 46 ++++++++++++++++++++------------------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 08a32fe2..230e14f5 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -159,6 +159,7 @@ The OME-Zarr Metadata version MUST be consistent within a hierarchy.
```
### "coordinateSystems" metadata
+(coordinate-systems-md)=
A "coordinate system" is a collection of "axes" / dimensions with a name.
Every coordinate system:
@@ -270,12 +271,12 @@ The `dimension_names` must be unique and non-null.
For example, if `0/zarr.json` contains:
-```json
+```jsonc
{
"zarr_format": 3,
"node_type": "array",
"shape": [4, 3, 5],
- ...
+ //...
}
```
Then `dim_0` has length 4, `dim_1` has length 3, and `dim_2` has length 5.
@@ -337,8 +338,7 @@ series.ome.zarr # One converted fileset from bioformats2raw
```
### bf2raw-attributes
-
-(bf2raw-attributes)=
+(bf2raw-attributes-md)=
The OME-Zarr Metadata in the top-level `zarr.json` file must contain the `bioformats2raw.layout` key:
@@ -351,6 +351,7 @@ but the "plate" key MUST also be present, takes precedence and parsing of such d
It is not possible to mix collections of images with plates at present.
```{literalinclude} examples/bf2raw/plate.json
+:language: json
```
The OME-Zarr Metadata in the `zarr.json` file within the OME group may contain the "series" key:
@@ -434,10 +435,10 @@ Conforming readers:
Coordinate transformations can be stored in multiple places to reflect different usecases.
- Multiscale transformations represent a special case of transformations
- and are explained [below](#multiscales-metadata).
+ and are explained [below](#multiscales-md).
- Additional transformations for single images MUST be stored under a field `coordinateTransformations`
in the multiscales dictionaries.
- This `coordinateTransformations` field MUST contain a list of valid [transformations](#transformation-types).
+ This `coordinateTransformations` field MUST contain a list of valid [transformations](#trafo-types-md).
- Transformations between two or more images MUST be stored in the attributes of a parent zarr group.
For transformations that store data or parameters in a zarr array,
those zarr arrays SHOULD be stored in a zarr group `coordinateTransformations`.
@@ -549,7 +550,7 @@ The `output` field can be a `path` to an output image or the name of a `coordina
If the names of `input` or `output` can be both a `path` or the name of a `coordinateSystem`, `path` MUST take precedent.
If unused, the `input` and `output` fields MAY be null.
-For usage in multiscales, see [multiscales section](#multiscales-metadata) for details.
+For usage in multiscales, see [multiscales section](#multiscales-md) for details.
Transformations in the `transformations` list of a `byDimensions` transformation
MUST provide `input` and `output` as arrays of strings
@@ -592,15 +593,16 @@ the `inverseOf` transformation type, for example:
Implementations SHOULD be able to compute and apply
the inverse of some coordinate transformations when they are computable
-in closed-form (as the [Transformation types](#transformation-types) section below indicates).
+in closed-form (as the [Transformation types](#trafo-types-md) section below indicates).
If an operation is requested that requires
the inverse of a transformation that can not be inverted in closed-form,
implementations MAY estimate an inverse,
or MAY output a warning that the requested operation is unsupported.
#### Matrix transformations
+(matrix-trafo-md)=
-Two transformation types ([affine](#affine) and [rotation](#rotation)) are parametrized by matrices.
+Two transformation types ([affine](#affine-md) and [rotation](#rotation-md)) are parametrized by matrices.
Matrices are applied to column vectors that represent points in the input coordinate system.
The first and last axes in a coordinate system correspond to the top and bottom entries in the column vector, respectively.
Matrices are stored as two-dimensional arrays, either as json or in a zarr array.
@@ -659,7 +661,7 @@ The position of the i-th axis of the output coordinate system
is set to the position of the ith axis of the input coordinate system.
`identity` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
````{admonition} Example
@@ -688,7 +690,7 @@ Each integer in the array MUST be a valid zero-based index into the input coordi
Each index MUST appear exactly once in the array.
The value at position `i` in the array indicates which input axis becomes the `i`-th output axis.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
````{admonition} Example
@@ -742,7 +744,7 @@ Input and output dimensionality MUST be identical
and MUST equal the the length of the "translation" array (N).
`translation` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
path
: The path to a zarr-array containing the translation parameters.
@@ -776,7 +778,7 @@ and MUST equal the the length of the "scale" array (N).
Values in the `scale` array SHOULD be non-zero;
in that case, `scale` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
path
: The path to a zarr-array containing the scale parameters.
@@ -803,14 +805,14 @@ y = 2 * j
#### affine
(affine-md)=
-`affine`s are [matrix transformations](#matrix-transformations) from N-dimensional inputs to M-dimensional outputs.
+`affine`s are [matrix transformations](#matrix-trafo-md) from N-dimensional inputs to M-dimensional outputs.
They are represented as the upper `(M)x(N+1)` sub-matrix of a `(M+1)x(N+1)` matrix in [homogeneous
coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates) (see examples).
This transformation type may be (but is not necessarily) invertible
when `N` equals `M`.
The matrix MUST be stored as a 2D array either as json or as a zarr array.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
path
: The path to a zarr-array containing the affine parameters.
@@ -881,7 +883,7 @@ where the last row `[0 0 1]` is omitted in the JSON representation.
#### rotation
(rotation-md)=
-`rotation`s are [matrix transformations](#matrix-transformations) that are special cases of affine transformations.
+`rotation`s are [matrix transformations](#matrix-trafo-md) that are special cases of affine transformations.
When possible, a rotation transformation SHOULD be preferred to its equivalent affine.
Input and output dimensionality (N) MUST be identical.
Rotations are stored as `NxN` matrices, see below,
@@ -889,7 +891,7 @@ and MUST have determinant equal to one, with orthonormal rows and columns.
The matrix MUST be stored as a 2D array either as json or in a zarr array.
`rotation` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
path
: The path to an array containing the affine parameters.
@@ -1010,7 +1012,7 @@ These transformation types refer to an array at location specified by the `"path
The input and output coordinate systems for these transformations ("input / output coordinate systems")
constrain the array size and the coordinate system metadata for the array ("field coordinate system").
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence) transformation.
+The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
* If the input coordinate system has `N` axes,
the array at location path MUST have `N+1` dimensions
@@ -1319,7 +1321,7 @@ It is stored in a multiple resolution representation.
Each `multiscales` dictionary MUST contain the field "coordinateSystems",
whose value is an array containing valid coordinate system metadata
-(see [coordinate systems](#coordinatesystems-metadata)).
+(see [coordinate systems](#coordinate-systems-md)).
The last entry of this array is the "default" coordinate system
and MUST contain transformations from array to physical coordinates.
It should be used for viewing and processing unless a use case dictates otherwise.
@@ -1351,12 +1353,12 @@ Each dictionary in `datasets` MUST contain the field `coordinateTransformations`
whose value is a list of dictionaries that define a transformation
that maps Zarr array coordinates for this resolution level to the "default" coordinate system
(the last entry of the `coordinateSystems` array).
-The transformation is defined according to [transformations metadata](#transformation-types).
+The transformation is defined according to [transformations metadata](#trafo-types-md).
The transformation MUST take as input points in the array coordinate system
corresponding to the Zarr array at location `path`.
The value of "input" SHOULD equal the value of `path`,
but implementations should always treat the value of `input` as if it were equal to the value of `path`.
-The value of the transformation’s `output` MUST be the name of the default [coordinate system](#coordinatesystems-metadata).
+The value of the transformation’s `output` MUST be the name of the default [coordinate system](#coordinate-systems-md).
This transformation MUST be one of the following:
@@ -1663,6 +1665,6 @@ NB: some parts of the specification don't obey this convention as they were adde
but they should be updated in due course.
# Implementations
-(implementations)=
+(implementations-md)=
See [Tools](https://ngff.openmicroscopy.org/tools/index.html).
From 004ddf45658b50f04401069566959aa66f65060c Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 13:12:54 +0200
Subject: [PATCH 19/47] removed deprecated statement about `byDimension`
transform
---
ngff_spec/specification.md | 5 -----
1 file changed, 5 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 230e14f5..3e775336 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -552,11 +552,6 @@ If unused, the `input` and `output` fields MAY be null.
For usage in multiscales, see [multiscales section](#multiscales-md) for details.
-Transformations in the `transformations` list of a `byDimensions` transformation
-MUST provide `input` and `output` as arrays of strings
-corresponding to axis names of the parent transformation's input and output coordinate systems
-(see below for details).
-
Coordinate transformations are functions of *points* in the input space to *points* in the output space.
We call this the "forward" direction.
Points are ordered lists of coordinates,
From 98dae149cd941cdea81899948ebec2ad93fe891c Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 21:12:51 +0200
Subject: [PATCH 20/47] harmonized indendations and json style
---
.../examples/coordSystems/arrayCoordSys.json | 16 +-
.../multiscales_example_relative.json | 144 +++++++++---------
.../examples/subspace/subspaceMultidim.json | 44 +++---
.../examples/subspace/subspacePermute.json | 46 +++---
.../examples/transformations/affine2d2d.json | 24 +--
.../examples/transformations/affine2d3d.json | 24 +--
.../examples/transformations/bijection.json | 32 ++--
.../transformations/bijection_verbose.json | 10 +-
.../transformations/byDimension1.json | 36 +++--
.../transformations/byDimensionInvalid1.json | 30 ++--
.../transformations/byDimensionInvalid2.json | 36 +++--
.../transformations/coordinates1d.json | 24 +--
.../transformations/displacement1d.json | 24 +--
.../examples/transformations/identity.json | 14 +-
.../examples/transformations/inverseOf.json | 30 ++--
.../examples/transformations/mapAxis1.json | 42 ++---
.../examples/transformations/mapAxis2.json | 42 ++---
.../examples/transformations/rotation.json | 24 +--
ngff_spec/examples/transformations/scale.json | 24 +--
.../examples/transformations/sequence.json | 32 ++--
.../transformations/sequenceSubspace1.json | 36 +++--
.../examples/transformations/translation.json | 24 +--
.../examples/transformations/xarrayLike.json | 36 +++--
ngff_spec/pre_build.py | 1 -
ngff_spec/specification.md | 140 +++++++++--------
25 files changed, 492 insertions(+), 443 deletions(-)
diff --git a/ngff_spec/examples/coordSystems/arrayCoordSys.json b/ngff_spec/examples/coordSystems/arrayCoordSys.json
index 812356f8..84b59755 100644
--- a/ngff_spec/examples/coordSystems/arrayCoordSys.json
+++ b/ngff_spec/examples/coordSystems/arrayCoordSys.json
@@ -1,10 +1,10 @@
{
- "arrayCoordinateSystem" : {
- "name" : "myDataArray",
- "axes" : [
- {"name": "k", "type": "array"},
- {"name": "j", "type": "array"},
- {"name": "i", "type": "array"}
- ]
- }
+ "arrayCoordinateSystem" : {
+ "name" : "myDataArray",
+ "axes" : [
+ {"name": "k", "type": "array"},
+ {"name": "j", "type": "array"},
+ {"name": "i", "type": "array"}
+ ]
+ }
}
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
index 1d1864e0..5b83bd4b 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
@@ -1,76 +1,76 @@
{
- "multiscales": [
+ "multiscales": [
+ {
+ "version": "0.5-dev",
+ "name": "example",
+ "coordinateSystems" : [
{
- "version": "0.5-dev",
- "name": "example",
- "coordinateSystems" : [
- {
- "name" : "exampleCoordinateSystem",
- "axes": [
- {"name": "t", "type": "time", "unit": "millisecond"},
- {"name": "c", "type": "channel"},
- {"name": "z", "type": "space", "unit": "micrometer"},
- {"name": "y", "type": "space", "unit": "micrometer"},
- {"name": "x", "type": "space", "unit": "micrometer"}
- ]
- },
- {
- "name" : "array_0",
- "axes": [
- {"name": "t", "type": "time", "unit": "millisecond"},
- {"name": "c", "type": "channel"},
- {"name": "z", "type": "space", "unit": "micrometer"},
- {"name": "y", "type": "space", "unit": "micrometer"},
- {"name": "x", "type": "space", "unit": "micrometer"}
- ]
- }
- ],
- "datasets": [
- {
- "path": "0",
- // the transformation of other arrays are defined relative to this, the highest resolution, array
- "coordinateTransformations": [{
- "type": "identity",
- "input": "/0",
- "output": "array_0"
- }]
- },
- {
- "path": "1",
- "coordinateTransformations": [{
- // the second scale level (downscaled by a factor of 2 relative to "0" in zyx)
- "type": "scale",
- "scale": [1, 1, 2, 2, 2],
- "input" : "/1",
- "output" : "array_0"
- }]
- },
- {
- "path": "2",
- "coordinateTransformations": [{
- // the third scale level (downscaled by a factor of 4 relative to "0" in zyx)
- "type": "scale",
- "scale": [1, 1, 4, 4, 4],
- "input" : "/2",
- "output" : "array_0"
- }]
- }
- ],
- "coordinateTransformations": [{
- // the time unit (0.1 milliseconds), the voxel size for all spatial axes of "0" (0.5 micrometers)
- "type": "scale",
- "scale": [0.1, 1.0, 0.5, 0.5, 0.5],
- "input" : "array_0",
- "output" : "exampleCoordinateSystem"
- }],
- "type": "gaussian",
- "metadata": {
- "description": "the fields in metadata depend on the downscaling implementation. Here, the parameters passed to the skimage function are given",
- "method": "skimage.transform.pyramid_gaussian",
- "version": "0.16.1",
- "args": "[true]",
- "kwargs": {"multichannel": true}
- }
+ "name" : "exampleCoordinateSystem",
+ "axes": [
+ {"name": "t", "type": "time", "unit": "millisecond"},
+ {"name": "c", "type": "channel"},
+ {"name": "z", "type": "space", "unit": "micrometer"},
+ {"name": "y", "type": "space", "unit": "micrometer"},
+ {"name": "x", "type": "space", "unit": "micrometer"}
+ ]
+ },
+ {
+ "name" : "array_0",
+ "axes": [
+ {"name": "t", "type": "time", "unit": "millisecond"},
+ {"name": "c", "type": "channel"},
+ {"name": "z", "type": "space", "unit": "micrometer"},
+ {"name": "y", "type": "space", "unit": "micrometer"},
+ {"name": "x", "type": "space", "unit": "micrometer"}
+ ]
+ }
+ ],
+ "datasets": [
+ {
+ "path": "0",
+ // the transformation of other arrays are defined relative to this, the highest resolution, array
+ "coordinateTransformations": [{
+ "type": "identity",
+ "input": "/0",
+ "output": "array_0"
+ }]
+ },
+ {
+ "path": "1",
+ "coordinateTransformations": [{
+ // the second scale level (downscaled by a factor of 2 relative to "0" in zyx)
+ "type": "scale",
+ "scale": [1, 1, 2, 2, 2],
+ "input" : "/1",
+ "output" : "array_0"
+ }]
+ },
+ {
+ "path": "2",
+ "coordinateTransformations": [{
+ // the third scale level (downscaled by a factor of 4 relative to "0" in zyx)
+ "type": "scale",
+ "scale": [1, 1, 4, 4, 4],
+ "input" : "/2",
+ "output" : "array_0"
+ }]
}
- ]
+ ],
+ "coordinateTransformations": [{
+ // the time unit (0.1 milliseconds), the voxel size for all spatial axes of "0" (0.5 micrometers)
+ "type": "scale",
+ "scale": [0.1, 1.0, 0.5, 0.5, 0.5],
+ "input" : "array_0",
+ "output" : "exampleCoordinateSystem"
+ }],
+ "type": "gaussian",
+ "metadata": {
+ "description": "the fields in metadata depend on the downscaling implementation. Here, the parameters passed to the skimage function are given",
+ "method": "skimage.transform.pyramid_gaussian",
+ "version": "0.16.1",
+ "args": "[true]",
+ "kwargs": {"multichannel": true}
+ }
+ }
+ ]
}
diff --git a/ngff_spec/examples/subspace/subspaceMultidim.json b/ngff_spec/examples/subspace/subspaceMultidim.json
index 566a4069..b2200a47 100644
--- a/ngff_spec/examples/subspace/subspaceMultidim.json
+++ b/ngff_spec/examples/subspace/subspaceMultidim.json
@@ -1,23 +1,23 @@
{
"coordinateSystems": [
- {
- "name": "in",
- "axes": [
- { "name": "0", "type": "array" },
- { "name": "1", "type": "array" },
- { "name": "2", "type": "array" },
- { "name": "3", "type": "array" },
- { "name": "4", "type": "array" }
- ]
- },
- {
- "name": "out",
- "axes": [
- { "name": "x", "type": "space" },
- { "name": "y", "type": "space" },
- { "name": "z", "type": "space" }
- ]
- }
+ {
+ "name": "in",
+ "axes": [
+ { "name": "0", "type": "array" },
+ { "name": "1", "type": "array" },
+ { "name": "2", "type": "array" },
+ { "name": "3", "type": "array" },
+ { "name": "4", "type": "array" }
+ ]
+ },
+ {
+ "name": "out",
+ "axes": [
+ { "name": "x", "type": "space" },
+ { "name": "y", "type": "space" },
+ { "name": "z", "type": "space" }
+ ]
+ }
],
"coordinateTransformations": [
{
@@ -29,14 +29,14 @@
{
"type": "mapAxis",
"mapAxis": { "0": "x", "2": "z" },
- "input": [ "0", "2" ],
- "output": [ "x", "z" ]
+ "input_axes": [ "0", "2" ],
+ "output_axes": [ "x", "z" ]
},
{
"type": "scale",
"scale": [ 2 ],
- "input": [ "1" ],
- "output": [ "y" ]
+ "input_axes": [ "1" ],
+ "output_axes": [ "y" ]
}
]
}
diff --git a/ngff_spec/examples/subspace/subspacePermute.json b/ngff_spec/examples/subspace/subspacePermute.json
index 26749751..4594e8c7 100644
--- a/ngff_spec/examples/subspace/subspacePermute.json
+++ b/ngff_spec/examples/subspace/subspacePermute.json
@@ -1,26 +1,26 @@
{
- "coordinateSystems" : [
- { "name" : "in", "axes" : [ {"name" : "i"}, {"name" : "j" } ]},
- { "name" : "out", "axes" : [ {"name" : "x"}, {"name" : "y" } ]}
- ],
- "coordinateTransformations" : [
- {
- "type" : "byDimension",
- "input" : "in",
- "output" : "out",
- "transformations" : [
- {
- "type": "identity",
- "input" : ["j"],
- "output" : ["x"]
- },
- {
- "type": "scale",
- "scale" : [2],
- "input" : ["i"],
- "output" : ["y"]
- }
- ]
+ "coordinateSystems" : [
+ { "name" : "in", "axes" : [ {"name" : "i"}, {"name" : "j" } ]},
+ { "name" : "out", "axes" : [ {"name" : "x"}, {"name" : "y" } ]}
+ ],
+ "coordinateTransformations" : [
+ {
+ "type" : "byDimension",
+ "input" : "in",
+ "output" : "out",
+ "transformations" : [
+ {
+ "type": "identity",
+ "input_axes" : ["j"],
+ "output_axes" : ["x"]
+ },
+ {
+ "type": "scale",
+ "scale" : [2],
+ "input_axes" : ["i"],
+ "output_axes" : ["y"]
}
- ]
+ ]
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/affine2d2d.json b/ngff_spec/examples/transformations/affine2d2d.json
index a4955d43..701d0a2e 100644
--- a/ngff_spec/examples/transformations/affine2d2d.json
+++ b/ngff_spec/examples/transformations/affine2d2d.json
@@ -1,14 +1,14 @@
{
- "coordinateSystems" : [
- { "name": "ji", "axes": [{"name": "j"}, {"name": "i"}] },
- { "name": "yx", "axes": [{"name": "y"}, {"name": "x"}] }
- ],
- "coordinateTransformations" : [
- {
- "type": "affine",
- "affine": [[1, 2, 3], [4, 5, 6]],
- "input": "ji",
- "output": "yx"
- }
- ]
+ "coordinateSystems" : [
+ { "name": "ji", "axes": [{"name": "j"}, {"name": "i"}] },
+ { "name": "yx", "axes": [{"name": "y"}, {"name": "x"}] }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type": "affine",
+ "affine": [[1, 2, 3], [4, 5, 6]],
+ "input": "ji",
+ "output": "yx"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/affine2d3d.json b/ngff_spec/examples/transformations/affine2d3d.json
index 588bdec5..50b4b82c 100644
--- a/ngff_spec/examples/transformations/affine2d3d.json
+++ b/ngff_spec/examples/transformations/affine2d3d.json
@@ -1,14 +1,14 @@
{
- "coordinateSystems": [
- { "name": "ij", "axes": [{"name": "i"}, {"name": "j"}] },
- { "name": "xyz", "axes": [{"name": "x"}, {"name": "y"}, {"name": "z"}] }
- ],
- "coordinateTransformations": [
- {
- "type": "affine",
- "affine": [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
- "input": "ij",
- "output": "xyz"
- }
- ]
+ "coordinateSystems": [
+ { "name": "ij", "axes": [{"name": "i"}, {"name": "j"}] },
+ { "name": "xyz", "axes": [{"name": "x"}, {"name": "y"}, {"name": "z"}] }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "affine",
+ "affine": [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ "input": "ij",
+ "output": "xyz"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/bijection.json b/ngff_spec/examples/transformations/bijection.json
index 7ee77062..5e2a9439 100644
--- a/ngff_spec/examples/transformations/bijection.json
+++ b/ngff_spec/examples/transformations/bijection.json
@@ -1,15 +1,21 @@
{
- "coordinateSystems" : [
- { "name": "src", "axes": [{"name": "j"}, {"name": "i"}] },
- { "name": "tgt", "axes": [{"name": "y"}, {"name": "x"}] }
- ],
- "coordinateTransformations" : [
- {
- "type": "bijection",
- "forward": { "type" : "coordinates", "path" : "forward_coordinates" },
- "inverse": { "type" : "coordinates", "path" : "inverse_coordinates" },
- "input": "src",
- "output": "tgt"
- }
- ]
+ "coordinateSystems" : [
+ { "name": "src", "axes": [{"name": "j"}, {"name": "i"}] },
+ { "name": "tgt", "axes": [{"name": "y"}, {"name": "x"}] }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type": "bijection",
+ "forward": {
+ "type" : "coordinates",
+ "path" : "forward_coordinates"
+ },
+ "inverse": {
+ "type" : "coordinates",
+ "path" : "inverse_coordinates"
+ },
+ "input": "src",
+ "output": "tgt"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/bijection_verbose.json b/ngff_spec/examples/transformations/bijection_verbose.json
index 56547fdc..dbf58c1b 100644
--- a/ngff_spec/examples/transformations/bijection_verbose.json
+++ b/ngff_spec/examples/transformations/bijection_verbose.json
@@ -1,7 +1,7 @@
{
- "type": "bijection",
- "forward": { "type" : "coordinates", "path" : "forward_coordinates", "input" : "src", "output" : "tgt" },
- "inverse": { "type" : "coordinates", "path" : "inverse_coordinates", "input" : "tgt", "output" : "src" },
- "input": "src",
- "output": "tgt"
+ "type": "bijection",
+ "forward": { "type" : "coordinates", "path" : "forward_coordinates", "input" : "src", "output" : "tgt" },
+ "inverse": { "type" : "coordinates", "path" : "inverse_coordinates", "input" : "tgt", "output" : "src" },
+ "input": "src",
+ "output": "tgt"
}
diff --git a/ngff_spec/examples/transformations/byDimension1.json b/ngff_spec/examples/transformations/byDimension1.json
index 3ade95e8..7c8de4d7 100644
--- a/ngff_spec/examples/transformations/byDimension1.json
+++ b/ngff_spec/examples/transformations/byDimension1.json
@@ -1,17 +1,27 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ] },
- { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ] }
- ],
- "coordinateTransformations": [
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ] },
+ { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ] }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "byDimension",
+ "input": "in",
+ "output": "out",
+ "transformations": [
{
- "type": "byDimension",
- "input": "in",
- "output": "out",
- "transformations": [
- { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["x"]},
- { "type": "scale", "scale": [2.0], "input": ["j"], "output": ["y"]}
- ]
+ "type": "translation",
+ "translation": [-1.0],
+ "input": ["i"],
+ "output": ["x"]
+ },
+ {
+ "type": "scale",
+ "scale": [2.0],
+ "input": ["j"],
+ "output": ["y"]
}
- ]
+ ]
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/byDimensionInvalid1.json b/ngff_spec/examples/transformations/byDimensionInvalid1.json
index 10498818..b1bdd052 100644
--- a/ngff_spec/examples/transformations/byDimensionInvalid1.json
+++ b/ngff_spec/examples/transformations/byDimensionInvalid1.json
@@ -1,17 +1,17 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ] },
- { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ] }
- ],
- "coordinateTransformations": [
- {
- "type": "byDimension",
- "input": "in",
- "output": "out",
- "transformations": [
- { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["z"]},
- { "type": "scale", "scale": [2.0], "input": ["0"], "output": ["y"]}
- ]
- }
- ]
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ] },
+ { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ] }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "byDimension",
+ "input": "in",
+ "output": "out",
+ "transformations": [
+ { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["z"]},
+ { "type": "scale", "scale": [2.0], "input": ["0"], "output": ["y"]}
+ ]
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/byDimensionInvalid2.json b/ngff_spec/examples/transformations/byDimensionInvalid2.json
index 3b38a467..b71f5f2f 100644
--- a/ngff_spec/examples/transformations/byDimensionInvalid2.json
+++ b/ngff_spec/examples/transformations/byDimensionInvalid2.json
@@ -1,17 +1,27 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ] },
- { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ] }
- ],
- "coordinateTransformations": [
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ] },
+ { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ] }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "byDimension",
+ "input": "in",
+ "output": "out",
+ "transformations": [
{
- "type": "byDimension",
- "input": "in",
- "output": "out",
- "transformations": [
- { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["x"]},
- { "type": "scale", "scale": [2.0], "input": ["i"], "output": ["x"]}
- ]
+ "type": "translation",
+ "translation": [-1.0],
+ "input_axes": ["i"],
+ "output_axes": ["x"]
+ },
+ {
+ "type": "scale",
+ "scale": [2.0],
+ "input_axes": ["i"],
+ "output_axes": ["x"]
}
- ]
+ ]
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/coordinates1d.json b/ngff_spec/examples/transformations/coordinates1d.json
index 314bc6fb..3dc8dd7b 100644
--- a/ngff_spec/examples/transformations/coordinates1d.json
+++ b/ngff_spec/examples/transformations/coordinates1d.json
@@ -1,14 +1,14 @@
{
- "coordinateSystems": [
- { "name": "i", "axes": [{"name": "i"}] },
- { "name": "x", "axes": [{"name": "x"}] }
- ],
- "coordinateTransformations": [{
- "name": "a coordinate field transform",
- "type": "coordinates",
- "path": "i2xCoordinates",
- "input": "i",
- "output": "x",
- "interpolation": "nearest"
- }]
+ "coordinateSystems": [
+ { "name": "input", "axes": [{"name": "i"}] },
+ { "name": "output", "axes": [{"name": "x"}] }
+ ],
+ "coordinateTransformations": [{
+ "name": "a coordinate field transform",
+ "type": "coordinates",
+ "path": "i2xCoordinates",
+ "input": "input",
+ "output": "output",
+ "interpolation": "nearest"
+ }]
}
diff --git a/ngff_spec/examples/transformations/displacement1d.json b/ngff_spec/examples/transformations/displacement1d.json
index 5db76446..95267c9a 100644
--- a/ngff_spec/examples/transformations/displacement1d.json
+++ b/ngff_spec/examples/transformations/displacement1d.json
@@ -1,14 +1,14 @@
{
- "coordinateSystems": [
- { "name": "i", "axes": [{"name": "i"}] },
- { "name": "x", "axes": [{"name": "x"}] }
- ],
- "coordinateTransformations": [{
- "name": "a displacement field transform",
- "type": "displacements",
- "path": "i2xCoordinates",
- "input": "i",
- "output": "x",
- "interpolation": "nearest"
- }]
+ "coordinateSystems": [
+ { "name": "input", "axes": [{"name": "i"}] },
+ { "name": "output", "axes": [{"name": "x"}] }
+ ],
+ "coordinateTransformations": [{
+ "name": "a displacement field transform",
+ "type": "displacements",
+ "path": "i2xCoordinates",
+ "input": "input",
+ "output": "output",
+ "interpolation": "nearest"
+ }]
}
diff --git a/ngff_spec/examples/transformations/identity.json b/ngff_spec/examples/transformations/identity.json
index 8de6d9d5..3edb6cb7 100644
--- a/ngff_spec/examples/transformations/identity.json
+++ b/ngff_spec/examples/transformations/identity.json
@@ -1,9 +1,9 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ]},
- { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ]}
- ],
- "coordinateTransformations": [
- { "type": "identity", "input": "in", "output": "out" }
- ]
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ]},
+ { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ]}
+ ],
+ "coordinateTransformations": [
+ { "type": "identity", "input": "in", "output": "out" }
+ ]
}
diff --git a/ngff_spec/examples/transformations/inverseOf.json b/ngff_spec/examples/transformations/inverseOf.json
index 6a94274c..4c77e9ea 100644
--- a/ngff_spec/examples/transformations/inverseOf.json
+++ b/ngff_spec/examples/transformations/inverseOf.json
@@ -1,17 +1,17 @@
{
- "coordinateSystems" : [
- { "name" : "moving", "axes" : [{"name" : "y-moving"}, {"name":"x-moving"}] },
- { "name" : "fixed", "axes" : [{"name" : "y-fixed"}, {"name":"x-fixed"}] }
- ],
- "coordinateTransformations" : [
- {
- "type": "inverseOf",
- "transformation" : {
- "type": "displacements",
- "path": "path/to/displacements"
- },
- "input" : "moving",
- "output" : "fixed"
- }
- ]
+ "coordinateSystems" : [
+ { "name" : "moving", "axes" : [{"name" : "y-moving"}, {"name":"x-moving"}] },
+ { "name" : "fixed", "axes" : [{"name" : "y-fixed"}, {"name":"x-fixed"}] }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type": "inverseOf",
+ "transformation" : {
+ "type": "displacements",
+ "path": "path/to/displacements"
+ },
+ "input" : "moving",
+ "output" : "fixed"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/mapAxis1.json b/ngff_spec/examples/transformations/mapAxis1.json
index 37d3c73c..6aeeca52 100644
--- a/ngff_spec/examples/transformations/mapAxis1.json
+++ b/ngff_spec/examples/transformations/mapAxis1.json
@@ -1,23 +1,23 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ]},
- { "name": "out1", "axes": [ {"name": "y"}, {"name": "x"} ]},
- { "name": "out2", "axes": [ {"name": "y"}, {"name": "x"} ]}
- ],
- "coordinateTransformations": [
- {
- "name": "equivalent to identity",
- "type": "mapAxis",
- "mapAxis": { "x":"i", "y":"j" },
- "input": "in",
- "output": "out1"
- },
- {
- "name": "permutation",
- "type": "mapAxis",
- "mapAxis": { "y":"i", "x":"j" },
- "input": "in",
- "output": "out2"
- }
- ]
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ]},
+ { "name": "out1", "axes": [ {"name": "y"}, {"name": "x"} ]},
+ { "name": "out2", "axes": [ {"name": "y"}, {"name": "x"} ]}
+ ],
+ "coordinateTransformations": [
+ {
+ "name": "equivalent to identity",
+ "type": "mapAxis",
+ "mapAxis": { "x":"i", "y":"j" },
+ "input": "in",
+ "output": "out1"
+ },
+ {
+ "name": "permutation",
+ "type": "mapAxis",
+ "mapAxis": { "y":"i", "x":"j" },
+ "input": "in",
+ "output": "out2"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/mapAxis2.json b/ngff_spec/examples/transformations/mapAxis2.json
index 4b50d1f5..0c008475 100644
--- a/ngff_spec/examples/transformations/mapAxis2.json
+++ b/ngff_spec/examples/transformations/mapAxis2.json
@@ -1,23 +1,23 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "a"}, {"name": "b"}]},
- { "name": "out_down", "axes": [ {"name": "x"}]},
- { "name": "out_up", "axes": [ {"name": "z"}, {"name": "y"}, {"name": "x"} ]}
- ],
- "coordinateTransformations": [
- {
- "name": "projection down",
- "type": "mapAxis",
- "mapAxis": { "x": "b" },
- "input": "in",
- "output": "out_down"
- },
- {
- "name": "projection up",
- "type": "mapAxis",
- "mapAxis": { "z": "b", "y": "b", "x": "a" },
- "input": "in",
- "output": "out_up"
- }
- ]
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "a"}, {"name": "b"}]},
+ { "name": "out_down", "axes": [ {"name": "x"}]},
+ { "name": "out_up", "axes": [ {"name": "z"}, {"name": "y"}, {"name": "x"} ]}
+ ],
+ "coordinateTransformations": [
+ {
+ "name": "projection down",
+ "type": "mapAxis",
+ "mapAxis": { "x": "b" },
+ "input": "in",
+ "output": "out_down"
+ },
+ {
+ "name": "projection up",
+ "type": "mapAxis",
+ "mapAxis": { "z": "b", "y": "b", "x": "a" },
+ "input": "in",
+ "output": "out_up"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/rotation.json b/ngff_spec/examples/transformations/rotation.json
index 942dcf39..89692e35 100644
--- a/ngff_spec/examples/transformations/rotation.json
+++ b/ngff_spec/examples/transformations/rotation.json
@@ -1,14 +1,14 @@
{
- "coordinateSystems" : [
- { "name" : "ji", "axes" : [{"name" : "j"}, {"name":"i"}] },
- { "name" : "yx", "axes" : [{"name" : "y"}, {"name":"x"}] }
- ],
- "coordinateTransformations" : [
- {
- "type": "rotation",
- "rotation": [[0, -1], [1, 0]],
- "input" : "ji",
- "output" : "yx"
- }
- ]
+ "coordinateSystems" : [
+ { "name" : "ji", "axes" : [{"name" : "j"}, {"name":"i"}] },
+ { "name" : "yx", "axes" : [{"name" : "y"}, {"name":"x"}] }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type": "rotation",
+ "rotation": [[0, -1], [1, 0]],
+ "input" : "ji",
+ "output" : "yx"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/scale.json b/ngff_spec/examples/transformations/scale.json
index 56d348a5..882b9dd7 100644
--- a/ngff_spec/examples/transformations/scale.json
+++ b/ngff_spec/examples/transformations/scale.json
@@ -1,14 +1,14 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [{"name": "j"}, {"name": "i"}] },
- { "name": "out", "axes": [{"name": "y"}, {"name": "x"}] }
- ],
- "coordinateTransformations": [
- {
- "type": "scale",
- "scale": [3.12, 2],
- "input": "in",
- "output": "out"
- }
- ]
+ "coordinateSystems": [
+ { "name": "in", "axes": [{"name": "j"}, {"name": "i"}] },
+ { "name": "out", "axes": [{"name": "y"}, {"name": "x"}] }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "scale",
+ "scale": [3.12, 2],
+ "input": "in",
+ "output": "out"
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/sequence.json b/ngff_spec/examples/transformations/sequence.json
index e781c108..7ef6c5d4 100644
--- a/ngff_spec/examples/transformations/sequence.json
+++ b/ngff_spec/examples/transformations/sequence.json
@@ -1,17 +1,23 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ]},
- { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ]}
- ],
- "coordinateTransformations": [
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "j"}, {"name": "i"} ]},
+ { "name": "out", "axes": [ {"name": "y"}, {"name": "x"} ]}
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "sequence",
+ "input": "in",
+ "output": "out",
+ "transformations": [
{
- "type": "sequence",
- "input": "in",
- "output": "out",
- "transformations": [
- { "type": "translation", "translation": [0.1, 0.9] },
- { "type": "scale", "scale": [2, 3] }
- ]
+ "type": "translation",
+ "translation": [0.1, 0.9]
+ },
+ {
+ "type": "scale",
+ "scale": [2, 3]
}
- ]
+ ]
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/sequenceSubspace1.json b/ngff_spec/examples/transformations/sequenceSubspace1.json
index e8a5bd35..488e7909 100644
--- a/ngff_spec/examples/transformations/sequenceSubspace1.json
+++ b/ngff_spec/examples/transformations/sequenceSubspace1.json
@@ -1,17 +1,27 @@
{
- "coordinateSystems" : [
- { "name" : "in", "axes" : [ {"name" : "i"}, {"name" : "j"} ] },
- { "name" : "out", "axes" : [ {"name" : "x"}, {"name" : "y"} ] }
- ],
- "coordinateTransformations" : [
+ "coordinateSystems" : [
+ { "name" : "in", "axes" : [ {"name" : "i"}, {"name" : "j"} ] },
+ { "name" : "out", "axes" : [ {"name" : "x"}, {"name" : "y"} ] }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type" : "sequence",
+ "input" : "in",
+ "output" : "out",
+ "transformations" : [
{
- "type" : "sequence",
- "input" : "in",
- "output" : "out",
- "transformations" : [
- { "type" : "coordinates", "path" : "/coordinates", "inputAxes" : ["i"], "outputAxes" : ["x"]},
- { "type" : "scale", "scale" : [2.0], "inputAxes" : ["j"], "outputAxes" : ["y"]}
- ]
+ "type" : "coordinates",
+ "path" : "/coordinates",
+ "input_axes" : ["i"],
+ "output_axes" : ["x"]
+ },
+ {
+ "type" : "scale",
+ "scale" : [2.0],
+ "input_axes" : ["j"],
+ "output_axes" : ["y"]
}
- ]
+ ]
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/translation.json b/ngff_spec/examples/transformations/translation.json
index 5e28be7a..bae772d9 100644
--- a/ngff_spec/examples/transformations/translation.json
+++ b/ngff_spec/examples/transformations/translation.json
@@ -1,14 +1,14 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [{"name": "j"}, {"name": "i"}] },
- { "name": "out", "axes": [{"name": "y"}, {"name": "x"}] }
- ],
- "coordinateTransformations" : [
- {
- "type": "translation",
- "input": "in",
- "output": "out",
- "translation": [9, -1.42]
- }
- ]
+ "coordinateSystems": [
+ { "name": "in", "axes": [{"name": "j"}, {"name": "i"}] },
+ { "name": "out", "axes": [{"name": "y"}, {"name": "x"}] }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type": "translation",
+ "input": "in",
+ "output": "out",
+ "translation": [9, -1.42]
+ }
+ ]
}
diff --git a/ngff_spec/examples/transformations/xarrayLike.json b/ngff_spec/examples/transformations/xarrayLike.json
index 6a7c45b4..73edbdeb 100644
--- a/ngff_spec/examples/transformations/xarrayLike.json
+++ b/ngff_spec/examples/transformations/xarrayLike.json
@@ -1,17 +1,27 @@
{
- "coordinateSystems": [
- { "name": "in", "axes": [ {"name": "i", "type": "array"}, {"name": "j", "type": "array"} ]},
- { "name": "out", "axes": [ {"name": "x", "type": "space"}, {"name": "y", "type": "space"} ]}
- ],
- "coordinateTransformations": [
+ "coordinateSystems": [
+ { "name": "in", "axes": [ {"name": "i", "type": "array"}, {"name": "j", "type": "array"} ]},
+ { "name": "out", "axes": [ {"name": "x", "type": "space"}, {"name": "y", "type": "space"} ]}
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "byDimension",
+ "input": "in",
+ "output": "out",
+ "transformations": [
{
- "type": "byDimension",
- "input": "in",
- "output": "out",
- "transformations": [
- { "type": "coordinates", "path": "/xCoordinates", "input" : ["i"], "output" : ["x"] },
- { "type": "coordinates", "path": "/yCoordinates", "input" : ["j"], "output" : ["y"] }
- ]
+ "type": "coordinates",
+ "path": "/xCoordinates",
+ "input_axes" : ["i"],
+ "output_axes" : ["x"]
+ },
+ {
+ "type": "coordinates",
+ "path": "/yCoordinates",
+ "input_axes" : ["j"],
+ "output_axes" : ["y"]
}
- ]
+ ]
+ }
+ ]
}
diff --git a/ngff_spec/pre_build.py b/ngff_spec/pre_build.py
index b6bb8e28..438633b8 100644
--- a/ngff_spec/pre_build.py
+++ b/ngff_spec/pre_build.py
@@ -54,7 +54,6 @@ def build_json_examples():
```{{literalinclude}} {os.path.abspath(json_file)}
:linenos:
-:tab-width: 2
:language: json
```
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 3e775336..42a9561b 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -392,6 +392,7 @@ Conforming readers:
- MAY ignore other groups or arrays under the root of the hierarchy.
## "coordinateTransformations" metadata
+(coord-trafo-md)=
"coordinateTransformations" describe the mapping between two coordinate systems (defined by "axes").
For example, to map an array's discrete coordinate system to its corresponding physical coordinates.
@@ -1019,40 +1020,37 @@ The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequen
* If the output coordinate system has `M` axes,
the length of the array along the `coordinate`/`displacement` dimension MUST be of length `M`.
-The `i`th value of the array along the `coordinate` or `displacement` axis refers to the coordinate or displacement
-of the `i`th output axis. See the example below.
+The i-th value of the array along the `coordinate` or `displacement` axis refers
+to the coordinate or displacement of the i-th output axis.
+See the example below.
`coordinates` and `displacements` transformations are not invertible in general,
but implementations MAY approximate their inverses.
Metadata for these coordinate transforms have the following fields:
-
- - path
- - The location of the coordinate array in this (or another) container.
- - interpolation
- - The
interpolation attributes MAY be provided.
- It's value indicates the interpolation to use
- if transforming points not on the array's discrete grid.
- Values could be:
-
- linear (default)
- nearest
- cubic
-
-
+path
+: The location of the coordinate array in this (or another) container.
+interpolation
+: The `interpolation` attributes MAY be provided.
+ It's value indicates the interpolation to use
+ if transforming points not on the array's discrete grid.
+ Values could be:
+ - `linear` (default)
+ - `nearest`
+ - `cubic`
For both `coordinates` and `displacements`,
-the array data at referred to by `path` MUST define coordinate system
-and coordinate transform metadata:
+the array data at referred to by `path` MUST define [`coordinateSystems`](#coordinate-systems-md) and
+[`coordinateTransformations`](coord-trafo-md) metadata:
-* Every axis name in the `coordinateTransform`'s `input`
+* Every axis name in the `coordinateTransformations`' `input`
MUST appear in the coordinate system.
* The array dimension corresponding to the `coordinate` or `displacement` axis
- MUST have length equal to the number of dimensions of the `coordinateTransform` `output`
-* If the input coordinate system `N` axes,
+ MUST have length equal to the number of dimensions of the `coordinateTransformation`'s `output`
+* If the input coordinate system has `N` axes,
then the array data at `path` MUST have `(N + 1)` dimensions.
-* SHOULD have a `name` identical to the `name` of the corresponding `coordinateTransform`.
+* SHOULD have a `name` identical to the `name` of the corresponding `coordinateTransformation`.
For `coordinates`:
@@ -1083,21 +1081,21 @@ Example metadata for the array data at path `coordinates` above:
```json
{
- "coordinateSystems" : [
- {
- "name" : "a coordinate field transform",
- "axes" : [
- { "name": "i", "type": "space", "discrete": true },
- { "name": "c", "type": "coordinate", "discrete": true }
- ]
- }
- ],
- "coordinateTransformations" : [
- {
- "type" : "identity",
- "output" : "a coordinate field transform"
- }
- ]
+ "coordinateSystems" : [
+ {
+ "name" : "a coordinate field transform",
+ "axes" : [
+ { "name": "i", "type": "space", "discrete": true },
+ { "name": "c", "type": "coordinate", "discrete": true }
+ ]
+ }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type" : "identity",
+ "output" : "a coordinate field transform"
+ }
+ ]
}
```
@@ -1115,12 +1113,12 @@ x =
A 1D example displacement field:
```json
{
- "name" : "a displacement field transform",
- "type": "displacements",
- "path" : "displacements",
- "input" : "i",
- "output" : "x",
- "interpolation" : "linear"
+ "name" : "a displacement field transform",
+ "type": "displacements",
+ "path" : "displacements",
+ "input" : "i",
+ "output" : "x",
+ "interpolation" : "linear"
}
```
@@ -1129,22 +1127,22 @@ Example metadata for the array data at path `displacements` above:
```json
{
- "coordinateSystems" : [
- {
- "name" : "a displacement field transform",
- "axes" : [
- { "name": "x", "type": "space", "unit" : "nanometer" },
- { "name": "d", "type": "displacement", "discrete": true }
- ]
- }
- ],
- "coordinateTransformations" : [
- {
- "type" : "scale",
- "scale" : [2, 1],
- "output" : "a displacement field transform"
- }
- ]
+ "coordinateSystems" : [
+ {
+ "name" : "a displacement field transform",
+ "axes" : [
+ { "name": "x", "type": "space", "unit" : "nanometer" },
+ { "name": "d", "type": "displacement", "discrete": true }
+ ]
+ }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type" : "scale",
+ "scale" : [2, 1],
+ "output" : "a displacement field transform"
+ }
+ ]
}
```
@@ -1166,16 +1164,16 @@ the other two dimensions MUST be axes that are identical to the axes of the `"in
```json
"coordinateSystems" : [
- { "name" : "in", "axes" : [{"name" : "y"}, {"name":"x"}] },
- { "name" : "out", "axes" : [{"name" : "y"}, {"name":"x"}] }
+ { "name" : "in", "axes" : [{"name" : "y"}, {"name":"x"}] },
+ { "name" : "out", "axes" : [{"name" : "y"}, {"name":"x"}] }
],
"coordinateTransformations" : [
- {
- "type": "displacements",
- "input" : "in",
- "output" : "out",
- "path" : "displacementField"
- }
+ {
+ "type": "displacements",
+ "input" : "in",
+ "output" : "out",
+ "path" : "displacementField"
+ }
]
```
@@ -1183,10 +1181,10 @@ The metadata at location `"displacementField"` should have a coordinate system s
```json
"coordinateSystems" : [
- { "name" : "in", "axes" : [
- {"name":"y"}, {"name":"x"},
- {"name":"d", "type":"displacement", "discrete":true} ]
- }
+ { "name" : "in", "axes" : [
+ {"name":"y"}, {"name":"x"},
+ {"name":"d", "type":"displacement", "discrete":true} ]
+ }
]
```
From 144f837855518fcd38692827b26de3c6922be5dd Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 21:25:32 +0200
Subject: [PATCH 21/47] fixed `byDimension` metadata
---
.../examples/transformations/byDimension1.json | 8 ++++----
.../examples/transformations/byDimension2.json | 8 ++++----
.../transformations/byDimensionInvalid1.json | 14 ++++++++++++--
.../transformations/byDimensionXarray.json | 8 ++++----
4 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/ngff_spec/examples/transformations/byDimension1.json b/ngff_spec/examples/transformations/byDimension1.json
index 7c8de4d7..f67a2579 100644
--- a/ngff_spec/examples/transformations/byDimension1.json
+++ b/ngff_spec/examples/transformations/byDimension1.json
@@ -12,14 +12,14 @@
{
"type": "translation",
"translation": [-1.0],
- "input": ["i"],
- "output": ["x"]
+ "input_axes": ["i"],
+ "output_axes": ["x"]
},
{
"type": "scale",
"scale": [2.0],
- "input": ["j"],
- "output": ["y"]
+ "input_axes": ["j"],
+ "output_axes": ["y"]
}
]
}
diff --git a/ngff_spec/examples/transformations/byDimension2.json b/ngff_spec/examples/transformations/byDimension2.json
index bb642825..5cf6fa13 100644
--- a/ngff_spec/examples/transformations/byDimension2.json
+++ b/ngff_spec/examples/transformations/byDimension2.json
@@ -27,14 +27,14 @@
{
"type": "translation",
"translation": [ 1, 3 ],
- "input": [ "i", "k" ],
- "output": [ "y", "x" ]
+ "input_axes": [ "i", "k" ],
+ "output_axes": [ "y", "x" ]
},
{
"type": "scale",
"scale": [ 2 ],
- "input": [ "j" ],
- "output": [ "z" ]
+ "input_axes": [ "j" ],
+ "output_axes": [ "z" ]
}
]
}
diff --git a/ngff_spec/examples/transformations/byDimensionInvalid1.json b/ngff_spec/examples/transformations/byDimensionInvalid1.json
index b1bdd052..33b99bda 100644
--- a/ngff_spec/examples/transformations/byDimensionInvalid1.json
+++ b/ngff_spec/examples/transformations/byDimensionInvalid1.json
@@ -9,8 +9,18 @@
"input": "in",
"output": "out",
"transformations": [
- { "type": "translation", "translation": [-1.0], "input": ["i"], "output": ["z"]},
- { "type": "scale", "scale": [2.0], "input": ["0"], "output": ["y"]}
+ {
+ "type": "translation",
+ "translation": [-1.0],
+ "input_axes": ["i"],
+ "output_axes": ["z"]
+ },
+ {
+ "type": "scale",
+ "scale": [2.0],
+ "input_axes": ["0"],
+ "output_axes": ["y"]
+ }
]
}
]
diff --git a/ngff_spec/examples/transformations/byDimensionXarray.json b/ngff_spec/examples/transformations/byDimensionXarray.json
index 187ee1a1..69e158e2 100644
--- a/ngff_spec/examples/transformations/byDimensionXarray.json
+++ b/ngff_spec/examples/transformations/byDimensionXarray.json
@@ -24,14 +24,14 @@
{
"type": "coordinates",
"path": "xCoordinates",
- "input": [ "dim_0" ],
- "output": [ "x" ]
+ "input_axes": [ "dim_0" ],
+ "output_axes": [ "x" ]
},
{
"type": "coordinates",
"path": "yCoordinates",
- "input": [ "dim_1" ],
- "output": [ "y" ]
+ "input_axes": [ "dim_1" ],
+ "output_axes": [ "y" ]
}
]
}
From 1c6038d4d9438e0beec3dfe57a15c47812c639d3 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 21:36:25 +0200
Subject: [PATCH 22/47] make examples collapsible
---
ngff_spec/specification.md | 122 ++++++++++++++++++++-----------------
1 file changed, 66 insertions(+), 56 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 42a9561b..b7fd930b 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -258,15 +258,8 @@ The i-th axis has `"name":"dim_i"` (these are the same default names used by [xa
The `dimension_names` must be unique and non-null.
````{admonition} Example
-```json
-{
- "name": "0",
- "axes": [
- {"name": "dim_0", "type": "array"},
- {"name": "dim_1", "type": "array"},
- {"name": "dim_2", "type": "array"}
- ]
-}
+```{literalinclude} examples/coordinate_systems/arrayCoordSys.json
+:language: json
```
For example, if `0/zarr.json` contains:
@@ -470,7 +463,8 @@ store.zarr # Root folder of the zarr store
└── zarr.json # physical coordinate system and transformations here
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
Two instruments simultaneously image the same sample from two different angles,
and the 3D data from both instruments are calibrated to "micrometer" units.
Two samples are collected ("sampleA" and "sampleB").
@@ -534,7 +528,7 @@ The image under `root/sampleA_instrument2` would have this as the first listed c
}
],
```
-````
+::::
### Additional details
@@ -606,7 +600,8 @@ When stored as a 2D zarr array, the first dimension indexes rows and the second
(e.g., an array of `"shape":[3,4]` has 3 rows and 4 columns).
When stored as a 2D json array, the inner array contains rows (e.g. `[[1,2,3], [4,5,6]]` has 2 rows and 3 columns).
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
For matrix transformations, points in the coordinate system:
@@ -638,7 +633,7 @@ because it is computed with the matrix-vector multiplication:
[ 0 0 -1] [3] [-3]
```
-````
+::::
### Transformation types
(trafo-types-md)=
@@ -659,7 +654,8 @@ is set to the position of the ith axis of the input coordinate system.
The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
```{literalinclude} examples/transformations/identity.json
:language: json
@@ -672,7 +668,7 @@ x = i
y = j
```
-````
+::::
#### mapAxis
(mapAxis-md)=
@@ -688,7 +684,8 @@ The value at position `i` in the array indicates which input axis becomes the `i
The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
-````{admonition} Example
+::::{admonition} Example 1
+:class: dropdown
```{literalinclude} examples/transformations/mapAxis1.json
:language: json
@@ -708,9 +705,10 @@ x = j
y = i
```
-````
+::::
-````{admonition} Example
+::::{admonition} Example 2
+:class: dropdown
```{literalinclude} examples/transformations/mapAxis2.json
:language: json
@@ -729,7 +727,7 @@ x = a
y = b
z = b
```
-````
+::::
#### translation
(translation-md)=
@@ -750,7 +748,8 @@ The array at this path MUST be 1D, and its length MUST be `N`.
: The translation parameters stored as a JSON list of numbers.
The list MUST have length `N`.
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
```{literalinclude} examples/transformations/translation.json
:language: json
@@ -762,7 +761,7 @@ defines the function:
x = i + 9
y = j - 1.42
```
-````
+::::
#### scale
(scale-md)=
@@ -784,7 +783,8 @@ The array at this path MUST be 1D, and its length MUST be `N`.
: The scale parameters are stored as a JSON list of numbers.
The list MUST have length `N`.
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
```{literalinclude} examples/transformations/scale.json
:language: json
@@ -796,7 +796,7 @@ defines the function:
x = 3.12 * i
y = 2 * j
```
-````
+::::
#### affine
(affine-md)=
@@ -819,7 +819,8 @@ The array at this path MUST be 2D whose shape MUST be `(M)x(N+1)`.
The matrix MUST be stored as 2D nested array
where the outer array MUST be length `M` and the inner arrays MUST be length `N+1`.
-````{admonition} Example
+::::{admonition} Example 1
+:class: dropdown
A 2D-2D example:
```{literalinclude} examples/transformations/affine2d2d.json
@@ -843,9 +844,10 @@ it is equivalent to this matrix-vector multiplication in homogeneous coordinates
where the last row `[0 0 1]` is omitted in the JSON representation.
-````
+::::
-````{admonition} Example
+::::{admonition} Example 2
+:class: dropdown
An example with two dimensional inputs and three dimensional outputs.
Note that the order of the axes can in general be determined by the application or user.
@@ -874,7 +876,7 @@ it is equivalent to this matrix-vector multiplication in homogeneous coordinates
```
where the last row `[0 0 1]` is omitted in the JSON representation.
-````
+::::
#### rotation
(rotation-md)=
@@ -898,7 +900,8 @@ The array at this path MUST be 2D whose shape MUST be `N x N`.
The matrix MUST be stored as a 2D nested array where the outer array MUST be length `N`
and the inner arrays MUST be length `N`.
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
A 2D example
```{literalinclude} examples/transformations/rotation.json
@@ -910,8 +913,8 @@ defines the function:
```
x = 0*i - 1*j
y = 1*i + 0*j
- ```
-````
+```
+::::
#### inverseOf
(inverseOf-md)=
@@ -935,12 +938,13 @@ At the same time, registration libraries can interpret the wrapped, inverted tra
as the correct corresponding transformation from fixed (output) to moving (input) coordinates.
```
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
```{literalinclude} examples/transformations/inverseOf.json
:language: json
```
-````
+::::
#### sequence
(sequence-md)=
@@ -974,7 +978,8 @@ f2(f1(f0(x)))
transformations
: A non-empty array of transformations.
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
This sequence:
@@ -990,7 +995,7 @@ y = (j + 0.9) * 3
```
and is invertible.
-````
+::::
#### coordinates and displacements
(coordinates-displacements-md)=
@@ -1063,7 +1068,8 @@ For `displacements`:
* the shape of the array along the "displacement" axis must be exactly `N`
* `input` and `output` MUST have an equal number of dimensions.
-````{admonition} Example
+::::{admonition} Example 1
+:class: dropdown
For example, in 1D:
```json
{
@@ -1107,9 +1113,10 @@ x =
else if ( i >= 0.5 and i < 1.5 ) 9
else if ( i >= 1.5 ) 0
```
-````
+::::
-````{admonition} Example
+::::{admonition} Example 2
+:class: dropdown
A 1D example displacement field:
```json
{
@@ -1154,9 +1161,10 @@ The transformation specifies linear interpolation,
which in this case yields `(0.5 * -1) + (0.5 * 0) = -0.5`.
That value gives us the displacement of the input point,
hence the output is `1.0 + (-0.5) = 0.5`.
-````
+::::
-````{admonition} Example
+::::{admonition} Example 3
+:class: dropdown
In this example, the array located at `"displacementField"` MUST have three dimensions.
One dimension MUST correspond to an axis with `type : displacement` (in this example, the last dimension),
@@ -1197,7 +1205,7 @@ x_displacement = displacementField[y][x][1]
I.e. the y-displacement is first, because the y-axis is the first element of the input and output coordinate systems.
-````
+::::
#### byDimension
(byDimension-md)=
@@ -1220,25 +1228,28 @@ The `input` and `output` fields MUST always be included for this transformations
-````{admonition} Example
+::::{admonition} Example 1
+:class: dropdown
A valid `byDimension` transformation:
```{literalinclude} examples/transformations/byDimension1.json
:language: json
```
-````
+::::
-````{admonition} Example
+::::{admonition} Example 2
+:class: dropdown
Another valid `byDimension` transformation:
```{literalinclude} examples/transformations/byDimension2.json
:language: json
```
-````
+::::
-````{admonition} Example
+::::{admonition} Example 3
+:class: dropdown
This is an **invalid** `byDimension` transform:
@@ -1250,9 +1261,10 @@ It is invalid for two reasons.
First because input `0` used by the scale transformation is not an axis of the `byDimension` transformation's `input`.
Second, the `x` axis of the `output` does not appear in the `output` of any child transformation.
-````
+::::
-````{admonition} Example
+::::{admonition} Example 4
+:class: dropdown
Another **invalid** `byDimension` transform:
@@ -1261,9 +1273,7 @@ Another **invalid** `byDimension` transform:
```
This transformation is invalid because the output axis `x` appears in more than one transformation in the `transformations` list.
-
-````
-
+::::
#### bijection
(bijection-md)=
@@ -1287,7 +1297,8 @@ Practically, non-invertible transformations have finite extents,
so bijection transforms should only be expected to be correct / consistent for points that fall within those extents.
It may not be correct for any point of appropriate dimensionality.
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
```{literalinclude} examples/transformations/bijection.json
:language: json
@@ -1298,9 +1309,7 @@ the input and output of the `forward` and `inverse` transformations are understo
```{literalinclude} examples/transformations/bijection_verbose.json
:language: json
```
-
-````
-
+::::
## "multiscales" metadata
(multiscales-md)=
@@ -1381,12 +1390,13 @@ It SHOULD contain the field "metadata",
which contains a dictionary with additional information about the downscaling method.
-````{admonition} Example
+::::{admonition} Example
+:class: dropdown
A complete example of json-file for a 5D (TCZYX) multiscales with 3 resolution levels could look like this:
```{literalinclude} examples/multiscales_strict/multiscales_example.json
:language: json
```
-````
+::::
If only one multiscale is provided, use it.
Otherwise, the user can choose by name,
From 129759892ab1db0b6811061a5ab8be25653f9814 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 21:57:56 +0200
Subject: [PATCH 23/47] renamed example folder
---
.../examples/{coordSystems => coordinate_systems}/.config.json | 0
.../{coordSystems => coordinate_systems}/arrayCoordSys.json | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename ngff_spec/examples/{coordSystems => coordinate_systems}/.config.json (100%)
rename ngff_spec/examples/{coordSystems => coordinate_systems}/arrayCoordSys.json (100%)
diff --git a/ngff_spec/examples/coordSystems/.config.json b/ngff_spec/examples/coordinate_systems/.config.json
similarity index 100%
rename from ngff_spec/examples/coordSystems/.config.json
rename to ngff_spec/examples/coordinate_systems/.config.json
diff --git a/ngff_spec/examples/coordSystems/arrayCoordSys.json b/ngff_spec/examples/coordinate_systems/arrayCoordSys.json
similarity index 100%
rename from ngff_spec/examples/coordSystems/arrayCoordSys.json
rename to ngff_spec/examples/coordinate_systems/arrayCoordSys.json
From 80011bb07ea3988d51d0eb7bbfb9870e2bec48d9 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Tue, 21 Oct 2025 22:17:04 +0200
Subject: [PATCH 24/47] add orcid logo to editor info
---
ngff_spec/specification.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index b7fd930b..4f865bd6 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -6,7 +6,7 @@ short_title: OME-Zarr
**Feedback:** [Forum](https://forum.image.sc/tag/ome-ngff), [Github](https://github.com/ome/ngff/issues)
-**Editor:** Josh Moore, ([German BioImaging e.V.](https://gerbi-gmb.de)), [https://orcid.org/0000-0003-4028-811X](https://orcid.org/0000-0003-4028-811X)
+**Editor:** Josh Moore, ([German BioImaging e.V.](https://gerbi-gmb.de)), [
](https://orcid.org/0000-0003-4028-811X)
## Abstract
From dee0b98c8355c62185872ac18dc393439d524fe0 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 12:48:11 +0200
Subject: [PATCH 25/47] fix reference
---
ngff_spec/specification.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 4f865bd6..0eef3db9 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -387,7 +387,7 @@ Conforming readers:
## "coordinateTransformations" metadata
(coord-trafo-md)=
-"coordinateTransformations" describe the mapping between two coordinate systems (defined by "axes").
+"coordinateTransformations" describe the mapping between two coordinate systems (defined by [`coordinateSystems`](#coordinate-systems-md)).
For example, to map an array's discrete coordinate system to its corresponding physical coordinates.
Coordinate transforms are in the "forward" direction.
They represent functions from *points* in the input space to *points* in the output space.
From a75d5126e8f8a95da114647daf5982cbcfed074e Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 12:48:31 +0200
Subject: [PATCH 26/47] change precedence
See discussion [here](https://github.com/bogovicj/ngff-rfc5-coordinate-transformation-examples/issues/11#issuecomment-3431688131)
---
ngff_spec/specification.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 0eef3db9..db45ac3f 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -542,7 +542,7 @@ In these two cases input and output could, in some cases, be omitted (see below
If used in a parent-level zarr-group, the `input` field MUST be a path to the input image.
The authoritative coordinate system for the input image is the first `coordinateSystem` defined therein.
The `output` field can be a `path` to an output image or the name of a `coordinateSystem` defined in the parent-level zarr group.
-If the names of `input` or `output` can be both a `path` or the name of a `coordinateSystem`, `path` MUST take precedent.
+If the names of `input` or `output` can be both a `path` or the name of a `coordinateSystem`, `coordinateSystem` MUST take precedent.
If unused, the `input` and `output` fields MAY be null.
For usage in multiscales, see [multiscales section](#multiscales-md) for details.
From e52f1fb432cd052ba538c80a37b1f2e97766cbf2 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 15:08:29 +0200
Subject: [PATCH 27/47] added examples for transformations with discrete axes
---
.../affine2d2d_with_channel.json | 32 +++++++++++++++++++
.../transformations/scale_with_discrete.json | 28 ++++++++++++++++
ngff_spec/specification.md | 23 ++++++++++++-
3 files changed, 82 insertions(+), 1 deletion(-)
create mode 100644 ngff_spec/examples/transformations/affine2d2d_with_channel.json
create mode 100644 ngff_spec/examples/transformations/scale_with_discrete.json
diff --git a/ngff_spec/examples/transformations/affine2d2d_with_channel.json b/ngff_spec/examples/transformations/affine2d2d_with_channel.json
new file mode 100644
index 00000000..7b3cf84c
--- /dev/null
+++ b/ngff_spec/examples/transformations/affine2d2d_with_channel.json
@@ -0,0 +1,32 @@
+{
+ "coordinateSystems" : [
+ {
+ "name": "cji",
+ "axes": [
+ {"name": "k", "discrete": true},
+ {"name": "j", "discrete": false},
+ {"name": "i", "discrete": false}
+ ]
+ },
+ {
+ "name": "cyx",
+ "axes": [
+ {"name": "c", "discrete": true},
+ {"name": "y", "discrete": false},
+ {"name": "x", "discrete": false}
+ ]
+ }
+ ],
+ "coordinateTransformations" : [
+ {
+ "type": "affine",
+ "affine": [
+ [1, 0, 0, 0],
+ [0, 1, 2, 3],
+ [0, 4, 5, 6]
+ ],
+ "input": "cji",
+ "output": "cyx"
+ }
+ ]
+}
diff --git a/ngff_spec/examples/transformations/scale_with_discrete.json b/ngff_spec/examples/transformations/scale_with_discrete.json
new file mode 100644
index 00000000..b2acb70c
--- /dev/null
+++ b/ngff_spec/examples/transformations/scale_with_discrete.json
@@ -0,0 +1,28 @@
+{
+ "coordinateSystems": [
+ {
+ "name": "in",
+ "axes": [
+ {"name": "k", "discrete": true},
+ {"name": "j", "discrete": false},
+ {"name": "i", "discrete": false}
+ ]
+ },
+ {
+ "name": "out",
+ "axes": [
+ {"name": "c", "discrete": true},
+ {"name": "y", "discrete": false},
+ {"name": "x", "discrete": false}
+ ]
+ }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "scale",
+ "scale": [1, 3.12, 2],
+ "input": "in",
+ "output": "out"
+ }
+ ]
+}
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index db45ac3f..d8c45c0c 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -783,7 +783,7 @@ The array at this path MUST be 1D, and its length MUST be `N`.
: The scale parameters are stored as a JSON list of numbers.
The list MUST have length `N`.
-::::{admonition} Example
+::::{admonition} Example 1
:class: dropdown
```{literalinclude} examples/transformations/scale.json
@@ -798,6 +798,17 @@ y = 2 * j
```
::::
+::::{admonition} Example 2
+:class: dropdown
+
+If the data contains discrete axes (e.g., channels),
+these axes are typically not transformed, but must be represented in the scale parameters.
+
+```{literalinclude} examples/transformations/scale_with_discrete.json
+:language: json
+```
+::::
+
#### affine
(affine-md)=
@@ -878,6 +889,16 @@ it is equivalent to this matrix-vector multiplication in homogeneous coordinates
where the last row `[0 0 1]` is omitted in the JSON representation.
::::
+::::{admonition} Example 3
+:class: dropdown
+
+If the image data contains discrete axes (e.g., channels),
+these axes are typically not transformed, but must be represented in the transformation matrix.
+
+```{literalinclude} examples/transformations/affine2d2d_with_channel.json
+:language: json
+```
+
#### rotation
(rotation-md)=
From 2faa956afe56b0c3375cb61cc69812a70c2c0c70 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 15:39:48 +0200
Subject: [PATCH 28/47] fix link to example
---
ngff_spec/examples.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ngff_spec/examples.md b/ngff_spec/examples.md
index 4f25ecbd..bb5e98f9 100644
--- a/ngff_spec/examples.md
+++ b/ngff_spec/examples.md
@@ -9,8 +9,8 @@ This section contains JSON examples for various metadata layouts.
- [image](#examples:bf2raw:image)
- [plate](#examples:bf2raw:plate)
-## coordSystems
-- [arrayCoordSys](#examples:coordSystems:arrayCoordSys)
+## coordinate_systems
+- [arrayCoordSys](#examples:coordinate_systems:arrayCoordSys)
## label_strict
- [colors_properties](#examples:label_strict:colors_properties)
From 8fb8ac1c3e875eaaa6f6db4b7e982a00ba891496 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 15:41:17 +0200
Subject: [PATCH 29/47] untrack autogenerated files
---
.gitignore | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.gitignore b/.gitignore
index f97a7680..adb61ce8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,9 @@ _bikeshed
# do not sync auto-generated md files
ngff_spec/_generated
+ngff_spec/footer.md
+ngff_spec/examples.md
+ngff_spec/schemas.md
# Byte-compiled / optimized / DLL files
__pycache__/
From 7ad14ba9205d428742edab6463df242cca751dd4 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 18:23:24 +0200
Subject: [PATCH 30/47] update affine examples and fix variable ordering
---
.../examples/transformations/affine2d3d.json | 6 ++---
ngff_spec/specification.md | 22 ++++++++++---------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/ngff_spec/examples/transformations/affine2d3d.json b/ngff_spec/examples/transformations/affine2d3d.json
index 50b4b82c..8010ee42 100644
--- a/ngff_spec/examples/transformations/affine2d3d.json
+++ b/ngff_spec/examples/transformations/affine2d3d.json
@@ -1,14 +1,14 @@
{
"coordinateSystems": [
{ "name": "ij", "axes": [{"name": "i"}, {"name": "j"}] },
- { "name": "xyz", "axes": [{"name": "x"}, {"name": "y"}, {"name": "z"}] }
+ { "name": "zyx", "axes": [{"name": "z"}, {"name": "y"}, {"name": "x"}] }
],
"coordinateTransformations": [
{
"type": "affine",
- "affine": [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ "affine": [[1, 0, 0], [2, 3, 4], [5, 6, 7]],
"input": "ij",
- "output": "xyz"
+ "output": "zyx"
}
]
}
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index d8c45c0c..1e1a38e4 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -841,15 +841,15 @@ A 2D-2D example:
defines the function:
```
-x = 1*i + 2*j + 3
-y = 4*i + 5*j + 6
+y = 1*j + 2*i + 3
+x = 4*j + 5*i + 6
```
it is equivalent to this matrix-vector multiplication in homogeneous coordinates:
```
-[ 1 2 3 ][ i ] [ x ]
-[ 4 5 6 ][ j ] = [ y ]
+[ 1 2 3 ][ j ] [ y ]
+[ 4 5 6 ][ i ] = [ x ]
[ 0 0 1 ][ 1 ] [ 1 ]
```
@@ -860,6 +860,7 @@ where the last row `[0 0 1]` is omitted in the JSON representation.
::::{admonition} Example 2
:class: dropdown
An example with two dimensional inputs and three dimensional outputs.
+The affine transformation adds a translation by 1 along the new z-axis.
Note that the order of the axes can in general be determined by the application or user.
These axes relate to the memory or on-disk order insofar as the last dimension is contiguous
@@ -872,17 +873,18 @@ when the zarr array is c-order (the default for zarr version 2, and the only opt
defines the function:
```
-x = 1*i + 2*j + 3
-y = 4*i + 5*j + 6
-z = 7*i + 8*j + 9
+z = 0*i + 0*j + 1
+y = 3*i + 4*j + 2
+x = 6*i + 7*j + 5
+
```
it is equivalent to this matrix-vector multiplication in homogeneous coordinates:
```
-[ 1 2 3 ][ i ] [ x ]
-[ 4 5 6 ][ j ] = [ y ]
-[ 7 8 9 ][ 1 ] [ z ]
+[ 1 0 0 ][ 1 ] [ z ]
+[ 2 3 4 ][ i ] = [ y ]
+[ 5 6 7 ][ j ] [ x ]
[ 0 0 1 ] [ 1 ]
```
From ad495b6d767eadf91f34c8f0b6fe52ec2b33743d Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 22:08:48 +0200
Subject: [PATCH 31/47] Fixed scale examples
---
ngff_spec/examples/transformations/scale.json | 2 +-
ngff_spec/specification.md | 16 ++++++++++++----
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/ngff_spec/examples/transformations/scale.json b/ngff_spec/examples/transformations/scale.json
index 882b9dd7..84664a80 100644
--- a/ngff_spec/examples/transformations/scale.json
+++ b/ngff_spec/examples/transformations/scale.json
@@ -6,7 +6,7 @@
"coordinateTransformations": [
{
"type": "scale",
- "scale": [3.12, 2],
+ "scale": [2, 3.12],
"input": "in",
"output": "out"
}
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 1e1a38e4..e7388bee 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -552,14 +552,22 @@ We call this the "forward" direction.
Points are ordered lists of coordinates,
where a coordinate is the location/value of that point along its corresponding axis.
The indexes of axis dimensions correspond to indexes into transformation parameter arrays.
-For example, the scale transformation above defines the function:
-```
-x = 0.5 * i
-y = 1.2 * j
+::::{admonition} Example
+:class: dropdown
+For example, the [scale transformation](#scale-md) metadata below
+
+```{literalinclude} examples/transformations/scale.json
+:language: json
```
+defines the function:
+```
+x = 3.12 * i
+y = 2 * j
+```
i.e., the mapping from the first input axis to the first output axis is determined by the first scale parameter.
+::::
When rendering transformed images and interpolating,
implementations may need the "inverse" transformation -
From 51c88095517ae84ee31f4f99f8cb3467d1fe58a1 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 22:11:24 +0200
Subject: [PATCH 32/47] removed example from additional details
---
ngff_spec/specification.md | 19 +++----------------
1 file changed, 3 insertions(+), 16 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index e7388bee..ef16a032 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -552,22 +552,7 @@ We call this the "forward" direction.
Points are ordered lists of coordinates,
where a coordinate is the location/value of that point along its corresponding axis.
The indexes of axis dimensions correspond to indexes into transformation parameter arrays.
-
-::::{admonition} Example
-:class: dropdown
-For example, the [scale transformation](#scale-md) metadata below
-
-```{literalinclude} examples/transformations/scale.json
-:language: json
-```
-
-defines the function:
-```
-x = 3.12 * i
-y = 2 * j
-```
-i.e., the mapping from the first input axis to the first output axis is determined by the first scale parameter.
-::::
+Examples are given below in the respective [transformation type](#trafo-types-md) sections.
When rendering transformed images and interpolating,
implementations may need the "inverse" transformation -
@@ -804,6 +789,8 @@ defines the function:
x = 3.12 * i
y = 2 * j
```
+i.e., the mapping from the first input axis to the first output axis is determined by the first scale parameter.
+
::::
::::{admonition} Example 2
From 5d99680660817218dde8cf7b37df56f7e241c006 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 22:16:54 +0200
Subject: [PATCH 33/47] specify affines/rotations as 2D matrices in parameter
table
---
ngff_spec/specification.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index ef16a032..aff19c87 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -410,8 +410,8 @@ The following transformations are supported:
| `mapAxis` | `"mapAxis":List[number]` | A `mapAxis` transformation specifies an axis permutation as a transpose array of integer indices that refer to the ordering of the axes in the respective coordinate system. |
| `translation` | one of:
`"translation":List[number]`,
`"path":str` | translation vector, stored either as a list of numbers (`"translation"`) or as binary data at a location in this container (`path`). |
| `scale` | one of:
`"scale":List[number]`,
`"path":str` | scale vector, stored either as a list of numbers (`scale`) or as binary data at a location in this container (`path`). |
-| `affine` | one of:
`"affine": List[List[number]]`,
`"path":str` | affine transformation matrix stored as a flat array stored either with json using the affine field or as binary data at a location in this container (path). If both are present, the binary values at path should be used. |
-| `rotation` | one of:
`"rotation":List[List[number]]`,
`"path":str` | rotation transformation matrix stored as an array stored either with json or as binary data at a location in this container (path). If both are present, the binary parameters at path are used. |
+| `affine` | one of:
`"affine": List[List[number]]`,
`"path":str` | affine transformation matrix stored as a 2D array, either directly in JSON using the affine field or as binary data at a location in this container (path). If both are present, the binary values at path should be used. |
+| `rotation` | one of:
`"rotation":List[List[number]]`,
`"path":str` | rotation transformation matrix stored as a 2D array stored either with json or as binary data at a location in this container (path). If both are present, the binary parameters at path are used. |
| `sequence` | `"transformations":List[Transformation]` | A sequence of transformations, Applying the sequence applies the composition of all transforms in the list, in order. |
| `displacements` | `"path":str`
`"interpolation":str` | Displacement field transformation located at (path). |
| `coordinates` | `"path":str`
`"interpolation":str` | Coordinate field transformation located at (path). |
From 938fbcee403b5255ed61837b49fa7e05d4d24a06 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 22:18:43 +0200
Subject: [PATCH 34/47] renamed coordinate transformations schema
---
ngff_spec/schemas/coordinate_systems_and_transforms.schema | 2 +-
...ransformation.schema => coordinate_transformations.schema} | 2 +-
ngff_spec/schemas/image.schema | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
rename ngff_spec/schemas/{coordinate_transformation.schema => coordinate_transformations.schema} (99%)
diff --git a/ngff_spec/schemas/coordinate_systems_and_transforms.schema b/ngff_spec/schemas/coordinate_systems_and_transforms.schema
index 403f78a5..3b6a4606 100644
--- a/ngff_spec/schemas/coordinate_systems_and_transforms.schema
+++ b/ngff_spec/schemas/coordinate_systems_and_transforms.schema
@@ -9,7 +9,7 @@
"$ref": "coordinate_systems.schema"
},
"coordinateTransformations": {
- "$ref": "coordinate_transformation.schema"
+ "$ref": "coordinate_transformations.schema"
},
"arrayCoordinateSystem": {
"type": "object",
diff --git a/ngff_spec/schemas/coordinate_transformation.schema b/ngff_spec/schemas/coordinate_transformations.schema
similarity index 99%
rename from ngff_spec/schemas/coordinate_transformation.schema
rename to ngff_spec/schemas/coordinate_transformations.schema
index e5156da0..35e6897e 100644
--- a/ngff_spec/schemas/coordinate_transformation.schema
+++ b/ngff_spec/schemas/coordinate_transformations.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/latest/schemas/coordinate_transformation.schema",
+ "$id": "https://ngff.openmicroscopy.org/latest/schemas/coordinate_transformations.schema",
"title": "NGFF Coordinate Systems and Transforms",
"description": "Coordinate Systems and transforms for OME-NGFF",
"type": "array",
diff --git a/ngff_spec/schemas/image.schema b/ngff_spec/schemas/image.schema
index 2f15522b..4623f826 100644
--- a/ngff_spec/schemas/image.schema
+++ b/ngff_spec/schemas/image.schema
@@ -48,7 +48,7 @@
"type": "string"
},
"coordinateTransformations": {
- "$ref": "coordinate_transformation.schema"
+ "$ref": "coordinate_transformations.schema"
}
},
"required": [
@@ -67,7 +67,7 @@
"$ref": "coordinate_systems.schema"
},
"coordinateTransformations": {
- "$ref": "coordinate_transformation.schema"
+ "$ref": "coordinate_transformations.schema"
}
},
"required": [
From 776b16448acf302bfe6cd2ef212a690e79ab2ed5 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 22:36:36 +0200
Subject: [PATCH 35/47] Refactor rotation property to use `mtxFlatOrNested`
---
ngff_spec/schemas/coordinate_transformations.schema | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/ngff_spec/schemas/coordinate_transformations.schema b/ngff_spec/schemas/coordinate_transformations.schema
index 35e6897e..8b8c581c 100644
--- a/ngff_spec/schemas/coordinate_transformations.schema
+++ b/ngff_spec/schemas/coordinate_transformations.schema
@@ -260,10 +260,7 @@
{
"properties": {
"rotation": {
- "type": "array",
- "items": {
- "type": "number"
- }
+ "$ref": "#/$defs/mtxFlatOrNested"
},
"required": [
"rotation"
From b3b7e2449e07b02eafc8dbc22697909467d48e7b Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 22 Oct 2025 23:06:12 +0200
Subject: [PATCH 36/47] Delete schemas.md
---
ngff_spec/schemas.md | 19 -------------------
1 file changed, 19 deletions(-)
delete mode 100644 ngff_spec/schemas.md
diff --git a/ngff_spec/schemas.md b/ngff_spec/schemas.md
deleted file mode 100644
index da86063d..00000000
--- a/ngff_spec/schemas.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# JSON Schemas
-
-This section contains JSON schemas for various metadata layouts.
-Find below links to auto_generated markdown pages or interactive HTML pages for each schema.
-
-| Schema | Markdown | HTML |
-|--------|----------|------|
-| axes | [axes](#schemas:axes) | [axes](_generated/schemas\html\axes.html) |
-| bf2raw | | [bf2raw](_generated/schemas\html\bf2raw.html) |
-| coordinate_systems | [coordinate_systems](#schemas:coordinate_systems) | [coordinate_systems](_generated/schemas\html\coordinate_systems.html) |
-| coordinate_systems_and_transforms | | |
-| coordinate_transformation | | |
-| image | | |
-| label | | [label](_generated/schemas\html\label.html) |
-| ome | | [ome](_generated/schemas\html\ome.html) |
-| ome_zarr | | [ome_zarr](_generated/schemas\html\ome_zarr.html) |
-| plate | | [plate](_generated/schemas\html\plate.html) |
-| well | | [well](_generated/schemas\html\well.html) |
-| _version | [_version](#schemas:_version) | [_version](_generated/schemas\html\_version.html) |
From dce465935166caf225a35b3db60ecb695a4ff2fc Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Fri, 24 Oct 2025 08:32:47 +0200
Subject: [PATCH 37/47] remove `mtxFloatOrNested`
affine/rotation matrices should always be 2D
---
.../schemas/coordinate_transformations.schema | 30 +++++++++----------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/ngff_spec/schemas/coordinate_transformations.schema b/ngff_spec/schemas/coordinate_transformations.schema
index 8b8c581c..413b9815 100644
--- a/ngff_spec/schemas/coordinate_transformations.schema
+++ b/ngff_spec/schemas/coordinate_transformations.schema
@@ -209,20 +209,6 @@
}
]
},
- "mtxFlatOrNested" : {
- "type": "array",
- "oneOf": [
- {
- "items": { "type": "number" }
- },
- {
- "items": {
- "type": "array",
- "items" : { "type" : "number" }
- }
- }
- ]
- },
"affine": {
"type": "object",
"properties": {
@@ -237,7 +223,13 @@
{
"properties": {
"affine": {
- "$ref": "#/$defs/mtxFlatOrNested"
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
},
"required": [
"affine"
@@ -260,7 +252,13 @@
{
"properties": {
"rotation": {
- "$ref": "#/$defs/mtxFlatOrNested"
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
},
"required": [
"rotation"
From bb63455477f3129ea99383ca81b318a2f9b77a8c Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 29 Oct 2025 13:16:51 +0100
Subject: [PATCH 38/47] "zarr array" instead of "binary data"
---
ngff_spec/specification.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index aff19c87..62e208d6 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -408,10 +408,10 @@ The following transformations are supported:
|------|--------|-------------|
| `identity` | | The identity transformation is the default transformation and is typically not explicitly defined. |
| `mapAxis` | `"mapAxis":List[number]` | A `mapAxis` transformation specifies an axis permutation as a transpose array of integer indices that refer to the ordering of the axes in the respective coordinate system. |
-| `translation` | one of:
`"translation":List[number]`,
`"path":str` | translation vector, stored either as a list of numbers (`"translation"`) or as binary data at a location in this container (`path`). |
-| `scale` | one of:
`"scale":List[number]`,
`"path":str` | scale vector, stored either as a list of numbers (`scale`) or as binary data at a location in this container (`path`). |
-| `affine` | one of:
`"affine": List[List[number]]`,
`"path":str` | affine transformation matrix stored as a 2D array, either directly in JSON using the affine field or as binary data at a location in this container (path). If both are present, the binary values at path should be used. |
-| `rotation` | one of:
`"rotation":List[List[number]]`,
`"path":str` | rotation transformation matrix stored as a 2D array stored either with json or as binary data at a location in this container (path). If both are present, the binary parameters at path are used. |
+| `translation` | one of:
`"translation":List[number]`,
`"path":str` | translation vector, stored either as a list of numbers (`"translation"`) or as a zarr array at a location in this container (`path`). |
+| `scale` | one of:
`"scale":List[number]`,
`"path":str` | scale vector, stored either as a list of numbers (`scale`) or as a zarr array at a location in this container (`path`). |
+| `affine` | one of:
`"affine": List[List[number]]`,
`"path":str` | affine transformation matrix stored as a 2D array, either directly in JSON using the affine field or as a zarr array at a location in this container (path). If both are present, the zarr array at path should be used. |
+| `rotation` | one of:
`"rotation":List[List[number]]`,
`"path":str` | rotation transformation matrix stored as a 2D array stored either with json or as a zarr array at a location in this container (path). If both are present, the zarr array parameters at path are used. |
| `sequence` | `"transformations":List[Transformation]` | A sequence of transformations, Applying the sequence applies the composition of all transforms in the list, in order. |
| `displacements` | `"path":str`
`"interpolation":str` | Displacement field transformation located at (path). |
| `coordinates` | `"path":str`
`"interpolation":str` | Coordinate field transformation located at (path). |
From fc7fef069e3e90554920829d5dd103b2f5b6e042 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 3 Nov 2025 13:05:35 +0100
Subject: [PATCH 39/47] WIP: Update rfc5 schemas (#1)
I'm merging this so that all necessary changes regarding the addition of rfc5-stuff to the main branch of the ngff-spec repo can be in one place. This branch was supposed to be a break-out to keep the commit-history of https://github.com/ome/ngff-spec/pull/17 clean.
* Update input/output to input_axes/output_axes in schema
* Add description and required field to byDimension
* Update mapAxis schema to use integer array
* Add path and interpolation to displacements schema
The displacements object now includes a required 'path' property for specifying the zarr array location and an 'interpolation' property with supported methods. This enhances the schema's ability to describe displacement fields and their application.
* Add path and interpolation to coordinates schema
Introduces 'path' and 'interpolation' properties to the 'coordinates' object in the schema, specifying the location of the coordinate field and the interpolation method to use. The 'path' property is now required.
* only allow paths, no URLs
* move required fields to correct places
* name musnt't be empty
* added axis types to schema
* Added descriptions to schemas
* updated versions to 0.6dev2
* fix paths and versions
* pull schema from correct location
* Added action to run the tests
* update config reference
* update versions in test suite
* Revert "update config reference"
This reverts commit ff3fedd4143d888ad5f107969042851ea86dc271.
* update all version references to "0.6dev2"
* update version reference
* at least two spatial axes
* allow any axis type
* update version reference
* Add maxItems constraint to axes schema
Set a maximum of 5 items for the axes array in the schema to enforce limits on the number of axes allowed.
* Refactor image schema for coordinate transformations
Refactors the definition of coordinateTransformations and coordinateSystems to use inline array schemas with stricter constraints. Adds a new multiscale_coordinateTransformations definition to support scale and translate transformations for multiscale datasets.
* Update to NGFF 0.6dev2 and refactor coordinate systems
Updated example and test JSON files to use the NGFF 0.6dev2 specification. Replaced 'axes' with 'coordinateSystems', added explicit 'input' and 'output' fields to coordinateTransformations, and restructured transformation chains for clarity and compliance with the new spec.
* fix schema resolution
---
.github/workflows/validation.yml | 16 +
.../multiscales_example.json | 2 +-
.../multiscales_example_relative.json | 56 +-
.../multiscales_transformations.json | 44 +-
ngff_spec/schemas/_version.schema | 4 +-
ngff_spec/schemas/axes.schema | 10 +-
ngff_spec/schemas/bf2raw.schema | 4 +-
ngff_spec/schemas/coordinate_systems.schema | 5 +-
.../coordinate_systems_and_transforms.schema | 8 +-
.../schemas/coordinate_transformations.schema | 159 ++--
ngff_spec/schemas/image.schema | 56 +-
ngff_spec/schemas/label.schema | 4 +-
ngff_spec/schemas/ome.schema | 4 +-
ngff_spec/schemas/ome_zarr.schema | 14 +-
ngff_spec/schemas/plate.schema | 4 +-
ngff_spec/schemas/strict_axes.schema | 4 +-
.../schemas/strict_coordinate_systems.schema | 2 +-
ngff_spec/schemas/strict_image.schema | 4 +-
ngff_spec/schemas/strict_label.schema | 4 +-
ngff_spec/schemas/strict_plate.schema | 4 +-
ngff_spec/schemas/strict_well.schema | 4 +-
ngff_spec/schemas/well.schema | 4 +-
tests/image_suite.json | 780 +++++++++++-------
tests/label_suite.json | 20 +-
tests/plate_suite.json | 62 +-
tests/strict_image_suite.json | 298 +++++--
tests/strict_label_suite.json | 4 +-
tests/strict_plate_suite.json | 12 +-
tests/strict_well_suite.json | 6 +-
tests/test_validation.py | 8 +-
tests/well_suite.json | 6 +-
31 files changed, 1023 insertions(+), 589 deletions(-)
create mode 100644 .github/workflows/validation.yml
diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml
new file mode 100644
index 00000000..2e2ab584
--- /dev/null
+++ b/.github/workflows/validation.yml
@@ -0,0 +1,16 @@
+name: Validation
+on:
+ push:
+ pull_request:
+
+jobs:
+ validate:
+ name: Validation
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.12'
+ - run: python -mpip install --upgrade wheel tox
+ - run: tox
\ No newline at end of file
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_example.json b/ngff_spec/examples/multiscales_strict/multiscales_example.json
index 55799eb2..a07d34d1 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_example.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_example.json
@@ -57,7 +57,7 @@
"input": "2",
"output": "physical"
}
- ]
+ ]
}
],
"type": "gaussian",
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
index 5b83bd4b..8bd828c9 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
@@ -1,21 +1,21 @@
{
"multiscales": [
{
- "version": "0.5-dev",
+ "version": "0.6dev2",
"name": "example",
"coordinateSystems" : [
{
- "name" : "exampleCoordinateSystem",
- "axes": [
- {"name": "t", "type": "time", "unit": "millisecond"},
- {"name": "c", "type": "channel"},
- {"name": "z", "type": "space", "unit": "micrometer"},
- {"name": "y", "type": "space", "unit": "micrometer"},
- {"name": "x", "type": "space", "unit": "micrometer"}
- ]
+ "name" : "world",
+ "axes": {
+ "t": {"type": "time", "unit": "millisecond"},
+ "c": {"type": "channel"},
+ "z": {"type": "space", "unit": "micrometer"},
+ "y": {"type": "space", "unit": "micrometer"},
+ "x": {"type": "space", "unit": "micrometer"}
+ }
},
{
- "name" : "array_0",
+ "name" : "intrinsic",
"axes": [
{"name": "t", "type": "time", "unit": "millisecond"},
{"name": "c", "type": "channel"},
@@ -27,12 +27,14 @@
],
"datasets": [
{
- "path": "0",
- // the transformation of other arrays are defined relative to this, the highest resolution, array
+ "path": "s0",
+ // the transformation of other arrays are
+ // defined relative to this, the highest resolution, array
"coordinateTransformations": [{
- "type": "identity",
- "input": "/0",
- "output": "array_0"
+ "type": "scale",
+ "scale": [1, 1, 1, 1, 1],
+ "input": "s0",
+ "output": "intrinsic"
}]
},
{
@@ -56,21 +58,15 @@
}]
}
],
- "coordinateTransformations": [{
- // the time unit (0.1 milliseconds), the voxel size for all spatial axes of "0" (0.5 micrometers)
- "type": "scale",
- "scale": [0.1, 1.0, 0.5, 0.5, 0.5],
- "input" : "array_0",
- "output" : "exampleCoordinateSystem"
- }],
- "type": "gaussian",
- "metadata": {
- "description": "the fields in metadata depend on the downscaling implementation. Here, the parameters passed to the skimage function are given",
- "method": "skimage.transform.pyramid_gaussian",
- "version": "0.16.1",
- "args": "[true]",
- "kwargs": {"multichannel": true}
- }
+ "coordinateTransformations": [
+ {
+ "name": "additional_translation",
+ "type": "translation",
+ "translation": [0, 0, 10, 20, 30],
+ "input": "intrinsic",
+ "output": "world"
+ }
+ ]
}
]
}
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_transformations.json b/ngff_spec/examples/multiscales_strict/multiscales_transformations.json
index e4eb742a..14304c0a 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_transformations.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_transformations.json
@@ -3,19 +3,39 @@
"node_type": "group",
"attributes": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
+ "name": "physical",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
},
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -24,7 +44,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -32,7 +54,9 @@
"coordinateTransformations": [
{
"scale": [10, 10],
- "type": "scale"
+ "type": "scale",
+ "input": "intrinsic",
+ "output": "physical"
}
],
"name": "image_with_coordinateTransformations",
diff --git a/ngff_spec/schemas/_version.schema b/ngff_spec/schemas/_version.schema
index 3845691c..b20a6702 100644
--- a/ngff_spec/schemas/_version.schema
+++ b/ngff_spec/schemas/_version.schema
@@ -1,10 +1,10 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema",
"title": "OME-Zarr Metadata version",
"description": "The version of the OME-Zarr Metadata",
"type": "string",
"enum": [
- "0.6.dev1"
+ "0.6dev2"
]
}
diff --git a/ngff_spec/schemas/axes.schema b/ngff_spec/schemas/axes.schema
index 56b447f2..3ed096da 100644
--- a/ngff_spec/schemas/axes.schema
+++ b/ngff_spec/schemas/axes.schema
@@ -1,11 +1,12 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/latest/schemas/axes.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/axes.schema",
"title": "NGFF Axes",
"description": "JSON from OME-NGFF .zattrs",
"type": "array",
"uniqueItems": true,
"minItems": 1,
+ "maxItems": 5,
"items": {
"$ref": "#/$defs/axis"
},
@@ -27,7 +28,7 @@
}
}
},
- "minContains": 0,
+ "minContains": 2,
"maxContains": 3,
"$defs": {
"axis": {
@@ -35,7 +36,8 @@
"properties": {
"name": {
"type": "string",
- "description": "Name of the axis"
+ "minLength": 1,
+ "description": "Name of the axis. Must be unique within the coordinate system."
},
"longName": {
"type": "string",
@@ -43,7 +45,7 @@
},
"type": {
"type": "string",
- "description": "Dimension of the axis"
+ "description": "Type of the axis. Can be a predefined type or custom type."
},
"discrete": {
"type": "boolean",
diff --git a/ngff_spec/schemas/bf2raw.schema b/ngff_spec/schemas/bf2raw.schema
index bb42ea87..edcfaaac 100644
--- a/ngff_spec/schemas/bf2raw.schema
+++ b/ngff_spec/schemas/bf2raw.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/bf2raw.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/bf2raw.schema",
"title": "OME-Zarr container produced by bioformats2raw",
"description": "The zarr.json attributes key",
"type": "object",
@@ -17,7 +17,7 @@
]
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/coordinate_systems.schema b/ngff_spec/schemas/coordinate_systems.schema
index 583d9941..f42d5b9a 100644
--- a/ngff_spec/schemas/coordinate_systems.schema
+++ b/ngff_spec/schemas/coordinate_systems.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/latest/schemas/coordinate_systems.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_systems.schema",
"title": "NGFF CoordinateSystem",
"description": "JSON from OME-NGFF .zattrs",
"type": "array",
@@ -15,7 +15,8 @@
"properties": {
"name": {
"type": "string",
- "description": "Name of coordinate system"
+ "minLength": 1,
+ "description": "Name of coordinate system. Must be unique among all coordinate systems."
},
"axes": {
"$ref": "axes.schema"
diff --git a/ngff_spec/schemas/coordinate_systems_and_transforms.schema b/ngff_spec/schemas/coordinate_systems_and_transforms.schema
index 3b6a4606..fd6b4b15 100644
--- a/ngff_spec/schemas/coordinate_systems_and_transforms.schema
+++ b/ngff_spec/schemas/coordinate_systems_and_transforms.schema
@@ -1,15 +1,17 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/latest/schemas/coordinate_systems_and_transforms.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_systems_and_transforms.schema",
"title": "NGFF Coordinate Systems and Transforms",
"description": "Coordinate Systems and transforms for OME-NGFF",
"type": "object",
"properties": {
"coordinateSystems": {
- "$ref": "coordinate_systems.schema"
+ "$ref": "coordinate_systems.schema",
+ "description": "Coordinate systems to combine with transforms to define spatial relationships"
},
"coordinateTransformations": {
- "$ref": "coordinate_transformations.schema"
+ "$ref": "coordinate_transformations.schema",
+ "description": "Coordinate transformations defining spatial relationships between coordinate systems"
},
"arrayCoordinateSystem": {
"type": "object",
diff --git a/ngff_spec/schemas/coordinate_transformations.schema b/ngff_spec/schemas/coordinate_transformations.schema
index 413b9815..20dce275 100644
--- a/ngff_spec/schemas/coordinate_transformations.schema
+++ b/ngff_spec/schemas/coordinate_transformations.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/latest/schemas/coordinate_transformations.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema",
"title": "NGFF Coordinate Systems and Transforms",
"description": "Coordinate Systems and transforms for OME-NGFF",
"type": "array",
@@ -29,22 +29,6 @@
]
},
"$defs": {
- "path_w_url": {
- "description": "Path specification. Schema local solution until https://github.com/ome/ngff/issues/144 is resolved.",
- "type": "object",
- "properties": {
- "path": {
- "type": "string"
- },
- "url": {
- "type": "string",
- "format": "uri"
- }
- },
- "required": [
- "path"
- ]
- },
"coordinateTransformation": {
"description": "OME-NGFF coordinate transformation.",
"allOf": [
@@ -111,22 +95,27 @@
{ "$ref": "#/$defs/coordinateTransformation" },
{
"properties": {
- "input": {
+ "input_axes": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Names of the input axes for this transformation."
},
- "output": {
+ "output_axes": {
"type": "array",
"items": {
"type": "string"
- }
+ },
+ "description": "Names of the output axes for this transformation."
}
- }
+ },
+ "required": [
+ "input_axes",
+ "output_axes"
+ ]
}
- ],
- "required": ["input", "output"]
+ ]
},
"identity": {
"type": "object",
@@ -144,12 +133,11 @@
"const": "mapAxis"
},
"mapAxis": {
- "type": "object",
- "patternProperties": {
- ".*": {
- "type": "string"
- }
- }
+ "type": "array",
+ "items": {
+ "type": "integer"
+ },
+ "description": "An array of integers representing the new axis order as zero-based indices of the input axes."
},
"required": [
"mapAxis"
@@ -165,7 +153,15 @@
},
"oneOf": [
{
- "$ref": "#/$defs/path_w_url"
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to a zarr array containing the scale factors."
+ }
+ },
+ "required": [
+ "path"
+ ]
},
{
"properties": {
@@ -192,7 +188,15 @@
},
"oneOf": [
{
- "$ref": "#/$defs/path_w_url"
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to a zarr array containing the translation vectors."
+ }
+ },
+ "required": [
+ "path"
+ ]
},
{
"properties": {
@@ -218,7 +222,15 @@
},
"oneOf": [
{
- "$ref": "#/$defs/path_w_url"
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to a zarr array containing the affine matrix."
+ }
+ },
+ "required": [
+ "path"
+ ]
},
{
"properties": {
@@ -230,11 +242,11 @@
"type": "number"
}
}
- },
- "required": [
- "affine"
- ]
- }
+ }
+ },
+ "required": [
+ "affine"
+ ]
}
]
},
@@ -247,7 +259,15 @@
},
"oneOf": [
{
- "$ref": "#/$defs/path_w_url"
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to a zarr array containing the rotation matrix."
+ }
+ },
+ "required": [
+ "path"
+ ]
},
{
"properties": {
@@ -259,11 +279,11 @@
"type": "number"
}
}
- },
- "required": [
- "rotation"
- ]
- }
+ }
+ },
+ "required": [
+ "rotation"
+ ]
}
]
},
@@ -279,7 +299,8 @@
},
"required": [
"transformation"
- ]
+ ],
+ "description": "The inverse of another coordinate transformation."
},
"bijection": {
"type": "object",
@@ -296,7 +317,8 @@
},
"required": [
"forward", "inverse"
- ]
+ ],
+ "description": "A pair of forward and inverse coordinate transformations."
},
"sequence": {
"description": "A sequence of transformations",
@@ -309,7 +331,10 @@
"$ref": "#/$defs/coordinateTransformation"
}
}
- }
+ },
+ "required": [
+ "transformations"
+ ]
},
"byDimension": {
"type": "object",
@@ -321,19 +346,49 @@
"$ref": "#/$defs/byDimensionTransformation"
}
}
- }
+ },
+ "required": [
+ "transformations"
+ ],
+ "description": "A set of transformations applied independently to each dimension."
},
"displacements": {
"type": "object",
"properties": {
- "type": { "const": "displacements" }
- }
+ "type": { "const": "displacements" },
+ "path": {
+ "type": "string",
+ "description": "Path to the zarr array containing the displacement field."
+ },
+ "interpolation": {
+ "type": "string",
+ "enum": ["nearest", "linear", "cubic"],
+ "default": "linear",
+ "description": "Interpolation method to use when applying the displacement field."
+ }
+ },
+ "required": [
+ "path"
+ ]
},
"coordinates": {
"type": "object",
"properties": {
- "type": { "const": "coordinates" }
- }
+ "type": { "const": "coordinates" },
+ "path": {
+ "type": "string",
+ "description": "Path to the zarr array containing the coordinate field."
+ },
+ "interpolation": {
+ "type": "string",
+ "enum": ["nearest", "linear", "cubic"],
+ "default": "linear",
+ "description": "Interpolation method to use when applying the coordinate field."
+ }
+ },
+ "required": [
+ "path"
+ ]
}
}
}
diff --git a/ngff_spec/schemas/image.schema b/ngff_spec/schemas/image.schema
index 4623f826..d7324d93 100644
--- a/ngff_spec/schemas/image.schema
+++ b/ngff_spec/schemas/image.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/image.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema",
"title": "OME-Zarr Image",
"description": "The zarr.json attributes key",
"type": "object",
@@ -10,13 +10,13 @@
"type": "object",
"properties": {
"multiscales": {
- "$ref": "#/$defs/multiscales"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema#/$defs/multiscales"
},
"omero": {
- "$ref": "#/$defs/omero"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema#/$defs/omero"
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
}
},
"required": [
@@ -48,7 +48,13 @@
"type": "string"
},
"coordinateTransformations": {
- "$ref": "coordinate_transformations.schema"
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema#/$defs/multiscale_coordinateTransformations"
+ },
+ "minItems": 1,
+ "maxItems": 1
}
},
"required": [
@@ -60,14 +66,22 @@
"version": {
"type": "string",
"enum": [
- "0.6.dev1"
+ "0.6dev2"
]
},
"coordinateSystems": {
- "$ref": "coordinate_systems.schema"
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_systems.schema#/$defs/coordinateSystem"
+ }
},
"coordinateTransformations": {
- "$ref": "coordinate_transformations.schema"
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/coordinateTransformation"
+ }
}
},
"required": [
@@ -77,6 +91,32 @@
"minItems": 1,
"uniqueItems": true
},
+ "multiscale_coordinateTransformations": {
+ "description": "OME-NGFF coordinate transformation for multiscale resolution level datasets (only scale or scale & translate).",
+ "oneOf": [
+ {"$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/scale"},
+ {
+ "type": "object",
+ "properties": {
+ "type": {"const": "sequence"},
+ "transformations": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {"$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/scale"},
+ {"$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/translation"}
+ ]
+ },
+ "minItems": 2,
+ "maxItems": 2
+ },
+ "input": {"type": "string"},
+ "output": {"type": "string"}
+ },
+ "required": ["type", "transformations", "input", "output"]
+ }
+ ]
+ },
"omero": {
"type": "object",
"properties": {
diff --git a/ngff_spec/schemas/label.schema b/ngff_spec/schemas/label.schema
index 5692edca..7f234ed8 100644
--- a/ngff_spec/schemas/label.schema
+++ b/ngff_spec/schemas/label.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/label.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/label.schema",
"title": "OME-Zarr labelled image schema",
"description": "The zarr.json attributes key",
"type": "object",
@@ -13,7 +13,7 @@
"$ref": "#/$defs/image-label"
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/ome.schema b/ngff_spec/schemas/ome.schema
index 2a3e5fa2..9a44f6bc 100644
--- a/ngff_spec/schemas/ome.schema
+++ b/ngff_spec/schemas/ome.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/ome.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome.schema",
"title": "OME-Zarr group produced by bioformats2raw to contain OME metadata",
"description": "The zarr.json attributes key",
"type": "object",
@@ -18,7 +18,7 @@
"minContains": 1
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/ome_zarr.schema b/ngff_spec/schemas/ome_zarr.schema
index 632d0192..2ce06ac6 100644
--- a/ngff_spec/schemas/ome_zarr.schema
+++ b/ngff_spec/schemas/ome_zarr.schema
@@ -1,24 +1,24 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/ome_zarr.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome_zarr.schema",
"anyOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/bf2raw.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/bf2raw.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/image.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/label.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/label.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/ome.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/plate.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/plate.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/well.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/well.schema"
}
]
}
diff --git a/ngff_spec/schemas/plate.schema b/ngff_spec/schemas/plate.schema
index e1626a27..06d7edb0 100644
--- a/ngff_spec/schemas/plate.schema
+++ b/ngff_spec/schemas/plate.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/plate.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/plate.schema",
"title": "OME-Zarr plate schema",
"description": "The zarr.json attributes key",
"type": "object",
@@ -138,7 +138,7 @@
]
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/strict_axes.schema b/ngff_spec/schemas/strict_axes.schema
index 522602d2..f6bab275 100644
--- a/ngff_spec/schemas/strict_axes.schema
+++ b/ngff_spec/schemas/strict_axes.schema
@@ -1,11 +1,11 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/latest/schemas/strict_axes.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_axes.schema",
"title": "NGFF Strict Axes",
"description": "JSON from OME-NGFF .zattrs",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/latest/schemas/axes.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/axes.schema"
},
{
"items": {
diff --git a/ngff_spec/schemas/strict_coordinate_systems.schema b/ngff_spec/schemas/strict_coordinate_systems.schema
index 425ccbe5..99474ce0 100644
--- a/ngff_spec/schemas/strict_coordinate_systems.schema
+++ b/ngff_spec/schemas/strict_coordinate_systems.schema
@@ -1,5 +1,5 @@
{
- "$id": "https://ngff.openmicroscopy.org/latest/schemas/strict_coordinate_systems.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_coordinate_systems.schema",
"allOf" : [
{
"$ref": "coordinate_systems.schema"
diff --git a/ngff_spec/schemas/strict_image.schema b/ngff_spec/schemas/strict_image.schema
index 4c51c95e..812f706f 100644
--- a/ngff_spec/schemas/strict_image.schema
+++ b/ngff_spec/schemas/strict_image.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/strict_image.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_image.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/image.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema"
},
{
"properties": {
diff --git a/ngff_spec/schemas/strict_label.schema b/ngff_spec/schemas/strict_label.schema
index 90e510c0..90daf564 100644
--- a/ngff_spec/schemas/strict_label.schema
+++ b/ngff_spec/schemas/strict_label.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/strict_label.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_label.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/label.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/label.schema"
},
{
"properties": {
diff --git a/ngff_spec/schemas/strict_plate.schema b/ngff_spec/schemas/strict_plate.schema
index 2fe258ce..7b91ff38 100644
--- a/ngff_spec/schemas/strict_plate.schema
+++ b/ngff_spec/schemas/strict_plate.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/strict_plate.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_plate.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/plate.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/plate.schema"
},
{
"properties": {
diff --git a/ngff_spec/schemas/strict_well.schema b/ngff_spec/schemas/strict_well.schema
index df7ad6c8..1192acda 100644
--- a/ngff_spec/schemas/strict_well.schema
+++ b/ngff_spec/schemas/strict_well.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/strict_well.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_well.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/well.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/well.schema"
}
]
}
diff --git a/ngff_spec/schemas/well.schema b/ngff_spec/schemas/well.schema
index f623adc4..f81fafa9 100644
--- a/ngff_spec/schemas/well.schema
+++ b/ngff_spec/schemas/well.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/well.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/well.schema",
"title": "OME-Zarr well schema",
"description": "JSON from OME-Zarr zarr.json",
"type": "object",
@@ -41,7 +41,7 @@
]
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/tests/image_suite.json b/tests/image_suite.json
index df359ce4..ee80509b 100644
--- a/tests/image_suite.json
+++ b/tests/image_suite.json
@@ -1,7 +1,7 @@
{
"description": "TBD",
"schema": {
- "id": "schemas/image.schema"
+ "id": "ngff_spec/schemas/image.schema"
},
"tests": [
{
@@ -9,24 +9,29 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "t",
- "type": "time",
- "unit": "micrometer"
- },
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "t",
+ "type": "time",
+ "unit": "micrometer"
+ },
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -35,7 +40,9 @@
"coordinateTransformations": [
{
"scale": [0.13, 0.13],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -51,22 +58,27 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "angle"
- },
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "angle"
+ },
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -75,6 +87,8 @@
"coordinateTransformations": [
{
"scale": [1, 1, 1],
+ "input": "0",
+ "output": "intrinsic",
"type": "scale"
}
]
@@ -91,27 +105,35 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micron"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micron"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
+
"datasets": [
{
"path": "0",
"coordinateTransformations": [
{
"scale": [0.13, 0.13],
+ "input": "0",
+ "output": "intrinsic",
"type": "scale"
}
]
@@ -128,7 +150,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
"datasets": [
@@ -137,7 +159,9 @@
"coordinateTransformations": [
{
"type": "scale",
- "scale": [1, 1]
+ "scale": [1, 1],
+ "input": "path/to/0",
+ "output": "intrinsic"
}
]
}
@@ -151,16 +175,21 @@
"multichannel": true
}
},
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
]
}
@@ -174,23 +203,28 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "angle",
- "type": "custom"
- },
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "angle",
+ "type": "custom"
+ },
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -199,6 +233,8 @@
"coordinateTransformations": [
{
"scale": [1, 1, 1],
+ "input": "0",
+ "output": "intrinsic",
"type": "scale"
}
]
@@ -215,28 +251,36 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
+
"datasets": [
{
"path": "0",
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -252,26 +296,33 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "t",
- "type": "time"
- },
+ "coordinateSystems": [
{
- "name": "c",
- "type": "channel"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "t",
+ "type": "time"
+ },
+ {
+ "name": "c",
+ "type": "channel"
+ }
+ ]
}
- ],
+ ],
"datasets": [
{
"path": "0",
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -287,19 +338,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -308,7 +364,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "translation"
+ "type": "translation",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -324,19 +382,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -345,7 +408,9 @@
"coordinateTransformations": [
{
"translation": [1, 1],
- "type": "translation"
+ "type": "translation",
+ "input": "0",
+ "output": "intrinsice"
}
]
}
@@ -361,33 +426,38 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "angle",
- "type": "custom"
- },
- {
- "name": "t",
- "type": "time"
- },
- {
- "name": "c",
- "type": "channel"
- },
- {
- "name": "z",
- "type": "space"
- },
- {
- "name": "y",
- "type": "space"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "angle",
+ "type": "custom"
+ },
+ {
+ "name": "t",
+ "type": "time"
+ },
+ {
+ "name": "c",
+ "type": "channel"
+ },
+ {
+ "name": "z",
+ "type": "space"
+ },
+ {
+ "name": "y",
+ "type": "space"
+ },
+ {
+ "name": "x",
+ "type": "space"
+ }
+ ]
}
],
"datasets": [
@@ -396,7 +466,9 @@
"coordinateTransformations": [
{
"scale": [1, 1, 1, 1, 1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -412,19 +484,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -433,7 +510,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -466,17 +545,22 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "type": "space",
- "unit": "micron"
- },
+ "coordinateSystems": [
{
- "type": "space",
- "unit": "micron"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -485,7 +569,9 @@
"coordinateTransformations": [
{
"scale": [0.13, 0.13],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -501,14 +587,19 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -517,7 +608,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -533,21 +626,26 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "t",
- "type": "time"
- },
+ "coordinateSystems": [
{
- "name": "c",
- "type": "channel"
- },
- {
- "name": "x",
- "type": "space"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "t",
+ "type": "time"
+ },
+ {
+ "name": "c",
+ "type": "channel"
+ },
+ {
+ "name": "x",
+ "type": "space"
+ }
+ ]
}
],
"datasets": [
@@ -556,7 +654,9 @@
"coordinateTransformations": [
{
"scale": [1, 1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -572,19 +672,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -593,7 +698,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": 0,
+ "output": "intrinsic"
}
]
}
@@ -609,19 +716,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -630,7 +742,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -652,19 +766,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -683,19 +802,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": []
@@ -710,19 +834,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
]
}
@@ -736,7 +865,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
"datasets": [
@@ -745,7 +874,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -761,19 +892,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "invalid",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "invalid",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -782,7 +918,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -798,19 +936,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -819,11 +962,15 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
},
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -839,7 +986,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
"axes": [],
@@ -849,7 +996,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -865,25 +1014,30 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "X",
- "type": "space"
- },
- {
- "name": "z",
- "type": "space"
- },
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space"
- },
- {
- "name": "x",
- "type": "space"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "X",
+ "type": "space"
+ },
+ {
+ "name": "z",
+ "type": "space"
+ },
+ {
+ "name": "y",
+ "type": "space"
+ },
+ {
+ "name": "x",
+ "type": "space"
+ }
+ ]
}
],
"datasets": [
@@ -892,7 +1046,9 @@
"coordinateTransformations": [
{
"scale": [1, 1, 1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -908,7 +1064,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": []
}
},
@@ -919,19 +1075,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -940,7 +1101,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
@@ -973,21 +1136,27 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
- ],
+ ]
+ ,
"datasets": [
{
"path": "0",
@@ -1005,19 +1174,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -1025,7 +1199,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "intrinsic"
}
]
}
diff --git a/tests/label_suite.json b/tests/label_suite.json
index 66a2d35d..ceeb9842 100644
--- a/tests/label_suite.json
+++ b/tests/label_suite.json
@@ -1,14 +1,14 @@
{
"description": "Tests for the image-label JSON schema",
"schema": {
- "id": "schemas/label.schema"
+ "id": "ngff_spec/schemas/label.schema"
},
"tests": [
{
"formerly": "image-label/minimal",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"colors": [
{
@@ -25,7 +25,7 @@
"formerly": "image-label/minimal_properties",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"colors": [
{
@@ -47,7 +47,7 @@
"formerly": "image-label/empty_colors",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"colors": []
}
@@ -59,7 +59,7 @@
"formerly": "image-label/empty_properties",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"properties": []
}
@@ -71,7 +71,7 @@
"formerly": "image-label/colors_no_label_value",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"colors": [
{
@@ -87,7 +87,7 @@
"formerly": "image-label/properties_no_label_value",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"properties": [
{
@@ -103,7 +103,7 @@
"formerly": "image-label/colors_rgba_length",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"colors": [
{
@@ -120,7 +120,7 @@
"formerly": "image-label/colors_rgba_type",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"colors": [
{
@@ -137,7 +137,7 @@
"formerly": "image-label/colors_duplicate",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {
"colors": [
{
diff --git a/tests/plate_suite.json b/tests/plate_suite.json
index 3db70de7..70bbf3ff 100644
--- a/tests/plate_suite.json
+++ b/tests/plate_suite.json
@@ -1,14 +1,14 @@
{
"description": "Tests for the plate JSON schema",
"schema": {
- "id": "schemas/plate.schema"
+ "id": "ngff_spec/schemas/plate.schema"
},
"tests": [
{
"formerly": "plate/minimal_no_acquisitions",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -36,7 +36,7 @@
"formerly": "plate/minimal_acquisitions",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -69,7 +69,7 @@
"formerly": "plate/missing_rows",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -92,7 +92,7 @@
"formerly": "plate/empty_rows",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -116,7 +116,7 @@
"formerly": "plate/duplicate_rows",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -147,7 +147,7 @@
"formerly": "plate/missing_columns",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"rows": [
{
@@ -170,7 +170,7 @@
"formerly": "plate/empty_columns",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [],
"rows": [
@@ -194,7 +194,7 @@
"formerly": "plate/duplicate_columns",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -225,7 +225,7 @@
"formerly": "plate/missing_wells",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -246,7 +246,7 @@
"formerly": "plate/empty_wells",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -268,7 +268,7 @@
"formerly": "plate/duplicate_rows",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -304,7 +304,7 @@
"formerly": "plate/missing_column_name",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -332,7 +332,7 @@
"formerly": "plate/missing_row_name",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -360,7 +360,7 @@
"formerly": "plate/missing_well_path",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -387,7 +387,7 @@
"formerly": "plate/missing_well_rowIndex",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -414,7 +414,7 @@
"formerly": "plate/missing_well_columnIndex",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -441,7 +441,7 @@
"formerly": "plate/well_1group",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -468,7 +468,7 @@
"formerly": "plate/well_3groups",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -495,7 +495,7 @@
"formerly": "plate/non_alphanumeric_column",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -523,7 +523,7 @@
"formerly": "plate/non_alphanumeric_row",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -551,7 +551,7 @@
"formerly": "plate/missing_acquisition_id",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -584,7 +584,7 @@
"formerly": "plate/non_integer_acquisition_id",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -617,7 +617,7 @@
"formerly": "plate/negative_acquisition_id",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -650,7 +650,7 @@
"formerly": "plate/non_integer_acquisition_maximumfieldcount",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -684,7 +684,7 @@
"formerly": "plate/acquisition_zero_maximumfieldcount",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -718,7 +718,7 @@
"formerly": "plate/acquisition_noninteger_starttime",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -752,7 +752,7 @@
"formerly": "plate/acquisition_negative_starttime",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -786,7 +786,7 @@
"formerly": "plate/acquisition_noninteger_endtime",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -820,7 +820,7 @@
"formerly": "plate/negative_endtime",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -854,7 +854,7 @@
"formerly": "plate/zero_field_count",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
diff --git a/tests/strict_image_suite.json b/tests/strict_image_suite.json
index b52fd2d3..486f936c 100644
--- a/tests/strict_image_suite.json
+++ b/tests/strict_image_suite.json
@@ -1,7 +1,7 @@
{
"description": "TBD",
"schema": {
- "id": "schemas/strict_image.schema"
+ "id": "ngff_spec/schemas/strict_image.schema"
},
"tests": [
{
@@ -9,43 +9,80 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
"name": "example",
- "axes": [
+ "coordinateSystems": [
{
- "name": "t",
- "type": "time",
- "unit": "millisecond"
- },
- {
- "name": "c",
- "type": "channel"
- },
- {
- "name": "z",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
+ "name": "world",
+ "axes": [
+ {
+ "name": "t",
+ "type": "time",
+ "unit": "millisecond"
+ },
+ {
+ "name": "c",
+ "type": "channel"
+ },
+ {
+ "name": "z",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
},
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "intrinsic",
+ "axes": [
+ {
+ "name": "t",
+ "type": "time",
+ "unit": "millisecond"
+ },
+ {
+ "name": "c",
+ "type": "channel"
+ },
+ {
+ "name": "z",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
- ],
+ ]
+ ,
"datasets": [
{
"path": "0",
"coordinateTransformations": [
{
"type": "scale",
- "scale": [1.0, 1.0, 0.5, 0.5, 0.5]
+ "scale": [1.0, 1.0, 0.5, 0.5, 0.5],
+ "input": "0",
+ "output": "intrinsic"
}
]
},
@@ -54,7 +91,9 @@
"coordinateTransformations": [
{
"type": "scale",
- "scale": [1.0, 1.0, 1.0, 1.0, 1.0]
+ "scale": [1.0, 1.0, 1.0, 1.0, 1.0],
+ "input": "1",
+ "output": "intrinsic"
}
]
},
@@ -63,7 +102,9 @@
"coordinateTransformations": [
{
"type": "scale",
- "scale": [1.0, 1.0, 2.0, 2.0, 2.0]
+ "scale": [1.0, 1.0, 2.0, 2.0, 2.0],
+ "input": "2",
+ "output": "intrinsic"
}
]
}
@@ -71,7 +112,9 @@
"coordinateTransformations": [
{
"type": "scale",
- "scale": [0.1, 1.0, 1.0, 1.0, 1.0]
+ "scale": [0.1, 1.0, 1.0, 1.0, 1.0],
+ "input": "world",
+ "output": "intrinsic"
}
],
"type": "gaussian",
@@ -95,19 +138,39 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
+ "name": "world",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
},
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "physical",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -116,7 +179,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "physical"
}
]
}
@@ -124,7 +189,9 @@
"coordinateTransformations": [
{
"scale": [10, 10],
- "type": "scale"
+ "type": "scale",
+ "input": "physical",
+ "output": "world"
}
],
"name": "image_with_coordinateTransformations",
@@ -143,7 +210,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"@id": "top",
"@type": "ngff:Image",
"multiscales": [
@@ -156,7 +223,9 @@
"coordinateTransformations": [
{
"type": "scale",
- "scale": [1, 1]
+ "scale": [1, 1],
+ "input": "path/to/0",
+ "output": "physical"
}
]
}
@@ -170,16 +239,21 @@
"multichannel": true
}
},
- "axes": [
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
+ "coordinateSystems": [
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "physical",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
]
}
@@ -193,19 +267,24 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
+ "coordinateSystems": [
{
- "name": "y",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "physical",
+ "axes": [
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -214,7 +293,9 @@
"coordinateTransformations": [
{
"scale": [1, 1],
- "type": "scale"
+ "type": "scale",
+ "input": "0",
+ "output": "physical"
}
]
}
@@ -235,32 +316,65 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"multiscales": [
{
- "axes": [
- {
- "name": "t",
- "type": "time"
- },
- {
- "name": "c",
- "type": "channel"
- },
+ "coordinateSystems": [
{
- "name": "z",
- "type": "space",
- "unit": "micrometer"
- },
- {
- "name": "y",
- "type": "space",
- "unit": "micrometer"
+ "name": "world",
+ "axes": [
+ {
+ "name": "t",
+ "type": "time"
+ },
+ {
+ "name": "c",
+ "type": "channel"
+ },
+ {
+ "name": "z",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
},
{
- "name": "x",
- "type": "space",
- "unit": "micrometer"
+ "name": "physical",
+ "axes": [
+ {
+ "name": "t",
+ "type": "time"
+ },
+ {
+ "name": "c",
+ "type": "channel"
+ },
+ {
+ "name": "z",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "y",
+ "type": "space",
+ "unit": "micrometer"
+ },
+ {
+ "name": "x",
+ "type": "space",
+ "unit": "micrometer"
+ }
+ ]
}
],
"datasets": [
@@ -269,11 +383,9 @@
"coordinateTransformations": [
{
"scale": [1, 1, 0.5, 0.13, 0.13],
- "type": "scale"
- },
- {
- "translation": [0, 9, 0.5, 25.74, 21.58],
- "type": "translation"
+ "type": "scale",
+ "input": "0",
+ "output": "physical"
}
]
},
@@ -282,11 +394,21 @@
"coordinateTransformations": [
{
"scale": [1, 1, 1, 0.26, 0.26],
- "type": "scale"
+ "type": "scale",
+ "input": "1",
+ "output": "physical"
}
]
}
],
+ "coordinateTransformations": [
+ {
+ "translation": [0, 9, 0.5, 25.74, 21.58],
+ "type": "translation",
+ "input": "intrinsic",
+ "output": "world"
+ }
+ ],
"name": "image_with_omero_metadata",
"type": "foo",
"metadata": {
@@ -331,7 +453,7 @@
"defaultZ": 2,
"model": "color"
},
- "version": "0.5-dev"
+ "version": "0.6dev2"
}
}
},
diff --git a/tests/strict_label_suite.json b/tests/strict_label_suite.json
index 1b3535c2..d72dc241 100644
--- a/tests/strict_label_suite.json
+++ b/tests/strict_label_suite.json
@@ -1,14 +1,14 @@
{
"description": "Tests for the strict image-label JSON schema",
"schema": {
- "id": "schemas/strict_label.schema"
+ "id": "ngff_spec/schemas/strict_label.schema"
},
"tests": [
{
"formerly": "image-label/no_colors",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"image-label": {}
}
},
diff --git a/tests/strict_plate_suite.json b/tests/strict_plate_suite.json
index 7cea0747..7a994108 100644
--- a/tests/strict_plate_suite.json
+++ b/tests/strict_plate_suite.json
@@ -1,14 +1,14 @@
{
"description": "Tests for the strict plate JSON schema",
"schema": {
- "id": "schemas/strict_plate.schema"
+ "id": "ngff_spec/schemas/strict_plate.schema"
},
"tests": [
{
"formerly": "plate/strict_no_acquisitions",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -37,7 +37,7 @@
"formerly": "plate/missing_name",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"columns": [
{
@@ -65,7 +65,7 @@
"formerly": "plate/strict_acquisitions",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -101,7 +101,7 @@
"formerly": "plate/missing_acquisition_name",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
@@ -136,7 +136,7 @@
"formerly": "plate/missing_acquisition_maximumfieldcount",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"plate": {
"acquisitions": [
{
diff --git a/tests/strict_well_suite.json b/tests/strict_well_suite.json
index f56b6c24..ee10a2c0 100644
--- a/tests/strict_well_suite.json
+++ b/tests/strict_well_suite.json
@@ -1,14 +1,14 @@
{
"description": "Tests for the strict well JSON schema",
"schema": {
- "id": "schemas/strict_well.schema"
+ "id": "ngff_spec/schemas/strict_well.schema"
},
"tests": [
{
"formerly": "well/strict_no_acquisitions",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"well": {
"images": [
{
@@ -24,7 +24,7 @@
"formerly": "plate/strict_acquisitions",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"well": {
"images": [
{
diff --git a/tests/test_validation.py b/tests/test_validation.py
index c2844f1a..5de3ecb7 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -11,13 +11,13 @@
from jsonschema.exceptions import ValidationError
schema_store = {}
-for schema_filename in glob.glob("schemas/*"):
+for schema_filename in glob.glob("ngff_spec/schemas/*"):
with open(schema_filename) as f:
schema = json.load(f)
schema_store[schema["$id"]] = schema
GENERIC_SCHEMA = schema_store[
- "https://ngff.openmicroscopy.org/0.5/schemas/ome_zarr.schema"
+ "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome_zarr.schema"
]
print(schema_store)
@@ -61,7 +61,7 @@ def pytest_generate_tests(metafunc):
suites: List[Schema] = []
ids: List[str] = []
schema_store = {}
- for filename in glob.glob("schemas/*.schema"):
+ for filename in glob.glob("ngff_spec/schemas/*.schema"):
with open(filename) as o:
schema = json.load(o)
schema_store[schema["$id"]] = schema
@@ -121,7 +121,7 @@ def test_example_configs():
Test that all example folders have a config file
"""
missing = []
- for subdir in os.walk("examples"):
+ for subdir in os.walk("ngff_spec/examples"):
has_examples = glob.glob(f"{subdir[0]}/*.json")
has_config = glob.glob(f"{subdir[0]}/.config.json")
if has_examples and not has_config:
diff --git a/tests/well_suite.json b/tests/well_suite.json
index 7fbf8ca2..9f9fe663 100644
--- a/tests/well_suite.json
+++ b/tests/well_suite.json
@@ -1,14 +1,14 @@
{
"description": "Tests for the well JSON schema",
"schema": {
- "id": "schemas/well.schema"
+ "id": "ngff_spec/schemas/well.schema"
},
"tests": [
{
"formerly": "well/minimal_no_acquisition",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"well": {
"images": [
{
@@ -24,7 +24,7 @@
"formerly": "well/minimal_acquisitions",
"data": {
"ome": {
- "version": "0.5",
+ "version": "0.6dev2",
"well": {
"images": [
{
From ecec30b27e7317902a82fc6ba9985a78169bb6cd Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 3 Nov 2025 22:55:49 +0100
Subject: [PATCH 40/47] sync PR with latest RFC5 proposal (#2)
Co-authored-by: Will Moore <900055+will-moore@users.noreply.github.com>
Co-authored-by: David Stansby
Co-authored-by: Davis Bennett
---
.../multiscales_example.json | 42 +--
ngff_spec/specification.md | 315 +++++++++++-------
2 files changed, 208 insertions(+), 149 deletions(-)
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_example.json b/ngff_spec/examples/multiscales_strict/multiscales_example.json
index a07d34d1..defbde1b 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_example.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_example.json
@@ -3,21 +3,21 @@
"node_type": "group",
"attributes": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.5",
"multiscales": [
{
- "name": "physical",
+ "name": "example",
"coordinateSystems": [
- {
- "name": "physical",
- "axes": [
- { "name": "t", "type": "time", "unit": "millisecond" },
- { "name": "c", "type": "channel" },
- { "name": "z", "type": "space", "unit": "micrometer" },
- { "name": "y", "type": "space", "unit": "micrometer" },
- { "name": "x", "type": "space", "unit": "micrometer" }
- ]
- }
+ {
+ "name": "intrinsic",
+ "axes": [
+ { "name": "t", "type": "time", "unit": "millisecond" },
+ { "name": "c", "type": "channel" },
+ { "name": "z", "type": "space", "unit": "micrometer" },
+ { "name": "y", "type": "space", "unit": "micrometer" },
+ { "name": "x", "type": "space", "unit": "micrometer" }
+ ]
+ }
],
"datasets": [
{
@@ -25,11 +25,11 @@
"coordinateTransformations": [
{
// the voxel size for the first scale level (0.5 micrometer)
- // the time unit (0.1 milliseconds), which is the same for each scale level
+ // and the time unit (0.1 milliseconds), which is the same for each scale level
"type": "scale",
"scale": [0.1, 1.0, 0.5, 0.5, 0.5],
"input": "0",
- "output": "physical"
+ "output": "intrinsic"
}
]
},
@@ -37,12 +37,12 @@
"path": "1",
"coordinateTransformations": [
{
- // the voxel size for the second scale level (1 micrometer)
- // the time unit (0.1 milliseconds), which is the same for each scale level
+ // the voxel size for the second scale level (downscaled by a factor of 2 -> 1 micrometer)
+ // and the time unit (0.1 milliseconds), which is the same for each scale level
"type": "scale",
"scale": [0.1, 1.0, 1.0, 1.0, 1.0],
"input": "1",
- "output": "physical"
+ "output": "intrinsic"
}
]
},
@@ -50,12 +50,12 @@
"path": "2",
"coordinateTransformations": [
{
- // the voxel size for the third scale level (2 micrometer)
- // the time unit (0.1 milliseconds), which is the same for each scale level
+ // the voxel size for the third scale level (downscaled by a factor of 4 -> 2 micrometer)
+ // and the time unit (0.1 milliseconds), which is the same for each scale level
"type": "scale",
"scale": [0.1, 1.0, 2.0, 2.0, 2.0],
"input": "2",
- "output": "physical"
+ "output": "intrinsic"
}
]
}
@@ -72,4 +72,4 @@
]
}
}
-}
+}
\ No newline at end of file
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index 62e208d6..ea4eac24 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -161,17 +161,16 @@ The OME-Zarr Metadata version MUST be consistent within a hierarchy.
### "coordinateSystems" metadata
(coordinate-systems-md)=
-A "coordinate system" is a collection of "axes" / dimensions with a name.
+A `coordinateSystem` is a JSON object with a "name" field and a "axes" field.
Every coordinate system:
- MUST contain the field "name".
The value MUST be a non-empty string that is unique among all entries under `coordinateSystems`.
- MUST contain the field "axes", whose value is an array of valid "axes" (see below).
-The order of the `"axes"` list matters
-and defines the index of each array dimension and coordinates for points in that coordinate system.
-For the above example, the `"x"` dimension is the last dimension.
+The elements of `"axes"` correspond to the index of each array dimension and coordinates for points in that coordinate system.
+For the below example, the `"x"` dimension is the last dimension.
The "dimensionality" of a coordinate system is indicated by the length of its "axes" array.
-The "volume_micrometers" example coordinate system above is three dimensional (3D).
+The "volume_micrometers" example coordinate system below is three dimensional (3D).
````{admonition} Example
@@ -191,14 +190,14 @@ Coordinate Systems metadata example
The axes of a coordinate system (see below) give information
about the types, units, and other properties of the coordinate system's dimensions.
-Axis `name`s may contain semantically meaningful information, but can be arbitrary.
+Axis names may contain semantically meaningful information, but can be arbitrary.
As a result, two coordinate systems that have identical axes in the same order
-ay not be "the same" in the sense that measurements at the same point
+may not be "the same" in the sense that measurements at the same point
refer to different physical entities and therefore should not be analyzed jointly.
Tasks that require images, annotations, regions of interest, etc.,
-SHOULD ensure that they are in the same coordinate system (same name, with identical axes)
+SHOULD ensure that they are in the same coordinate system (same name and location within the Zarr hierarchy, with identical axes)
or can be transformed to the same coordinate system before doing analysis.
-See the example below.
+See the [example below](#spec:example:coordinate_transformation).
#### "axes" metadata
@@ -208,13 +207,13 @@ and adds an interpretation to the samples along that dimension.
It is a list of dictionaries,
where each dictionary describes a dimension (axis) and:
- MUST contain the field "name" that gives the name for this dimension.
- The values MUST be unique across all "name" fields.
+ The values MUST be unique across all "name" fields in the same coordinate system.
- SHOULD contain the field "type".
It SHOULD be one of the strings "array", "space", "time", "channel", "coordinate", or "displacement"
but MAY take other string values for custom axis types that are not part of this specification yet.
- MAY contain the field "discrete".
The value MUST be a boolean,
- and is `true` if the axis represents a discrete dimension.
+ and is `true` if the axis represents a discrete dimension (see below for details).
- SHOULD contain the field "unit" to specify the physical unit of this dimension.
The value SHOULD be one of the following strings,
which are valid units according to UDUNITS-2.
@@ -224,7 +223,7 @@ where each dictionary describes a dimension (axis) and:
The value MUST be a string,
and can provide a longer name or description of an axis and its properties.
-If part of metadata, the length of "axes" MUST be equal to the number of dimensions of the arrays that contain the image data.
+The length of "axes" MUST be equal to the number of dimensions of the arrays that contain the image data.
Arrays are inherently discrete (see Array coordinate systems, below)
but are often used to store discrete samples of a continuous variable.
@@ -233,7 +232,7 @@ If an axis is continuous (`"discrete" : false`), it indicates that interpolation
Axes representing `space` and `time` are usually continuous.
Similarly, joint interpolation across axes is well-defined only for axes of the same `type`.
In contrast, discrete axes (`"discrete" : true`) may be indexed only by integers.
-Axes of representing a `channel`, `coordinate`, or `displacement` are usually discrete.
+Axes representing a channel, coordinate, or displacement are usually discrete.
```{note}
The most common methods for interpolation are "nearest neighbor", "linear", "cubic", and "windowed sinc".
@@ -251,19 +250,28 @@ Indicating that choice explicitly will be important for interoperability.
This is possible by using **array coordinate systems**.
Every array has a default coordinate system whose parameters need not be explicitly defined.
-The dimensionality of each array coordinate system equals the dimensionality of its corresponding zarr array.
+The dimensionality of each array coordinate system equals the dimensionality of its corresponding Zarr array.
Its name is the path to the array in the container,
-its axes have `"type":"array"`, are unitless, and have default `name`s.
-The i-th axis has `"name":"dim_i"` (these are the same default names used by [xarray](https://docs.xarray.dev/en/stable/user-guide/terminology.html)).
-The `dimension_names` must be unique and non-null.
+its axes have `"type": "array"`, are unitless, and have default names.
+The i-th axis has `"name": "dim_i"` (these are the same default names used by [xarray](https://docs.xarray.dev/en/stable/user-guide/terminology.html)).
+As with all coordinate systems, the dimension names must be unique and non-null.
````{admonition} Example
-```{literalinclude} examples/coordinate_systems/arrayCoordSys.json
-:language: json
-```
+```json
+{
+ "arrayCoordinateSystem" : {
+ "name" : "myDataArray",
+ "axes" : [
+ {"name": "dim_0", "type": "array"},
+ {"name": "dim_1", "type": "array"},
+ {"name": "dim_2", "type": "array"}
+ ]
+ }
+}
-For example, if `0/zarr.json` contains:
+```
+For example, if 0/zarr.json contains:
```jsonc
{
"zarr_format": 3,
@@ -272,14 +280,14 @@ For example, if `0/zarr.json` contains:
//...
}
```
+
Then `dim_0` has length 4, `dim_1` has length 3, and `dim_2` has length 5.
+
````
-The dimensionality of each array coordinate system equals the dimensionality of its corresponding zarr array.
-The axis with name `"dim_i"` is the i-th element of the `"axes"` list.
-The axes and their order align with the `shape` attribute in the zarr array attributes (in `.zarray`),
+The axes and their order align with the shape of the corresponding zarr array,
and whose data depends on the byte order used to store chunks.
-As described in the [zarr array metadata](https://zarr.readthedocs.io/en/stable/spec/v2.html#arrays),
+As described in the [Zarr array metadata](https://zarr.readthedocs.io/en/stable/spec/v3.html#arrays),
the last dimension of an array in "C" order are stored contiguously on disk or in-memory when directly loaded.
The name and axes names MAY be customized by including a `arrayCoordinateSystem` field
@@ -387,10 +395,13 @@ Conforming readers:
## "coordinateTransformations" metadata
(coord-trafo-md)=
-"coordinateTransformations" describe the mapping between two coordinate systems (defined by [`coordinateSystems`](#coordinate-systems-md)).
+"coordinateTransformations" describe the mapping between two coordinate systems (defined by [coordinateSystems](#coordinate-systems-md)).
For example, to map an array's discrete coordinate system to its corresponding physical coordinates.
Coordinate transforms are in the "forward" direction.
-They represent functions from *points* in the input space to *points* in the output space.
+This means they represent functions from *points* in the input space to *points* in the output space
+(see [example below](#spec:example:coordinate_transformation_scale)).
+
+They:
- MUST contain the field "type" (string).
- MUST contain any other fields required by the given "type" (see table below).
@@ -406,82 +417,115 @@ The following transformations are supported:
| Type | Fields | Description |
|------|--------|-------------|
-| `identity` | | The identity transformation is the default transformation and is typically not explicitly defined. |
-| `mapAxis` | `"mapAxis":List[number]` | A `mapAxis` transformation specifies an axis permutation as a transpose array of integer indices that refer to the ordering of the axes in the respective coordinate system. |
-| `translation` | one of:
`"translation":List[number]`,
`"path":str` | translation vector, stored either as a list of numbers (`"translation"`) or as a zarr array at a location in this container (`path`). |
-| `scale` | one of:
`"scale":List[number]`,
`"path":str` | scale vector, stored either as a list of numbers (`scale`) or as a zarr array at a location in this container (`path`). |
-| `affine` | one of:
`"affine": List[List[number]]`,
`"path":str` | affine transformation matrix stored as a 2D array, either directly in JSON using the affine field or as a zarr array at a location in this container (path). If both are present, the zarr array at path should be used. |
-| `rotation` | one of:
`"rotation":List[List[number]]`,
`"path":str` | rotation transformation matrix stored as a 2D array stored either with json or as a zarr array at a location in this container (path). If both are present, the zarr array parameters at path are used. |
-| `sequence` | `"transformations":List[Transformation]` | A sequence of transformations, Applying the sequence applies the composition of all transforms in the list, in order. |
-| `displacements` | `"path":str`
`"interpolation":str` | Displacement field transformation located at (path). |
-| `coordinates` | `"path":str`
`"interpolation":str` | Coordinate field transformation located at (path). |
-| `inverseOf` | `"transformation":Transformation` | The inverse of a transformation. Useful if a transform is not closed-form invertible. See Forward and inverse for details and examples. |
-| `bijection` | `"forward":Transformation`
`"inverse":Transformation` | Explicitly define an invertible transformation by providing a forward transformation and its inverse. |
-| `byDimension` | `"transformations":List[Transformation]`,
`"input_axes": List[str]`,
`"output_axes": List[str]` | Define a high dimensional transformation using lower dimensional transformations on subsets of dimensions. |
+| [`identity`](#identity-md) | | The identity transformation is the do-nothing transformation and is typically not explicitly defined. |
+| [`mapAxis`](#mapaxis-md) | `"mapAxis":List[number]` | an axis permutation as a transpose array of integer indices that refer to the ordering of the axes in the respective coordinate system. |
+| [`translation`](#translation-md) | one of:
`"translation":List[number]`,
`"path":str` | Translation vector, stored either as a list of numbers (`"translation"`) or as a zarr array at a location in this container (`path`). |
+| [`scale`](#scale-md) | one of:
`"scale":List[number]`,
`"path":str` | Scale vector, stored either as a list of numbers (`scale`) or as a zarr array at a location in this container (`path`). |
+| [`affine`](#affine-md) | one of:
`"affine":List[List[number]]`,
`"path":str` | 2D affine transformation matrix stored either with JSON (`affine`) or as a zarr array at a location in this container (`path`). |
+| [`rotation`](#rotation-md) | one of:
`"rotation":List[List[number]]`,
`"path":str` | 2D rotation transformation matrix stored as an array stored either with json (`rotation`) or as a zarr array at a location in this container (`path`).|
+| [`sequence`](#sequence-md) | `"transformations":List[Transformation]` | sequence of transformations. Applying the sequence applies the composition of all transforms in the list, in order. |
+| [`displacements`](#coordinates-and-displacements-md) | `"path":str`
`"interpolation":str` | Displacement field transformation located at `path`. |
+| [`coordinates`](#coordinates-and-displacements-md) | `"path":str`
`"interpolation":str` | Coordinate field transformation located at `path`. |
+| [`inverseOf`](#inverseof-md) | `"transformation":Transformation` | The inverse of a transformation. Useful if a transform is not closed-form invertible. See forward and inverse of [bijections](#bijection) for details and examples. |
+| [`bijection`](#bijection-md) | `"forward":Transformation`
`"inverse":Transformation` | An invertible transformation providing an explicit forward transformation and its inverse. |
+| [`byDimension`](#bydimension-md) | `"transformations":List[Transformation]`,
`"input_axes": List[str]`,
`"output_axes": List[str]` | A high dimensional transformation using lower dimensional transformations on subsets of dimensions. |
+
+Implementations SHOULD prefer to store transformations as a sequence of less expressive transformations where possible
+(e.g., sequence[translation, rotation], instead of affine transformation with translation/rotation).
+
+::::{admonition} Example
+(spec:example:coordinate_transformation_scale)=
+:class: dropdown
+
+```json
+{
+ "coordinateSystems": [
+ { "name": "in", "axes": [{"name": "j"}, {"name": "i"}] },
+ { "name": "out", "axes": [{"name": "y"}, {"name": "x"}] }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "scale",
+ "scale": [2, 3.12],
+ "input": "in",
+ "output": "out"
+ }
+ ]
+}
+
+```
+
+For example, the scale transformation above defines the function:
+
+```
+x = 3.12 * i
+y = 2 * j
+```
+
+i.e., the mapping from the first input axis to the first output axis is determined by the first scale parameter.
+::::
Conforming readers:
- MUST parse `identity`, `scale`, `translation` transformations;
- SHOULD parse `mapAxis`, `affine`, `rotation` transformations;
-- SHOULD display an informative warning if encountering transformations that cannot be parsed;
+- SHOULD display an informative warning if encountering transformations that cannot be parsed or displayed by a viewer;
- SHOULD be able to apply transformations to points;
- SHOULD be able to apply transformations to images;
Coordinate transformations can be stored in multiple places to reflect different usecases.
-- Multiscale transformations represent a special case of transformations
- and are explained [below](#multiscales-md).
-- Additional transformations for single images MUST be stored under a field `coordinateTransformations`
+- Transformations in individual multiscale datasets represent a special case of transformations
+ and are explained [below](#multiscales-metadata).
+- Additional transformations for single multiscale images MUST be stored under a field `coordinateTransformations`
in the multiscales dictionaries.
- This `coordinateTransformations` field MUST contain a list of valid [transformations](#trafo-types-md).
+ This `coordinateTransformations` field MUST contain a list of valid [transformations](#transformation-types).
- Transformations between two or more images MUST be stored in the attributes of a parent zarr group.
For transformations that store data or parameters in a zarr array,
- those zarr arrays SHOULD be stored in a zarr group `coordinateTransformations`.
+ those zarr arrays SHOULD be stored in a zarr group called "coordinateTransformations".
-Implementations SHOULD prefer to store transformations as a sequence of less expressive transformations
-(i.e., sequence[translation, rotation] instead of affine transformation with translation/rotation) component.
store.zarr # Root folder of the zarr store
│
├── zarr.json # coordinate transformations describing the relationship between two image coordinate systems
│ # are stored in the attributes of their parent group.
-│ # transformations between 'volume' and 'crop' coordinate systems are stored here.
+│ # transformations between coordinate systems in the 'volume' and 'crop' multiscale images are stored here.
│
-├── coordinateTransformations # transformations that use array storage go in a "coordinateTransformations" zarr group.
+├── coordinateTransformations # transformations that use array storage for their parameters should go in a zarr group named "coordinateTransformations".
│ └── displacements # for example, a zarr array containing a displacement field
│ └── zarr.json
│
├── volume
│ ├── zarr.json # group level attributes (multiscales)
-│ └── 0 # a group containing the 0th scale
-│ └── image # a zarr array
+│ └── 0 # a group containing the 0th scale
+│ └── image # a zarr array
│ └── zarr.json # physical coordinate system and transformations here
└── crop
├── zarr.json # group level attributes (multiscales)
- └── 0 # a group containing the 0th scale
- └── image # a zarr array
+ └── 0 # a group containing the 0th scale
+ └── image # a zarr array
└── zarr.json # physical coordinate system and transformations here
::::{admonition} Example
:class: dropdown
+(spec:example:coordinate_transformation)=
Two instruments simultaneously image the same sample from two different angles,
and the 3D data from both instruments are calibrated to "micrometer" units.
-Two samples are collected ("sampleA" and "sampleB").
-An analysis of sample A requires measurements from both instruments' images at certain points in space.
+An analysis of sample A requires measurements from images taken from both instruments at certain points in space.
Suppose a region of interest (ROI) is determined from the image obtained from instrument 2,
but quantification from that region is needed for instrument 1.
Since measurements were collected at different angles,
-a measurement by instrument 1 at the point with coordinates (x,y,z)
-may not correspond to the measurement at the same point in instrument 2
+a measurement by instrument 1 at the point with image array coordinates (x,y,z)
+may not correspond to the measurement at the same array coordinates in instrument 2
(i.e., it may not be the same physical location in the sample).
-To analyze both images together, they must be in the same coordinate system.
+To analyze both images together, they must be transformed to a common coordinate system.
The set of coordinate transformations encodes relationships between coordinate systems,
-specifically, how to convert points and images to different coordinate systems.
+specifically, how to convert points from one coordinate system to another.
Implementations can apply the coordinate transform to images or points
in coordinate system "sampleA_instrument2" to bring them into the "sampleA_instrument1" coordinate system.
-In this case, the ROI should be transformed to the "sampleA_image1" coordinate system,
+In this case, image data within the ROI defined in image2 should be transformed to the "sampleA_image1" coordinate system,
then used for quantification with the instrument 1 image.
The `coordinateTransformations` in the parent-level metadata would contain the following data.
@@ -499,7 +543,7 @@ under `coordinateTransformations/sampleA_instrument2-to-instrument1` as shown ab
]
```
-And the image under `root/sampleA_instrument1` would have the following as the first coordinate system:
+And the image at the path `sampleA_instrument1` would have the following as the first coordinate system:
```json
"coordinateSystems": [
@@ -514,7 +558,7 @@ And the image under `root/sampleA_instrument1` would have the following as the f
]
```
-The image under `root/sampleA_instrument2` would have this as the first listed coordinate system:
+The image at path `sampleA_instrument2` would have this as the first listed coordinate system:
```json
[
@@ -530,29 +574,32 @@ The image under `root/sampleA_instrument2` would have this as the first listed c
```
::::
-### Additional details
+#### Additional details
Most coordinate transformations MUST specify their input and output coordinate systems
using `input` and `output` with a string value
that MUST correspond to the name of a coordinate system or the path to a multiscales group.
-Exceptions are if the coordinate transformation appears in the `transformations` list of a `sequence`
-or is the `transformation` of an `inverseOf` transformation.
+Exceptions are if the coordinate transformation is wrapped in another transformation,
+e.g. as part of a `transformations` list of a `sequence` or
+as `transformation` of an `inverseOf` transformation.
In these two cases input and output could, in some cases, be omitted (see below for details).
-
-If used in a parent-level zarr-group, the `input` field MUST be a path to the input image.
-The authoritative coordinate system for the input image is the first `coordinateSystem` defined therein.
-The `output` field can be a `path` to an output image or the name of a `coordinateSystem` defined in the parent-level zarr group.
-If the names of `input` or `output` can be both a `path` or the name of a `coordinateSystem`, `coordinateSystem` MUST take precedent.
If unused, the `input` and `output` fields MAY be null.
-For usage in multiscales, see [multiscales section](#multiscales-md) for details.
+If used in a parent-level zarr-group, the `input` and `output` fields
+can be the name of a `coordinateSystem` in the same parent-level group or the path to a multiscale image group.
+If either `input` or `output` is a path to a multiscale image group,
+the authoritative coordinate system for the respective image is the first `coordinateSystem` defined therein.
+If the names of `input` or `output` correspond to both an existing path to a multiscale image group
+and the name of a `coordinateSystem` defined in the same metadata document,
+the `coordinateSystem` MUST take precedent.
+
+For usage in multiscales, see [the multiscales section](#multiscales-md) for details.
Coordinate transformations are functions of *points* in the input space to *points* in the output space.
We call this the "forward" direction.
Points are ordered lists of coordinates,
where a coordinate is the location/value of that point along its corresponding axis.
The indexes of axis dimensions correspond to indexes into transformation parameter arrays.
-Examples are given below in the respective [transformation type](#trafo-types-md) sections.
When rendering transformed images and interpolating,
implementations may need the "inverse" transformation -
@@ -585,7 +632,7 @@ or MAY output a warning that the requested operation is unsupported.
#### Matrix transformations
(matrix-trafo-md)=
-Two transformation types ([affine](#affine-md) and [rotation](#rotation-md)) are parametrized by matrices.
+Two transformation types ([affine](#affine) and [rotation](#rotation)) are parametrized by matrices.
Matrices are applied to column vectors that represent points in the input coordinate system.
The first and last axes in a coordinate system correspond to the top and bottom entries in the column vector, respectively.
Matrices are stored as two-dimensional arrays, either as json or in a zarr array.
@@ -631,8 +678,8 @@ because it is computed with the matrix-vector multiplication:
### Transformation types
(trafo-types-md)=
-Input and output dimensionality may be determined by the value of the `input` and `output` fields, respectively.
-If the value of `input` is an array, its shape gives the input dimension,
+Input and output dimensionality may be determined by the coordinate system referred to by the `input` and `output` fields, respectively.
+If the value of `input` is a path to an array, its shape gives the input dimension,
otherwise it is given by the length of `axes` for the coordinate system with the name of the `input`.
If the value of `output` is an array, its shape gives the output dimension,
otherwise it is given by the length of `axes` for the coordinate system with the name of the `output`.
@@ -645,7 +692,8 @@ The position of the i-th axis of the output coordinate system
is set to the position of the ith axis of the input coordinate system.
`identity` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
+The `input` and `output` fields MAY be omitted if wrapped in another transformation that provides `input`/`output`
+(e.g., [`sequence`](#sequence-md), [`inverseOf`](#inverseof-md), ['byDimension](#bydimension-md) or [`bijection`](#bijection-md)).
::::{admonition} Example
:class: dropdown
@@ -674,8 +722,11 @@ Each integer in the array MUST be a valid zero-based index into the input coordi
(i.e., between 0 and N-1 for an N-dimensional input).
Each index MUST appear exactly once in the array.
The value at position `i` in the array indicates which input axis becomes the `i`-th output axis.
+`mapAxis` transforms are invertible.
+
+The `input` and `output` fields MAY be omitted if wrapped in another transformation that provides `input`/`output`
+(e.g., [`sequence`](#sequence-md), [`inverseOf`](#inverseof-md), ['byDimension](#bydimension-md) or [`bijection`](#bijection-md)).
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
::::{admonition} Example 1
:class: dropdown
@@ -731,7 +782,8 @@ Input and output dimensionality MUST be identical
and MUST equal the the length of the "translation" array (N).
`translation` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
+The `input` and `output` fields MAY be omitted if wrapped in another transformation that provides `input`/`output`
+(e.g., [`sequence`](#sequence-md), [`inverseOf`](#inverseof-md), ['byDimension](#bydimension-md) or [`bijection`](#bijection-md)).
path
: The path to a zarr-array containing the translation parameters.
@@ -766,7 +818,8 @@ and MUST equal the the length of the "scale" array (N).
Values in the `scale` array SHOULD be non-zero;
in that case, `scale` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
+The `input` and `output` fields MAY be omitted if wrapped in another transformation that provides `input`/`output`
+(e.g., [`sequence`](#sequence-md), [`inverseOf`](#inverseof-md), ['byDimension](#bydimension-md) or [`bijection`](#bijection-md)).
path
: The path to a zarr-array containing the scale parameters.
@@ -814,7 +867,8 @@ This transformation type may be (but is not necessarily) invertible
when `N` equals `M`.
The matrix MUST be stored as a 2D array either as json or as a zarr array.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
+The `input` and `output` fields MAY be omitted if wrapped in another transformation that provides `input`/`output`
+(e.g., [`sequence`](#sequence-md), [`inverseOf`](#inverseof-md), ['byDimension](#bydimension-md) or [`bijection`](#bijection-md)).
path
: The path to a zarr-array containing the affine parameters.
@@ -822,7 +876,7 @@ The array at this path MUST be 2D whose shape MUST be `(M)x(N+1)`.
affine
: The affine parameters stored in JSON.
-The matrix MUST be stored as 2D nested array
+The matrix MUST be stored as 2D nested array (an array of arrays of numbers)
where the outer array MUST be length `M` and the inner arrays MUST be length `N+1`.
::::{admonition} Example 1
@@ -900,14 +954,15 @@ these axes are typically not transformed, but must be represented in the transfo
(rotation-md)=
`rotation`s are [matrix transformations](#matrix-trafo-md) that are special cases of affine transformations.
-When possible, a rotation transformation SHOULD be preferred to its equivalent affine.
+When possible, a rotation transformation SHOULD be used instead of an equivalent affine.
Input and output dimensionality (N) MUST be identical.
Rotations are stored as `NxN` matrices, see below,
and MUST have determinant equal to one, with orthonormal rows and columns.
The matrix MUST be stored as a 2D array either as json or in a zarr array.
`rotation` transformations are invertible.
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
+The `input` and `output` fields MAY be omitted if wrapped in another transformation that provides `input`/`output`
+(e.g., [`sequence`](#sequence-md), [`inverseOf`](#inverseof-md), ['byDimension](#bydimension-md) or [`bijection`](#bijection-md)).
path
: The path to an array containing the affine parameters.
@@ -915,7 +970,7 @@ The array at this path MUST be 2D whose shape MUST be `N x N`.
rotation
: The parameters stored in JSON.
-The matrix MUST be stored as a 2D nested array where the outer array MUST be length `N`
+The matrix MUST be stored as a 2D nested array (an array of arrays of numbers) where the outer array MUST be length `N`
and the inner arrays MUST be length `N`.
::::{admonition} Example
@@ -937,23 +992,24 @@ y = 1*i + 0*j
#### inverseOf
(inverseOf-md)=
-An `inverseOf` transformation contains another transformation, which is often non-linear.
-It indicates that transforming points from output to input coordinate systems
+An `inverseOf` transformation contains another transformation (often non-linear),
+and indicates that transforming points from output to input coordinate systems
is possible using the contained transformation.
+Transforming points from the input to the output coordinate systems
+requires the inverse of the contained transformation (if it exists).
The `input` and `output` fields MAY be omitted for `inverseOf` transformations
if those fields may be omitted for the transformation it wraps.
```{note}
Software libraries that perform image registration
-often return the transformation from fixed (output) image coordinates to moving (input) image coordinates,
-because this "inverse" transformation is most often required when rendering the transformed moving image.
+often return the transformation from fixed image coordinates to moving image coordinates,
+because this "inverse" transformation is most often required
+when rendering the transformed moving image.
Results such as this may be enclosed in an `inverseOf` transformation.
This enables the "outer" coordinate transformation to specify the moving image coordinates
as `input` and fixed image coordinates as `output`,
a choice that many users and developers find intuitive.
-At the same time, registration libraries can interpret the wrapped, inverted transformation
-as the correct corresponding transformation from fixed (output) to moving (input) coordinates.
```
::::{admonition} Example
@@ -979,6 +1035,9 @@ The output of the last transformation is the result of the sequence.
A sequence transformation MUST NOT be part of another sequence transformation.
The `input` and `output` fields MUST be included for sequence transformations.
+transformations
+: A non-empty array of transformations.
+
````{note}
Considering transformations as functions of points,
@@ -993,9 +1052,6 @@ f2(f1(f0(x)))
````
-transformations
-: A non-empty array of transformations.
-
::::{admonition} Example
:class: dropdown
@@ -1031,7 +1087,8 @@ These transformation types refer to an array at location specified by the `"path
The input and output coordinate systems for these transformations ("input / output coordinate systems")
constrain the array size and the coordinate system metadata for the array ("field coordinate system").
-The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequence-md) transformation.
+The `input` and `output` fields MAY be omitted if wrapped in another transformation that provides `input`/`output`
+(e.g., [`sequence`](#sequence-md), [`inverseOf`](#inverseof-md), ['byDimension](#bydimension-md) or [`bijection`](#bijection-md)).
* If the input coordinate system has `N` axes,
the array at location path MUST have `N+1` dimensions
@@ -1043,37 +1100,40 @@ The `input` and `output` fields MAY be omitted if part of a [`sequence`](#sequen
* If the output coordinate system has `M` axes,
the length of the array along the `coordinate`/`displacement` dimension MUST be of length `M`.
-The i-th value of the array along the `coordinate` or `displacement` axis refers
-to the coordinate or displacement of the i-th output axis.
-See the example below.
+The `i`th value of the array along the `coordinate` or `displacement` axis refers to the coordinate or displacement
+of the `i`th output axis. See the example below.
`coordinates` and `displacements` transformations are not invertible in general,
but implementations MAY approximate their inverses.
Metadata for these coordinate transforms have the following fields:
-path
-: The location of the coordinate array in this (or another) container.
+
+ - path
+ - The location of the coordinate array in this (or another) container.
+ - interpolation
+ - The
interpolation attributes MAY be provided.
+ Its value indicates the interpolation to use
+ if transforming points not on the array's discrete grid.
+ Values could be:
+
+ linear (default)
+ nearest
+ cubic
+
+
-interpolation
-: The `interpolation` attributes MAY be provided.
- It's value indicates the interpolation to use
- if transforming points not on the array's discrete grid.
- Values could be:
- - `linear` (default)
- - `nearest`
- - `cubic`
For both `coordinates` and `displacements`,
-the array data at referred to by `path` MUST define [`coordinateSystems`](#coordinate-systems-md) and
-[`coordinateTransformations`](coord-trafo-md) metadata:
+the array data at referred to by `path` MUST define coordinate system
+and coordinate transform metadata:
-* Every axis name in the `coordinateTransformations`' `input`
+* Every axis name in the `coordinateTransform`'s `input`
MUST appear in the coordinate system.
* The array dimension corresponding to the `coordinate` or `displacement` axis
- MUST have length equal to the number of dimensions of the `coordinateTransformation`'s `output`
-* If the input coordinate system has `N` axes,
+ MUST have length equal to the number of dimensions of the `coordinateTransform` `output`
+* If the input coordinate system `N` axes,
then the array data at `path` MUST have `(N + 1)` dimensions.
-* SHOULD have a `name` identical to the `name` of the corresponding `coordinateTransformation`.
+* SHOULD have a `name` identical to the `name` of the corresponding `coordinateTransform`.
For `coordinates`:
@@ -1340,20 +1400,19 @@ It is stored in a multiple resolution representation.
`multiscales` contains a list of dictionaries where each entry describes a multiscale image.
Each `multiscales` dictionary MUST contain the field "coordinateSystems",
-whose value is an array containing valid coordinate system metadata
-(see [coordinate systems](#coordinate-systems-md)).
-The last entry of this array is the "default" coordinate system
-and MUST contain transformations from array to physical coordinates.
+whose value is an array containing coordinate system metadata
+(see [coordinate systems](#coordinatesystems-metadata)).
+The last entry of this array is the "intrinsic" coordinate system
+and MUST contain axis information pertaining to physical coordinates.
It should be used for viewing and processing unless a use case dictates otherwise.
-It will generally be a representation of the image in its native physical coordinate system.
+It will generally be a representation of the image in its native physical coordinate system.
-The following MUST hold for all coordinate systems.
+The following MUST hold for all coordinate systems inside multiscales metadata.
The length of "axes" must be between 2 and 5
and MUST be equal to the dimensionality of the Zarr arrays storing the image data (see "datasets:path").
The "axes" MUST contain 2 or 3 entries of "type:space"
and MAY contain one additional entry of "type:time"
and MAY contain one additional entry of "type:channel" or a null / custom type.
-The order of the entries MUST correspond to the order of dimensions of the Zarr arrays.
In addition, the entries MUST be ordered by "type" where the "time" axis must come first (if present),
followed by the "channel" or custom axis (if present) and the axes of type "space".
If there are three spatial axes where two correspond to the image plane ("yx")
@@ -1371,14 +1430,14 @@ The number of dimensions and order MUST correspond to number and order of `axes`
Each dictionary in `datasets` MUST contain the field `coordinateTransformations`,
whose value is a list of dictionaries that define a transformation
-that maps Zarr array coordinates for this resolution level to the "default" coordinate system
+that maps Zarr array coordinates for this resolution level to the "intrinsic" coordinate system
(the last entry of the `coordinateSystems` array).
-The transformation is defined according to [transformations metadata](#trafo-types-md).
+The transformation is defined according to [transformations metadata](#transformation-types).
The transformation MUST take as input points in the array coordinate system
corresponding to the Zarr array at location `path`.
-The value of "input" SHOULD equal the value of `path`,
-but implementations should always treat the value of `input` as if it were equal to the value of `path`.
-The value of the transformation’s `output` MUST be the name of the default [coordinate system](#coordinate-systems-md).
+The value of "input" MUST equal the value of `path`,
+implementations should always treat the value of `input` as if it were equal to the value of `path`.
+The value of the transformation’s `output` MUST be the name of the "intrinsic" [coordinate system](#coordinatesystems-metadata).
This transformation MUST be one of the following:
@@ -1391,14 +1450,14 @@ the value MUST express the scaling factor between the current resolution
and the first resolution for the given axis,
defaulting to 1.0 if there is no downsampling along the axis.
This is strongly recommended
-so that the the "default" coordinate system of the imageavoids more complex transformations.
+so that the the "intrinsic" coordinate system of the image avoids more complex transformations.
If applications require additional transformations,
each `multiscales` dictionary MAY contain the field `coordinateTransformations`,
describing transformations that are applied to all resolution levels in the same manner.
-The value of `input` MUST equal the name of the "default" coordinate system.
+The value of `input` MUST equal the name of the "intrinsic" coordinate system.
The value of `output` MUST be the name of the output coordinate System
-which is different from the "default" coordinate system.
+which is different from the "intrinsic" coordinate system.
Each `multiscales` dictionary SHOULD contain the field `name`.
From 06309d4504129aa2955119f943a44677636f8ffe Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:56:05 +0100
Subject: [PATCH 41/47] fix links
---
ngff_spec/specification.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index ea4eac24..0217e09c 100644
--- a/ngff_spec/specification.md
+++ b/ngff_spec/specification.md
@@ -424,9 +424,9 @@ The following transformations are supported:
| [`affine`](#affine-md) | one of:
`"affine":List[List[number]]`,
`"path":str` | 2D affine transformation matrix stored either with JSON (`affine`) or as a zarr array at a location in this container (`path`). |
| [`rotation`](#rotation-md) | one of:
`"rotation":List[List[number]]`,
`"path":str` | 2D rotation transformation matrix stored as an array stored either with json (`rotation`) or as a zarr array at a location in this container (`path`).|
| [`sequence`](#sequence-md) | `"transformations":List[Transformation]` | sequence of transformations. Applying the sequence applies the composition of all transforms in the list, in order. |
-| [`displacements`](#coordinates-and-displacements-md) | `"path":str`
`"interpolation":str` | Displacement field transformation located at `path`. |
-| [`coordinates`](#coordinates-and-displacements-md) | `"path":str`
`"interpolation":str` | Coordinate field transformation located at `path`. |
-| [`inverseOf`](#inverseof-md) | `"transformation":Transformation` | The inverse of a transformation. Useful if a transform is not closed-form invertible. See forward and inverse of [bijections](#bijection) for details and examples. |
+| [`displacements`](#coordinates-displacements-md) | `"path":str`
`"interpolation":str` | Displacement field transformation located at `path`. |
+| [`coordinates`](#coordinates-displacements-md) | `"path":str`
`"interpolation":str` | Coordinate field transformation located at `path`. |
+| [`inverseOf`](#inverseof-md) | `"transformation":Transformation` | The inverse of a transformation. Useful if a transform is not closed-form invertible. See forward and inverse of [bijections](#bijection-md) for details and examples. |
| [`bijection`](#bijection-md) | `"forward":Transformation`
`"inverse":Transformation` | An invertible transformation providing an explicit forward transformation and its inverse. |
| [`byDimension`](#bydimension-md) | `"transformations":List[Transformation]`,
`"input_axes": List[str]`,
`"output_axes": List[str]` | A high dimensional transformation using lower dimensional transformations on subsets of dimensions. |
@@ -475,10 +475,10 @@ Conforming readers:
Coordinate transformations can be stored in multiple places to reflect different usecases.
- Transformations in individual multiscale datasets represent a special case of transformations
- and are explained [below](#multiscales-metadata).
+ and are explained [below](#multiscales-md).
- Additional transformations for single multiscale images MUST be stored under a field `coordinateTransformations`
in the multiscales dictionaries.
- This `coordinateTransformations` field MUST contain a list of valid [transformations](#transformation-types).
+ This `coordinateTransformations` field MUST contain a list of valid [transformations](#trafo-types-md).
- Transformations between two or more images MUST be stored in the attributes of a parent zarr group.
For transformations that store data or parameters in a zarr array,
those zarr arrays SHOULD be stored in a zarr group called "coordinateTransformations".
@@ -632,7 +632,7 @@ or MAY output a warning that the requested operation is unsupported.
#### Matrix transformations
(matrix-trafo-md)=
-Two transformation types ([affine](#affine) and [rotation](#rotation)) are parametrized by matrices.
+Two transformation types ([affine](#affine-md) and [rotation](#rotation-md)) are parametrized by matrices.
Matrices are applied to column vectors that represent points in the input coordinate system.
The first and last axes in a coordinate system correspond to the top and bottom entries in the column vector, respectively.
Matrices are stored as two-dimensional arrays, either as json or in a zarr array.
@@ -1401,7 +1401,7 @@ It is stored in a multiple resolution representation.
Each `multiscales` dictionary MUST contain the field "coordinateSystems",
whose value is an array containing coordinate system metadata
-(see [coordinate systems](#coordinatesystems-metadata)).
+(see [coordinate systems](#coordinate-systems-md)).
The last entry of this array is the "intrinsic" coordinate system
and MUST contain axis information pertaining to physical coordinates.
It should be used for viewing and processing unless a use case dictates otherwise.
@@ -1432,12 +1432,12 @@ Each dictionary in `datasets` MUST contain the field `coordinateTransformations`
whose value is a list of dictionaries that define a transformation
that maps Zarr array coordinates for this resolution level to the "intrinsic" coordinate system
(the last entry of the `coordinateSystems` array).
-The transformation is defined according to [transformations metadata](#transformation-types).
+The transformation is defined according to [transformations metadata](#trafo-types-md).
The transformation MUST take as input points in the array coordinate system
corresponding to the Zarr array at location `path`.
The value of "input" MUST equal the value of `path`,
implementations should always treat the value of `input` as if it were equal to the value of `path`.
-The value of the transformation’s `output` MUST be the name of the "intrinsic" [coordinate system](#coordinatesystems-metadata).
+The value of the transformation’s `output` MUST be the name of the "intrinsic" [coordinate system](#coordinate-systems-md).
This transformation MUST be one of the following:
From f4fbb9666ae75b91f5e40731ef22dd9de96dd5b3 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 5 Nov 2025 16:56:15 +0100
Subject: [PATCH 42/47] fix schema resolution
---
ngff_spec/pre_build.py | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/ngff_spec/pre_build.py b/ngff_spec/pre_build.py
index 071a9f04..dfa838f2 100644
--- a/ngff_spec/pre_build.py
+++ b/ngff_spec/pre_build.py
@@ -3,6 +3,10 @@
import glob
from pathlib import Path
import jsonc as json
+import logging
+
+# Suppress warnings from json-schema-for-humans about unresolvable URLs
+logging.getLogger().setLevel(logging.ERROR)
# change working directory to the location of this script
os.chdir(os.path.dirname(os.path.abspath(__file__)))
@@ -67,12 +71,21 @@ 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'
os.makedirs(output_directory, exist_ok=True)
schema_files = glob.glob(os.path.join(schema_source_dir, '*.schema'), recursive=True)
+ # Create a resolver mapping for local schemas
+ schema_mapping = {}
+ for schema_file in schema_files:
+ with open(schema_file, 'r') as f:
+ schema_content = json.load(f)
+ if '$id' in schema_content:
+ schema_mapping[schema_content['$id']] = os.path.abspath(schema_file)
+
index_markdown = """# JSON Schemas
This section contains JSON schemas for various metadata layouts.
@@ -98,7 +111,8 @@ def build_json_schemas():
template_name='md',
with_footer=True,
show_toc=False,
- link_to_reused_ref=False)
+ link_to_reused_ref=False,
+ custom_template_global_vars={'schema_mapping': schema_mapping})
generate_from_filename(
os.path.abspath(schema_file),
result_file_name=os.path.abspath(output_path_md),
@@ -122,7 +136,8 @@ def build_json_schemas():
template_name='js',
with_footer=True,
show_toc=False,
- link_to_reused_ref=False)
+ link_to_reused_ref=False,
+ custom_template_global_vars={'schema_mapping': schema_mapping})
generate_from_filename(
os.path.abspath(schema_file),
From 031d5daa6aac255b57803ad85cede964cd2efa54 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 24 Nov 2025 12:02:10 +0100
Subject: [PATCH 43/47] move example/schema index pages in _generated folder
and fix encoding error
---
ngff_spec/myst.yml | 4 ++--
ngff_spec/pre_build.py | 17 +++++++++--------
2 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/ngff_spec/myst.yml b/ngff_spec/myst.yml
index 223bc014..46136026 100644
--- a/ngff_spec/myst.yml
+++ b/ngff_spec/myst.yml
@@ -96,10 +96,10 @@ project:
orcid: "https://orcid.org/0000-0002-2198-1958"
toc:
- file: specification.md
- - file: examples.md
+ - file: _generated/examples.md
children:
- pattern: _generated/examples/*
- - file: schemas.md
+ - file: _generated/schemas.md
children:
- pattern: _generated/schemas/markdown/*
- file: contribute.md
diff --git a/ngff_spec/pre_build.py b/ngff_spec/pre_build.py
index e7bb634a..ad22bead 100644
--- a/ngff_spec/pre_build.py
+++ b/ngff_spec/pre_build.py
@@ -31,7 +31,6 @@ def build_json_examples():
for example in example_types:
json_files = glob.glob(os.path.join(input_directory, example, '*.json'), recursive=True)
- markdown_file_name = os.path.join(output_directory, f'{example}.md')
index_md += f"\n## {example}\n"
@@ -66,10 +65,10 @@ def build_json_examples():
```
"""
# create
- with open(markdown_file_name, 'w') as md_file:
+ with open(os.path.join(output_directory, f'{example}.md'), 'w') as md_file:
md_file.write(markdown_content)
- with open(os.path.join("examples.md"), 'w') as index_file:
+ with open(os.path.join("_generated/examples.md"), 'w') as index_file:
index_file.write(index_md)
def build_json_schemas():
@@ -121,7 +120,8 @@ def build_json_schemas():
with_footer=True,
show_toc=False,
link_to_reused_ref=False,
- custom_template_global_vars={'schema_mapping': schema_mapping})
+# custom_template_global_vars={'schema_mapping': schema_mapping}
+ )
generate_from_filename(
os.path.abspath(schema_file),
result_file_name=os.path.abspath(output_path_md),
@@ -129,7 +129,7 @@ def build_json_schemas():
)
# insert mySt cross-reference at top of markdown files
- with open(output_path_md, 'r') as md_file:
+ with open(output_path_md, 'r', encoding='utf-8') as md_file:
md_content = md_file.read()
crossref = f"schemas:{Path(schema_file).stem}"
md_content = f"""---
@@ -137,7 +137,7 @@ def build_json_schemas():
---
({crossref})=\n\n{md_content}
"""
- with open(output_path_md, 'w') as md_file:
+ with open(output_path_md, 'w', encoding='utf-8') as md_file:
md_file.write(md_content)
link_markdown = f"[{Path(schema_file).stem}](#{crossref})"
@@ -150,7 +150,8 @@ def build_json_schemas():
with_footer=True,
show_toc=False,
link_to_reused_ref=False,
- custom_template_global_vars={'schema_mapping': schema_mapping})
+# custom_template_global_vars={'schema_mapping': schema_mapping}
+ )
generate_from_filename(
os.path.abspath(schema_file),
@@ -164,7 +165,7 @@ def build_json_schemas():
index_markdown += f"| {Path(schema_file).stem} | {link_markdown} | {link_html} |\n"
- with open(os.path.join("schemas.md"), 'w') as index_file:
+ with open(os.path.join("_generated/schemas.md"), 'w') as index_file:
index_file.write(index_markdown)
def build_footer():
From 557f7b90967c584963e63022f8beacd76f826c12 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 24 Nov 2025 13:43:59 +0100
Subject: [PATCH 44/47] removed unnecessary code and added traceback print
---
ngff_spec/pre_build.py | 23 +++++++----------------
1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/ngff_spec/pre_build.py b/ngff_spec/pre_build.py
index ad22bead..ca0de89e 100644
--- a/ngff_spec/pre_build.py
+++ b/ngff_spec/pre_build.py
@@ -74,21 +74,12 @@ 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'
os.makedirs(output_directory, exist_ok=True)
schema_files = glob.glob(os.path.join(schema_source_dir, '*.schema'), recursive=True)
- # Create a resolver mapping for local schemas
- schema_mapping = {}
- for schema_file in schema_files:
- with open(schema_file, 'r') as f:
- schema_content = json.load(f)
- if '$id' in schema_content:
- schema_mapping[schema_content['$id']] = os.path.abspath(schema_file)
-
index_markdown = """---
title: NGFF metadata JSON Schemas
@@ -118,9 +109,8 @@ def build_json_schemas():
config_md = GenerationConfiguration(
template_name='md',
with_footer=True,
- show_toc=False,
- link_to_reused_ref=False,
-# custom_template_global_vars={'schema_mapping': schema_mapping}
+ show_toc=True,
+ link_to_reused_ref=True,
)
generate_from_filename(
os.path.abspath(schema_file),
@@ -141,7 +131,8 @@ def build_json_schemas():
md_file.write(md_content)
link_markdown = f"[{Path(schema_file).stem}](#{crossref})"
- except Exception:
+ except Exception as e:
+ print(f"Error generating markdown for {schema_file}: {e}")
link_markdown = ""
try:
@@ -149,8 +140,7 @@ def build_json_schemas():
template_name='js',
with_footer=True,
show_toc=False,
- link_to_reused_ref=False,
-# custom_template_global_vars={'schema_mapping': schema_mapping}
+ link_to_reused_ref=True,
)
generate_from_filename(
@@ -160,7 +150,8 @@ def build_json_schemas():
)
link_html = f"[{Path(schema_file).stem}]({output_path_html})"
- except Exception:
+ except Exception as e:
+ print(f"Error generating HTML for {schema_file}: {e}")
link_html = ""
index_markdown += f"| {Path(schema_file).stem} | {link_markdown} | {link_html} |\n"
From 0b842a2a1ad2a8b613ebf7be6b856844cc9da77a Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Mon, 24 Nov 2025 13:45:34 +0100
Subject: [PATCH 45/47] Comment out example tests
---
tests/test_validation.py | 37 ++++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/tests/test_validation.py b/tests/test_validation.py
index 5de3ecb7..73ae7110 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -78,23 +78,26 @@ def pytest_generate_tests(metafunc):
suites.append(Suite(schema, test["data"], test["valid"]))
# Examples
- for config_filename in glob.glob("examples/*/.config.json"):
- with open(config_filename) as o:
- data = json.load(o)
- schema = data["schema"]
- with open(schema) as f:
- schema = json.load(f)
- example_folder = os.path.dirname(config_filename)
- for filename in glob.glob(f"{example_folder}/*.json"):
- with open(filename) as f:
- # Strip comments
- data = "".join(
- line for line in f if not line.lstrip().startswith("//")
- )
- data = json.loads(data)
- data = data["attributes"] # Only validate the attributes object
- ids.append("example_" + str(filename).split("/")[-1][0:-5])
- suites.append(Suite(schema, data, True)) # Assume true
+ # TODO: Split examples into snippets (used for reference in spec) and
+ # complete examples (to be validated here)
+ # for config_filename in glob.glob("ngff_spec/examples/*/.config.json"):
+ # with open(config_filename) as o:
+ # data = json.load(o)
+ # schema = data["schema"]
+ # with open(schema) as f:
+ # schema = json.load(f)
+ # example_folder = os.path.dirname(config_filename)
+ # for filename in glob.glob(f"{example_folder}/*.json"):
+ # print(filename)
+ # with open(filename) as f:
+ # # Strip comments
+ # data = "".join(
+ # line for line in f if not line.lstrip().startswith("//")
+ # )
+ # data = json.loads(data)
+ # data = data["attributes"] # Only validate the attributes object
+ # ids.append("example_" + str(filename).split("/")[-1][0:-5])
+ # suites.append(Suite(schema, data, True)) # Assume true
metafunc.parametrize("suite", suites, ids=ids, indirect=True)
From b91fd82faf396c21bf820fdc84975095226e05ec Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 26 Nov 2025 23:26:01 +0100
Subject: [PATCH 46/47] correct versioning semantic
Previously `0.6dev2`, now `0.6.dev2`
---
.../multiscales_example_relative.json | 2 +-
.../multiscales_transformations.json | 2 +-
ngff_spec/schemas/_version.schema | 4 +-
ngff_spec/schemas/axes.schema | 2 +-
ngff_spec/schemas/bf2raw.schema | 4 +-
ngff_spec/schemas/coordinate_systems.schema | 2 +-
.../coordinate_systems_and_transforms.schema | 2 +-
.../schemas/coordinate_transformations.schema | 2 +-
ngff_spec/schemas/image.schema | 22 +++----
ngff_spec/schemas/label.schema | 4 +-
ngff_spec/schemas/ome.schema | 4 +-
ngff_spec/schemas/ome_zarr.schema | 14 ++---
ngff_spec/schemas/plate.schema | 4 +-
ngff_spec/schemas/strict_axes.schema | 4 +-
.../schemas/strict_coordinate_systems.schema | 2 +-
ngff_spec/schemas/strict_image.schema | 4 +-
ngff_spec/schemas/strict_label.schema | 4 +-
ngff_spec/schemas/strict_plate.schema | 4 +-
ngff_spec/schemas/strict_well.schema | 4 +-
ngff_spec/schemas/well.schema | 4 +-
tests/image_suite.json | 56 ++++++++---------
tests/label_suite.json | 18 +++---
tests/plate_suite.json | 60 +++++++++----------
tests/strict_image_suite.json | 12 ++--
tests/strict_label_suite.json | 2 +-
tests/strict_plate_suite.json | 10 ++--
tests/strict_well_suite.json | 4 +-
tests/test_validation.py | 2 +-
tests/well_suite.json | 4 +-
29 files changed, 131 insertions(+), 131 deletions(-)
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
index 8bd828c9..65a6e9d5 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
@@ -1,7 +1,7 @@
{
"multiscales": [
{
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"name": "example",
"coordinateSystems" : [
{
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_transformations.json b/ngff_spec/examples/multiscales_strict/multiscales_transformations.json
index 14304c0a..46e60a4c 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_transformations.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_transformations.json
@@ -3,7 +3,7 @@
"node_type": "group",
"attributes": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
diff --git a/ngff_spec/schemas/_version.schema b/ngff_spec/schemas/_version.schema
index b20a6702..f1541e9f 100644
--- a/ngff_spec/schemas/_version.schema
+++ b/ngff_spec/schemas/_version.schema
@@ -1,10 +1,10 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema",
"title": "OME-Zarr Metadata version",
"description": "The version of the OME-Zarr Metadata",
"type": "string",
"enum": [
- "0.6dev2"
+ "0.6.dev2"
]
}
diff --git a/ngff_spec/schemas/axes.schema b/ngff_spec/schemas/axes.schema
index 3ed096da..1a13045e 100644
--- a/ngff_spec/schemas/axes.schema
+++ b/ngff_spec/schemas/axes.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/axes.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/axes.schema",
"title": "NGFF Axes",
"description": "JSON from OME-NGFF .zattrs",
"type": "array",
diff --git a/ngff_spec/schemas/bf2raw.schema b/ngff_spec/schemas/bf2raw.schema
index edcfaaac..2f92993b 100644
--- a/ngff_spec/schemas/bf2raw.schema
+++ b/ngff_spec/schemas/bf2raw.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/bf2raw.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/bf2raw.schema",
"title": "OME-Zarr container produced by bioformats2raw",
"description": "The zarr.json attributes key",
"type": "object",
@@ -17,7 +17,7 @@
]
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/coordinate_systems.schema b/ngff_spec/schemas/coordinate_systems.schema
index f42d5b9a..7ce4460e 100644
--- a/ngff_spec/schemas/coordinate_systems.schema
+++ b/ngff_spec/schemas/coordinate_systems.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_systems.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_systems.schema",
"title": "NGFF CoordinateSystem",
"description": "JSON from OME-NGFF .zattrs",
"type": "array",
diff --git a/ngff_spec/schemas/coordinate_systems_and_transforms.schema b/ngff_spec/schemas/coordinate_systems_and_transforms.schema
index fd6b4b15..715b6fe9 100644
--- a/ngff_spec/schemas/coordinate_systems_and_transforms.schema
+++ b/ngff_spec/schemas/coordinate_systems_and_transforms.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_systems_and_transforms.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_systems_and_transforms.schema",
"title": "NGFF Coordinate Systems and Transforms",
"description": "Coordinate Systems and transforms for OME-NGFF",
"type": "object",
diff --git a/ngff_spec/schemas/coordinate_transformations.schema b/ngff_spec/schemas/coordinate_transformations.schema
index 20dce275..3ecbc7f5 100644
--- a/ngff_spec/schemas/coordinate_transformations.schema
+++ b/ngff_spec/schemas/coordinate_transformations.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_transformations.schema",
"title": "NGFF Coordinate Systems and Transforms",
"description": "Coordinate Systems and transforms for OME-NGFF",
"type": "array",
diff --git a/ngff_spec/schemas/image.schema b/ngff_spec/schemas/image.schema
index d7324d93..ad8729ae 100644
--- a/ngff_spec/schemas/image.schema
+++ b/ngff_spec/schemas/image.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema",
"title": "OME-Zarr Image",
"description": "The zarr.json attributes key",
"type": "object",
@@ -10,13 +10,13 @@
"type": "object",
"properties": {
"multiscales": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema#/$defs/multiscales"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema#/$defs/multiscales"
},
"omero": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema#/$defs/omero"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema#/$defs/omero"
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
@@ -51,7 +51,7 @@
"type": "array",
"uniqueItems": true,
"items": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema#/$defs/multiscale_coordinateTransformations"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema#/$defs/multiscale_coordinateTransformations"
},
"minItems": 1,
"maxItems": 1
@@ -66,21 +66,21 @@
"version": {
"type": "string",
"enum": [
- "0.6dev2"
+ "0.6.dev2"
]
},
"coordinateSystems": {
"type": "array",
"minItems": 1,
"items": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_systems.schema#/$defs/coordinateSystem"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_systems.schema#/$defs/coordinateSystem"
}
},
"coordinateTransformations": {
"type": "array",
"minItems": 1,
"items": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/coordinateTransformation"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_transformations.schema#/$defs/coordinateTransformation"
}
}
},
@@ -94,7 +94,7 @@
"multiscale_coordinateTransformations": {
"description": "OME-NGFF coordinate transformation for multiscale resolution level datasets (only scale or scale & translate).",
"oneOf": [
- {"$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/scale"},
+ {"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_transformations.schema#/$defs/scale"},
{
"type": "object",
"properties": {
@@ -103,8 +103,8 @@
"type": "array",
"items": {
"oneOf": [
- {"$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/scale"},
- {"$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/coordinate_transformations.schema#/$defs/translation"}
+ {"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_transformations.schema#/$defs/scale"},
+ {"$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_transformations.schema#/$defs/translation"}
]
},
"minItems": 2,
diff --git a/ngff_spec/schemas/label.schema b/ngff_spec/schemas/label.schema
index 7f234ed8..4ab19c27 100644
--- a/ngff_spec/schemas/label.schema
+++ b/ngff_spec/schemas/label.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/label.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/label.schema",
"title": "OME-Zarr labelled image schema",
"description": "The zarr.json attributes key",
"type": "object",
@@ -13,7 +13,7 @@
"$ref": "#/$defs/image-label"
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/ome.schema b/ngff_spec/schemas/ome.schema
index 9a44f6bc..75b92648 100644
--- a/ngff_spec/schemas/ome.schema
+++ b/ngff_spec/schemas/ome.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/ome.schema",
"title": "OME-Zarr group produced by bioformats2raw to contain OME metadata",
"description": "The zarr.json attributes key",
"type": "object",
@@ -18,7 +18,7 @@
"minContains": 1
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/ome_zarr.schema b/ngff_spec/schemas/ome_zarr.schema
index 2ce06ac6..47c80c0d 100644
--- a/ngff_spec/schemas/ome_zarr.schema
+++ b/ngff_spec/schemas/ome_zarr.schema
@@ -1,24 +1,24 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome_zarr.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/ome_zarr.schema",
"anyOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/bf2raw.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/bf2raw.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/label.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/label.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/ome.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/plate.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/plate.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/well.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/well.schema"
}
]
}
diff --git a/ngff_spec/schemas/plate.schema b/ngff_spec/schemas/plate.schema
index 06d7edb0..382093f7 100644
--- a/ngff_spec/schemas/plate.schema
+++ b/ngff_spec/schemas/plate.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/plate.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/plate.schema",
"title": "OME-Zarr plate schema",
"description": "The zarr.json attributes key",
"type": "object",
@@ -138,7 +138,7 @@
]
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/schemas/strict_axes.schema b/ngff_spec/schemas/strict_axes.schema
index f6bab275..7420293d 100644
--- a/ngff_spec/schemas/strict_axes.schema
+++ b/ngff_spec/schemas/strict_axes.schema
@@ -1,11 +1,11 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_axes.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_axes.schema",
"title": "NGFF Strict Axes",
"description": "JSON from OME-NGFF .zattrs",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/axes.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/axes.schema"
},
{
"items": {
diff --git a/ngff_spec/schemas/strict_coordinate_systems.schema b/ngff_spec/schemas/strict_coordinate_systems.schema
index 99474ce0..e39c5955 100644
--- a/ngff_spec/schemas/strict_coordinate_systems.schema
+++ b/ngff_spec/schemas/strict_coordinate_systems.schema
@@ -1,5 +1,5 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_coordinate_systems.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_coordinate_systems.schema",
"allOf" : [
{
"$ref": "coordinate_systems.schema"
diff --git a/ngff_spec/schemas/strict_image.schema b/ngff_spec/schemas/strict_image.schema
index 812f706f..d0508687 100644
--- a/ngff_spec/schemas/strict_image.schema
+++ b/ngff_spec/schemas/strict_image.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_image.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_image.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/image.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema"
},
{
"properties": {
diff --git a/ngff_spec/schemas/strict_label.schema b/ngff_spec/schemas/strict_label.schema
index 90daf564..73625010 100644
--- a/ngff_spec/schemas/strict_label.schema
+++ b/ngff_spec/schemas/strict_label.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_label.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_label.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/label.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/label.schema"
},
{
"properties": {
diff --git a/ngff_spec/schemas/strict_plate.schema b/ngff_spec/schemas/strict_plate.schema
index 7b91ff38..532d5dfc 100644
--- a/ngff_spec/schemas/strict_plate.schema
+++ b/ngff_spec/schemas/strict_plate.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_plate.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_plate.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/plate.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/plate.schema"
},
{
"properties": {
diff --git a/ngff_spec/schemas/strict_well.schema b/ngff_spec/schemas/strict_well.schema
index 1192acda..57018470 100644
--- a/ngff_spec/schemas/strict_well.schema
+++ b/ngff_spec/schemas/strict_well.schema
@@ -1,8 +1,8 @@
{
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/strict_well.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_well.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/well.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/well.schema"
}
]
}
diff --git a/ngff_spec/schemas/well.schema b/ngff_spec/schemas/well.schema
index f81fafa9..9985430f 100644
--- a/ngff_spec/schemas/well.schema
+++ b/ngff_spec/schemas/well.schema
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "https://ngff.openmicroscopy.org/0.6dev2/schemas/well.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/well.schema",
"title": "OME-Zarr well schema",
"description": "JSON from OME-Zarr zarr.json",
"type": "object",
@@ -41,7 +41,7 @@
]
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6dev2/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/tests/image_suite.json b/tests/image_suite.json
index ee80509b..51193440 100644
--- a/tests/image_suite.json
+++ b/tests/image_suite.json
@@ -9,7 +9,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -58,7 +58,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -105,7 +105,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -150,7 +150,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"datasets": [
@@ -203,7 +203,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -251,7 +251,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -296,7 +296,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -338,7 +338,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -382,7 +382,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -426,7 +426,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -484,7 +484,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -545,7 +545,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -587,7 +587,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -626,7 +626,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -672,7 +672,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -716,7 +716,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -766,7 +766,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -802,7 +802,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -834,7 +834,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -865,7 +865,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"datasets": [
@@ -892,7 +892,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -936,7 +936,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -986,7 +986,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"axes": [],
@@ -1014,7 +1014,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -1064,7 +1064,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": []
}
},
@@ -1075,7 +1075,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -1136,7 +1136,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -1174,7 +1174,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
diff --git a/tests/label_suite.json b/tests/label_suite.json
index ceeb9842..227e924e 100644
--- a/tests/label_suite.json
+++ b/tests/label_suite.json
@@ -8,7 +8,7 @@
"formerly": "image-label/minimal",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"colors": [
{
@@ -25,7 +25,7 @@
"formerly": "image-label/minimal_properties",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"colors": [
{
@@ -47,7 +47,7 @@
"formerly": "image-label/empty_colors",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"colors": []
}
@@ -59,7 +59,7 @@
"formerly": "image-label/empty_properties",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"properties": []
}
@@ -71,7 +71,7 @@
"formerly": "image-label/colors_no_label_value",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"colors": [
{
@@ -87,7 +87,7 @@
"formerly": "image-label/properties_no_label_value",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"properties": [
{
@@ -103,7 +103,7 @@
"formerly": "image-label/colors_rgba_length",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"colors": [
{
@@ -120,7 +120,7 @@
"formerly": "image-label/colors_rgba_type",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"colors": [
{
@@ -137,7 +137,7 @@
"formerly": "image-label/colors_duplicate",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {
"colors": [
{
diff --git a/tests/plate_suite.json b/tests/plate_suite.json
index 70bbf3ff..19bc8e08 100644
--- a/tests/plate_suite.json
+++ b/tests/plate_suite.json
@@ -8,7 +8,7 @@
"formerly": "plate/minimal_no_acquisitions",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -36,7 +36,7 @@
"formerly": "plate/minimal_acquisitions",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -69,7 +69,7 @@
"formerly": "plate/missing_rows",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -92,7 +92,7 @@
"formerly": "plate/empty_rows",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -116,7 +116,7 @@
"formerly": "plate/duplicate_rows",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -147,7 +147,7 @@
"formerly": "plate/missing_columns",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"rows": [
{
@@ -170,7 +170,7 @@
"formerly": "plate/empty_columns",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [],
"rows": [
@@ -194,7 +194,7 @@
"formerly": "plate/duplicate_columns",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -225,7 +225,7 @@
"formerly": "plate/missing_wells",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -246,7 +246,7 @@
"formerly": "plate/empty_wells",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -268,7 +268,7 @@
"formerly": "plate/duplicate_rows",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -304,7 +304,7 @@
"formerly": "plate/missing_column_name",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -332,7 +332,7 @@
"formerly": "plate/missing_row_name",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -360,7 +360,7 @@
"formerly": "plate/missing_well_path",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -387,7 +387,7 @@
"formerly": "plate/missing_well_rowIndex",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -414,7 +414,7 @@
"formerly": "plate/missing_well_columnIndex",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -441,7 +441,7 @@
"formerly": "plate/well_1group",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -468,7 +468,7 @@
"formerly": "plate/well_3groups",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -495,7 +495,7 @@
"formerly": "plate/non_alphanumeric_column",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -523,7 +523,7 @@
"formerly": "plate/non_alphanumeric_row",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -551,7 +551,7 @@
"formerly": "plate/missing_acquisition_id",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -584,7 +584,7 @@
"formerly": "plate/non_integer_acquisition_id",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -617,7 +617,7 @@
"formerly": "plate/negative_acquisition_id",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -650,7 +650,7 @@
"formerly": "plate/non_integer_acquisition_maximumfieldcount",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -684,7 +684,7 @@
"formerly": "plate/acquisition_zero_maximumfieldcount",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -718,7 +718,7 @@
"formerly": "plate/acquisition_noninteger_starttime",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -752,7 +752,7 @@
"formerly": "plate/acquisition_negative_starttime",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -786,7 +786,7 @@
"formerly": "plate/acquisition_noninteger_endtime",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -820,7 +820,7 @@
"formerly": "plate/negative_endtime",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -854,7 +854,7 @@
"formerly": "plate/zero_field_count",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
diff --git a/tests/strict_image_suite.json b/tests/strict_image_suite.json
index 486f936c..adc33f55 100644
--- a/tests/strict_image_suite.json
+++ b/tests/strict_image_suite.json
@@ -9,7 +9,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"name": "example",
@@ -138,7 +138,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -210,7 +210,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"@id": "top",
"@type": "ngff:Image",
"multiscales": [
@@ -267,7 +267,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -316,7 +316,7 @@
"description": "TBD",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"multiscales": [
{
"coordinateSystems": [
@@ -453,7 +453,7 @@
"defaultZ": 2,
"model": "color"
},
- "version": "0.6dev2"
+ "version": "0.6.dev2"
}
}
},
diff --git a/tests/strict_label_suite.json b/tests/strict_label_suite.json
index d72dc241..7cc9d4c0 100644
--- a/tests/strict_label_suite.json
+++ b/tests/strict_label_suite.json
@@ -8,7 +8,7 @@
"formerly": "image-label/no_colors",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"image-label": {}
}
},
diff --git a/tests/strict_plate_suite.json b/tests/strict_plate_suite.json
index 7a994108..dbba40b5 100644
--- a/tests/strict_plate_suite.json
+++ b/tests/strict_plate_suite.json
@@ -8,7 +8,7 @@
"formerly": "plate/strict_no_acquisitions",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -37,7 +37,7 @@
"formerly": "plate/missing_name",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"columns": [
{
@@ -65,7 +65,7 @@
"formerly": "plate/strict_acquisitions",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -101,7 +101,7 @@
"formerly": "plate/missing_acquisition_name",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
@@ -136,7 +136,7 @@
"formerly": "plate/missing_acquisition_maximumfieldcount",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"plate": {
"acquisitions": [
{
diff --git a/tests/strict_well_suite.json b/tests/strict_well_suite.json
index ee10a2c0..371b8684 100644
--- a/tests/strict_well_suite.json
+++ b/tests/strict_well_suite.json
@@ -8,7 +8,7 @@
"formerly": "well/strict_no_acquisitions",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"well": {
"images": [
{
@@ -24,7 +24,7 @@
"formerly": "plate/strict_acquisitions",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"well": {
"images": [
{
diff --git a/tests/test_validation.py b/tests/test_validation.py
index 73ae7110..9e58172d 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -17,7 +17,7 @@
schema_store[schema["$id"]] = schema
GENERIC_SCHEMA = schema_store[
- "https://ngff.openmicroscopy.org/0.6dev2/schemas/ome_zarr.schema"
+ "https://ngff.openmicroscopy.org/0.6.dev2/schemas/ome_zarr.schema"
]
print(schema_store)
diff --git a/tests/well_suite.json b/tests/well_suite.json
index 9f9fe663..4e8118bc 100644
--- a/tests/well_suite.json
+++ b/tests/well_suite.json
@@ -8,7 +8,7 @@
"formerly": "well/minimal_no_acquisition",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev22",
"well": {
"images": [
{
@@ -24,7 +24,7 @@
"formerly": "well/minimal_acquisitions",
"data": {
"ome": {
- "version": "0.6dev2",
+ "version": "0.6.dev2",
"well": {
"images": [
{
From 325c35ed0da1c466424b8224c0a1d937e4eb52b0 Mon Sep 17 00:00:00 2001
From: Johannes Soltwedel <38459088+jo-mueller@users.noreply.github.com>
Date: Wed, 26 Nov 2025 23:39:56 +0100
Subject: [PATCH 47/47] typo
---
tests/well_suite.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/well_suite.json b/tests/well_suite.json
index 4e8118bc..2664649c 100644
--- a/tests/well_suite.json
+++ b/tests/well_suite.json
@@ -8,7 +8,7 @@
"formerly": "well/minimal_no_acquisition",
"data": {
"ome": {
- "version": "0.6.dev22",
+ "version": "0.6.dev2",
"well": {
"images": [
{