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/.gitignore b/.gitignore
index 4c0f08bd..a6d169df 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__/
diff --git a/ngff_spec/examples.md b/ngff_spec/examples.md
deleted file mode 100644
index 94df347f..00000000
--- a/ngff_spec/examples.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-title: NGFF metadata JSON Examples
-short_title: JSON Examples
-author: ""
----
-
-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/examples/coordSystems/arrayCoordSys.json b/ngff_spec/examples/coordSystems/arrayCoordSys.json
deleted file mode 100644
index 812356f8..00000000
--- a/ngff_spec/examples/coordSystems/arrayCoordSys.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "arrayCoordinateSystem" : {
- "name" : "myDataArray",
- "axes" : [
- {"name": "k", "type": "array"},
- {"name": "j", "type": "array"},
- {"name": "i", "type": "array"}
- ]
- }
-}
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/coordinate_systems/arrayCoordSys.json b/ngff_spec/examples/coordinate_systems/arrayCoordSys.json
new file mode 100644
index 00000000..84b59755
--- /dev/null
+++ b/ngff_spec/examples/coordinate_systems/arrayCoordSys.json
@@ -0,0 +1,10 @@
+{
+ "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.json b/ngff_spec/examples/multiscales_strict/multiscales_example.json
index 55799eb2..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,14 +50,14 @@
"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"
}
- ]
+ ]
}
],
"type": "gaussian",
@@ -72,4 +72,4 @@
]
}
}
-}
+}
\ No newline at end of file
diff --git a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
index 1d1864e0..65a6e9d5 100644
--- a/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
+++ b/ngff_spec/examples/multiscales_strict/multiscales_example_relative.json
@@ -1,76 +1,72 @@
{
- "multiscales": [
+ "multiscales": [
+ {
+ "version": "0.6.dev2",
+ "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" : "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" : "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": "s0",
+ // the transformation of other arrays are
+ // defined relative to this, the highest resolution, array
+ "coordinateTransformations": [{
+ "type": "scale",
+ "scale": [1, 1, 1, 1, 1],
+ "input": "s0",
+ "output": "intrinsic"
+ }]
+ },
+ {
+ "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": [
+ {
+ "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..46e60a4c 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.6.dev2",
"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/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/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/affine2d3d.json b/ngff_spec/examples/transformations/affine2d3d.json
index 588bdec5..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"}] }
- ],
- "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": "zyx", "axes": [{"name": "z"}, {"name": "y"}, {"name": "x"}] }
+ ],
+ "coordinateTransformations": [
+ {
+ "type": "affine",
+ "affine": [[1, 0, 0], [2, 3, 4], [5, 6, 7]],
+ "input": "ij",
+ "output": "zyx"
+ }
+ ]
}
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..f67a2579 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_axes": ["i"],
+ "output_axes": ["x"]
+ },
+ {
+ "type": "scale",
+ "scale": [2.0],
+ "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 10498818..33b99bda 100644
--- a/ngff_spec/examples/transformations/byDimensionInvalid1.json
+++ b/ngff_spec/examples/transformations/byDimensionInvalid1.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": ["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/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/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" ]
}
]
}
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..84664a80 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": [2, 3.12],
+ "input": "in",
+ "output": "out"
+ }
+ ]
}
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/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/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 f007a641..ca0de89e 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__)))
@@ -27,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"
@@ -58,16 +61,14 @@ def build_json_examples():
```{{literalinclude}} {os.path.abspath(json_file)}
:linenos:
-:tab-width: 2
:language: json
-
```
"""
# 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():
@@ -79,6 +80,7 @@ def build_json_schemas():
os.makedirs(output_directory, exist_ok=True)
schema_files = glob.glob(os.path.join(schema_source_dir, '*.schema'), recursive=True)
+
index_markdown = """---
title: NGFF metadata JSON Schemas
short_title: JSON Schemas
@@ -107,8 +109,9 @@ def build_json_schemas():
config_md = GenerationConfiguration(
template_name='md',
with_footer=True,
- show_toc=False,
- link_to_reused_ref=False)
+ show_toc=True,
+ link_to_reused_ref=True,
+ )
generate_from_filename(
os.path.abspath(schema_file),
result_file_name=os.path.abspath(output_path_md),
@@ -116,7 +119,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"""---
@@ -124,11 +127,12 @@ 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})"
- except Exception:
+ except Exception as e:
+ print(f"Error generating markdown for {schema_file}: {e}")
link_markdown = ""
try:
@@ -136,7 +140,8 @@ def build_json_schemas():
template_name='js',
with_footer=True,
show_toc=False,
- link_to_reused_ref=False)
+ link_to_reused_ref=True,
+ )
generate_from_filename(
os.path.abspath(schema_file),
@@ -145,12 +150,13 @@ 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"
- 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():
diff --git a/ngff_spec/schemas.md b/ngff_spec/schemas.md
deleted file mode 100644
index 1ea2fa16..00000000
--- a/ngff_spec/schemas.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: NGFF metadata JSON Schemas
-short_title: JSON Schemas
-author: ""
----
-
-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) |
diff --git a/ngff_spec/schemas/_version.schema b/ngff_spec/schemas/_version.schema
index 3845691c..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.6.dev1/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.6.dev1"
+ "0.6.dev2"
]
}
diff --git a/ngff_spec/schemas/axes.schema b/ngff_spec/schemas/axes.schema
index 56b447f2..1a13045e 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.6.dev2/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..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.6.dev1/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.6.dev1/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 583d9941..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/latest/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",
@@ -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 403f78a5..715b6fe9 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.6.dev2/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_transformation.schema"
+ "$ref": "coordinate_transformations.schema",
+ "description": "Coordinate transformations defining spatial relationships between coordinate systems"
},
"arrayCoordinateSystem": {
"type": "object",
diff --git a/ngff_spec/schemas/coordinate_transformation.schema b/ngff_spec/schemas/coordinate_transformations.schema
similarity index 65%
rename from ngff_spec/schemas/coordinate_transformation.schema
rename to ngff_spec/schemas/coordinate_transformations.schema
index e5156da0..3ecbc7f5 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/0.6.dev2/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": {
@@ -209,20 +213,6 @@
}
]
},
- "mtxFlatOrNested" : {
- "type": "array",
- "oneOf": [
- {
- "items": { "type": "number" }
- },
- {
- "items": {
- "type": "array",
- "items" : { "type" : "number" }
- }
- }
- ]
- },
"affine": {
"type": "object",
"properties": {
@@ -232,17 +222,31 @@
},
"oneOf": [
{
- "$ref": "#/$defs/path_w_url"
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to a zarr array containing the affine matrix."
+ }
+ },
+ "required": [
+ "path"
+ ]
},
{
"properties": {
"affine": {
- "$ref": "#/$defs/mtxFlatOrNested"
- },
- "required": [
- "affine"
- ]
- }
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ },
+ "required": [
+ "affine"
+ ]
}
]
},
@@ -255,20 +259,31 @@
},
"oneOf": [
{
- "$ref": "#/$defs/path_w_url"
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Path to a zarr array containing the rotation matrix."
+ }
+ },
+ "required": [
+ "path"
+ ]
},
{
"properties": {
"rotation": {
"type": "array",
"items": {
- "type": "number"
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
}
- },
- "required": [
- "rotation"
- ]
- }
+ }
+ },
+ "required": [
+ "rotation"
+ ]
}
]
},
@@ -284,7 +299,8 @@
},
"required": [
"transformation"
- ]
+ ],
+ "description": "The inverse of another coordinate transformation."
},
"bijection": {
"type": "object",
@@ -301,7 +317,8 @@
},
"required": [
"forward", "inverse"
- ]
+ ],
+ "description": "A pair of forward and inverse coordinate transformations."
},
"sequence": {
"description": "A sequence of transformations",
@@ -314,7 +331,10 @@
"$ref": "#/$defs/coordinateTransformation"
}
}
- }
+ },
+ "required": [
+ "transformations"
+ ]
},
"byDimension": {
"type": "object",
@@ -326,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 2f15522b..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.6.dev1/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": "#/$defs/multiscales"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema#/$defs/multiscales"
},
"omero": {
- "$ref": "#/$defs/omero"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema#/$defs/omero"
},
"version": {
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
@@ -48,7 +48,13 @@
"type": "string"
},
"coordinateTransformations": {
- "$ref": "coordinate_transformation.schema"
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema#/$defs/multiscale_coordinateTransformations"
+ },
+ "minItems": 1,
+ "maxItems": 1
}
},
"required": [
@@ -60,14 +66,22 @@
"version": {
"type": "string",
"enum": [
- "0.6.dev1"
+ "0.6.dev2"
]
},
"coordinateSystems": {
- "$ref": "coordinate_systems.schema"
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/coordinate_systems.schema#/$defs/coordinateSystem"
+ }
},
"coordinateTransformations": {
- "$ref": "coordinate_transformation.schema"
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/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.6.dev2/schemas/coordinate_transformations.schema#/$defs/scale"},
+ {
+ "type": "object",
+ "properties": {
+ "type": {"const": "sequence"},
+ "transformations": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {"$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,
+ "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..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.6.dev1/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.6.dev1/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 2a3e5fa2..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.6.dev1/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.6.dev1/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 632d0192..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.6.dev1/schemas/ome_zarr.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/ome_zarr.schema",
"anyOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/bf2raw.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/bf2raw.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/image.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/image.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/label.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/label.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/ome.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/ome.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/schemas/plate.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/plate.schema"
},
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/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 e1626a27..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.6.dev1/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.6.dev1/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 522602d2..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/latest/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/latest/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 425ccbe5..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/latest/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 4c51c95e..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.6.dev1/schemas/strict_image.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_image.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/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 90e510c0..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.6.dev1/schemas/strict_label.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_label.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/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 2fe258ce..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.6.dev1/schemas/strict_plate.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_plate.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/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 df7ad6c8..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.6.dev1/schemas/strict_well.schema",
+ "$id": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/strict_well.schema",
"allOf": [
{
- "$ref": "https://ngff.openmicroscopy.org/0.6.dev1/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 f623adc4..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.6.dev1/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.6.dev1/schemas/_version.schema"
+ "$ref": "https://ngff.openmicroscopy.org/0.6.dev2/schemas/_version.schema"
}
},
"required": [
diff --git a/ngff_spec/specification.md b/ngff_spec/specification.md
index c05284ed..0217e09c 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
@@ -158,97 +158,23 @@ The OME-Zarr Metadata version MUST be consistent within a hierarchy.
}
```
-## "axes" metadata
-(axes-md)=
+### "coordinateSystems" metadata
+(coordinate-systems-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
-
-(coord-sys-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 `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 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 below is three dimensional (3D).
````{admonition} Example
-Example of valid `coordinateSystems` metadata:
+Coordinate Systems metadata example
```json
{
@@ -262,150 +188,126 @@ 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.
-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.
+The axes of a coordinate system (see below) give information
+about the types, units, and other properties of the coordinate system's dimensions.
+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
+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).
-````{admonition} Example
+#### "axes" metadata
-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.
+"axes" describes the dimensions of a coordinate systems
+and adds an interpretation to the samples along that dimension.
-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.
+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 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 (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.
+ - 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.
-```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"
- }
-]
-```
+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 representing a channel, coordinate, or displacement are usually discrete.
-### Array coordinate systems
+```{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.
+```
-The dimensions of an array do not have an interpretation until they are associated with a coordinate system via a coordinate transformation.
+#### 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.
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 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
-For example, a 3D array at path `0` defines the coordinate system:
-
```json
{
- "name" : "0",
+ "arrayCoordinateSystem" : {
+ "name" : "myDataArray",
"axes" : [
- {"name": "dim_0", "type": "array"},
- {"name": "dim_1", "type": "array"},
- {"name": "dim_2", "type": "array"}
+ {"name": "dim_0", "type": "array"},
+ {"name": "dim_1", "type": "array"},
+ {"name": "dim_2", "type": "array"}
]
+ }
}
-```
-
-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
+For example, if 0/zarr.json contains:
+```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.
+
````
+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/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
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
+#### 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
@@ -437,8 +339,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:
@@ -451,6 +352,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:
@@ -491,217 +393,255 @@ Conforming readers:
- MAY ignore other groups or arrays under the root of the hierarchy.
## "coordinateTransformations" metadata
+(coord-trafo-md)=
-(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.
+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".
+- 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
- | |
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 -│ └── zarr.json # physical coordinate system and transformations here -│ # the array attributes +│ ├── 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 └── crop - ├── .zattrs # 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 -``` - -### 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. + ├── 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 ++ +::::{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. +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 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 transformed to a common coordinate system. -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). +The set of coordinate transformations encodes relationships between 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, 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. -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). +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. -````{admonition} Example +```json +"coordinateTransformations": [ + { + "type": "affine", + "path": "coordinateTransformations/sampleA_instrument2-to-instrument1", + "input": "sampleA_instrument2", + "output": "sampleA_instrument1" + } +] +``` -The sequence transformation's input corresponds to an array coordinate system at path "my/array". +And the image at the path `sampleA_instrument1` would have the following as the first coordinate system: ```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 ] - }, +"coordinateSystems": [ { - "type" : "sequence", - "input" : "my/array", - "output" : "outSeq", - "transformations" : [ - { "type": "scale", "scale" : [ 0.5, 0.6 ] }, - { "type": "translation", "translation" : [ 2, 5 ] } + "name": "sampleA-instrument1", + "axes": [ + {"name": "z", "type": "space", "unit": "micrometer"}, + {"name": "y", "type": "space", "unit": "micrometer"}, + {"name": "x", "type": "space", "unit": "micrometer"} ] }, +] +``` + +The image at path `sampleA_instrument2` would have this as the first listed coordinate system: + +```json +[ { - "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"]} + "name": "sampleA-instrument2", + "axes": [ + {"name": "z", "type": "space", "unit": "micrometer"}, + {"name": "y", "type": "space", "unit": "micrometer"}, + {"name": "x", "type": "space", "unit": "micrometer"} ] } -] +], ``` +:::: -```` +#### 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 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 unused, the `input` and `output` fields MAY be null. + +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. +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 -``` - -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](#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-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. +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 +::::{admonition} Example +:class: dropdown For matrix transformations, points in the coordinate system: @@ -733,25 +673,30 @@ because it is computed with the matrix-vector multiplication: [ 0 0 -1] [3] [-3] ``` -```` +:::: ### 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 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`. #### 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. +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. -````{admonition} Example +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 ```{literalinclude} examples/transformations/identity.json :language: json @@ -764,19 +709,27 @@ x = i 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. +`mapAxis` transforms are invertible. -````{admonition} Example +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 1 +:class: dropdown ```{literalinclude} examples/transformations/mapAxis1.json :language: json @@ -796,9 +749,10 @@ x = j y = i ``` -```` +:::: -````{admonition} Example +::::{admonition} Example 2 +:class: dropdown ```{literalinclude} examples/transformations/mapAxis2.json :language: json @@ -817,25 +771,30 @@ x = a y = b z = b ``` -```` +:::: #### translation (translation-md)= `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. -
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)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.