Skip to content

Commit 6f707fc

Browse files
oestebanjmarabottosgiavasis
committed
doc: finalize documenting new object
Resolves: #111. Co-authored-by: Julien Marabotto <166002186+jmarabotto@users.noreply.github.com> Co-authored-by: sgiavasis <sgiava77@gmail.com>
1 parent a3979a2 commit 6f707fc

File tree

3 files changed

+87
-20
lines changed

3 files changed

+87
-20
lines changed

docs/_api/io.rst

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ AFNI
2020
.. automodule:: nitransforms.io.afni
2121
:members:
2222

23+
^^^^^^^^
24+
BIDS' X5
25+
^^^^^^^^
26+
.. automodule:: nitransforms.io.x5
27+
:members:
28+
29+
^^^^^^^^^^^^^^
30+
FreeSurfer/LTA
31+
^^^^^^^^^^^^^^
32+
.. automodule:: nitransforms.io.lta
33+
:members:
34+
2335
^^^
2436
FSL
2537
^^^
@@ -31,9 +43,3 @@ ITK
3143
^^^
3244
.. automodule:: nitransforms.io.itk
3345
:members:
34-
35-
^^^^^^^^^^^^^^
36-
FreeSurfer/LTA
37-
^^^^^^^^^^^^^^
38-
.. automodule:: nitransforms.io.lta
39-
:members:

nitransforms/io/x5.py

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1-
"""Data structures for the X5 transform format."""
1+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
4+
#
5+
# See COPYING file distributed along with the NiBabel package for the
6+
# copyright and license terms.
7+
#
8+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
9+
"""
10+
Data structures for the X5 transform format.
11+
12+
Implements what's drafted in the `BIDS X5 specification draft
13+
<https://docs.google.com/document/d/1yk5O0QTAOXLdP9iSG3W8ta7IcMFypu2106c3Pnjfi-4/edit>`__.
14+
15+
"""
216

317
from __future__ import annotations
418

519
from dataclasses import dataclass
20+
from pathlib import Path
621
from typing import Any, Dict, Optional, Sequence, List
722

823
import json
@@ -13,33 +28,77 @@
1328

1429
@dataclass
1530
class X5Domain:
16-
"""Domain information of a transform."""
31+
"""Domain information of a transform representing reference/moving spaces."""
1732

1833
grid: bool
34+
"""Whether sampling locations in the manifold are located regularly."""
1935
size: Sequence[int]
20-
mapping: np.ndarray
36+
"""The number of sampling locations per dimension (or total if not a grid)."""
37+
mapping: Optional[np.ndarray]
38+
"""A mapping to go from samples (pixel/voxel coordinates, indices) to space coordinates."""
2139
coordinates: Optional[str] = None
40+
"""Indexing type of the Mapping field (for example, "cartesian", "spherical" or "index")."""
2241

2342

2443
@dataclass
2544
class X5Transform:
2645
"""Represent one transform entry of an X5 file."""
2746

2847
type: str
48+
"""A REQUIRED unicode string with possible values: "linear", "nonlinear", "composite"."""
2949
transform: np.ndarray
30-
dimension_kinds: Sequence[str]
31-
array_length: int = 1
32-
domain: Optional[X5Domain] = None
50+
"""A REQUIRED array of parameters (e.g., affine matrix, or dense displacements field)."""
3351
subtype: Optional[str] = None
52+
"""An OPTIONAL extension of type to drive the interpretation of AdditionalParameters."""
3453
representation: Optional[str] = None
54+
"""
55+
A string specifiying the transform representation or model, REQUIRED only for nonlinear Type.
56+
"""
3557
metadata: Optional[Dict[str, Any]] = None
58+
"""An OPTIONAL string (JSON) to embed metadata."""
59+
dimension_kinds: Optional[Sequence[str]] = None
60+
"""Identifies what "kind" of information is represented by the samples along each axis."""
61+
domain: Optional[X5Domain] = None
62+
"""
63+
A dataset specifying the reference manifold for the transform (either
64+
a regularly gridded 3D space or a surface/sphere).
65+
REQUIRED for nonlinear Type, RECOMMENDED for linear Type.
66+
"""
3667
inverse: Optional[np.ndarray] = None
68+
"""Placeholder to pre-calculated inverses."""
3769
jacobian: Optional[np.ndarray] = None
38-
additional_parameters: Optional[np.ndarray] = None
70+
"""
71+
A RECOMMENDED data array to keep cached the determinant of Jacobian of the transform
72+
in case tools have calculated it.
73+
For parametric models it is generally possible to obtain it analytically, so this dataset
74+
could not be as useful in that case.
75+
"""
76+
# additional_parameters: Optional[np.ndarray] = None
77+
# AdditionalParameters is empty in the draft spec - ignore for now.
78+
# Only documentation ATM is for SubType:
79+
# The SubType setting enables setting the additional parameters on a dataset called
80+
# "AdditionalParameters" that hangs directly from this transform node.
81+
array_length: int = 1
82+
"""Undocumented field in the draft to enable a single transform group for 4D transforms."""
83+
84+
85+
def to_filename(fname: str | Path, x5_list: List[X5Transform]):
86+
"""
87+
Write a list of :class:`X5Transform` objects to an X5 HDF5 file.
88+
89+
Parameters
90+
----------
91+
fname : :obj:`os.pathlike`
92+
The file name (preferably with the ".x5" extension) in which transforms will be stored.
93+
x5_list : :obj:`list`
94+
The list of transforms to be stored in the output dataset.
3995
96+
Returns
97+
-------
98+
fname : :obj:`os.pathlike`
99+
File containing the transform(s).
40100
41-
def to_filename(fname: str, x5_list: List[X5Transform]):
42-
"""Write a list of :class:`X5Transform` objects to an X5 HDF5 file."""
101+
"""
43102
with h5py.File(str(fname), "w") as out_file:
44103
out_file.attrs["Format"] = "X5"
45104
out_file.attrs["Version"] = np.uint16(1)
@@ -71,8 +130,9 @@ def to_filename(fname: str, x5_list: List[X5Transform]):
71130
g.create_dataset("Inverse", data=node.inverse)
72131
if node.jacobian is not None:
73132
g.create_dataset("Jacobian", data=node.jacobian)
74-
if node.additional_parameters is not None:
75-
g.create_dataset(
76-
"AdditionalParameters", data=node.additional_parameters
77-
)
133+
# Disabled until we need SubType and AdditionalParameters
134+
# if node.additional_parameters is not None:
135+
# g.create_dataset(
136+
# "AdditionalParameters", data=node.additional_parameters
137+
# )
78138
return fname

nitransforms/tests/test_x5.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ def test_x5_transform_defaults():
1616
assert xf.metadata is None
1717
assert xf.inverse is None
1818
assert xf.jacobian is None
19-
assert xf.additional_parameters is None
2019
assert xf.array_length == 1
20+
# Disabled for now
21+
# assert xf.additional_parameters is None
2122

2223

2324
def test_to_filename(tmp_path):

0 commit comments

Comments
 (0)