brainhops.io.transformations.x5
Reader and writer for BIDS X5 (.x5) transformation files.
X5 is the HDF5-based transformation format drafted by the BIDS extension proposal BEP014 ("Transforms"). The draft is not final; this module follows what its two implementations read and write, for interoperability with them:
- nitransforms >= 25.0 (
nitransforms/io/x5.py, and theto_x5/from_x5functions oflinear.py,nonlinear.pyandmanip.py), which writes the current layout,Version = 1; - fslpy 3.x (
fsl/transform/x5.py), which writes an earlier layout,Version = "0.1.0". It is read, and written back in the current layout.
A draft format
Everything below that is not in nitransforms or fslpy is left unimplemented rather than guessed: see "Not supported".
Layout
/ attrs: Format = "X5", Version = 1
/TransformGroup/0 attrs: Type, SubType, Representation,
Metadata (JSON), ArrayLength
Transform the parameters: a 4x4 matrix, or a field
DimensionKinds what each axis of Transform holds,
e.g. ["space", "space", "space", "vector"]
Inverse optional precomputed inverse
Jacobian optional cached Jacobian determinant
AdditionalParameters optional, depends on SubType
Domain/ REQUIRED for nonlinear, RECOMMENDED for linear
Grid 1 if the samples lie on a regular grid
Size the number of samples per dimension
Mapping voxel-to-world affine of the grid
attrs: Coordinates e.g. "cartesian"
/TransformGroup/1 ...
/TransformChain/0 optional: a string "0/1/2" of node indices
Unlike ITK's .h5, which also keeps its transforms under a
TransformGroup, an X5 file has no ITKVersion, and says what it is in
its root Format attribute, which is what tells the two apart. An X5
file named .h5 is therefore read by this reader, not by
brainhops.io.transformations.itk.h5.
Arrays are read as h5py returns them: a field written by nitransforms
or fslpy from a numpy array of shape (X, Y, Z, 3) is read with that
shape, with DimensionKinds ("space", "space", "space", "vector").
When DimensionKinds puts the "vector" axis elsewhere, it is moved
last.
Direction
There are no named source and target spaces in X5. Every transform
maps points of one world space, A, to points of another, B, in RAS
millimetres -- so each one is read as a brainhops transformation whose
input and output are both RASmm, and which maps an input point to
an output point.
- nitransforms: the affine "maps coordinates from reference space
into moving space" (
linear.py,Affine.__init__), and a field is sampled on the reference grid (Domain), mapping each reference point tox + u(x)(nonlinear.py,DenseFieldTransform.map). A is the reference (fixed) space: the transform "pulls" the moving image onto the reference grid. - fslpy: "X5 files enable a transformation from the world coordinate
system of image A to the world coordinate system of image B"
(
x5.py, module docstring). For a linear file, A is the source and B the reference (writeLinearX5(fname, xform, src, ref)writessrcto/A), so the matrix maps source points to reference points. For a nonlinear file, A is the reference (writeNonLinearX5writesfield.refto/A), as with FNIRT.
Both agree on "A to B", which is all that brainhops represents. Which image A is differs between fslpy's linear files and every other file. Resampling an image with a transformation read here is a matter of the caller knowing which of the two images it was registered from.
Fields
A nonlinear node with SubType = "densefield" (or none) is read as:
Representation |
Transformation |
|---|---|
"displacements" (fslpy relative) |
X5DisplacementField |
"deformations" (fslpy absolute) |
X5CoordinatesField |
nitransforms writes "deformations" for a field of absolute
coordinates; "coordinates" and "absolute" are read as the same. A
field of displacements holds, at each voxel of the Domain grid, the
RAS displacement of the point at its centre, and is read as the chain
RAS to voxel, displacements in voxel units, voxel to RAS -- the same
chain as a NIfTI DISPVECT field
(brainhops.io.transformations.nifti), built by the same shared
helpers. It is interpolated linearly, and extended with its nearest
value outside its grid. nitransforms interpolates it with cubic splines
and treats points outside the grid as not displaced, so the two can
differ off the grid nodes.
B-splines
A nonlinear node with SubType = "bspline" and Representation =
"coefficients" is nitransforms' BSplineFieldTransform
(nonlinear.py, to_x5 / from_x5), and is read as an
X5BSplineField:
Transformholds the B-spline coefficients of a displacement in RAS millimetres, one 3-vector per knot,(X, Y, Z, 3)(DimensionKinds("space", "space", "space", "vector"));AdditionalParametersis the voxel-to-RAS affine of the grid of knots: knotksits at voxelkof that grid;Domainis the grid of the reference image, on which nitransforms'to_fieldsamples the field. The transform itself does not depend on it.
nitransforms maps a RAS point x to x + sum_k c_k B3(i(x) - k)
(nonlinear.py, _map_xyz), where i(x) are the coordinates of x
in the grid of knots, and B3 is the tensor product of centred cubic
B-splines (interp/bspline.py, _cubic_bspline); only knots that
exist contribute, so coefficients beyond the grid are zero. The degree
is not stored: nitransforms evaluates cubics only. This is the chain
RAS to knot voxel, a DisplacementField of coefficients (coeff=True,
degree 3, zero boundary) rotated into knot units, knot voxel to RAS --
the same chain as a dense field of displacements, and the same
knot-grid convention as an ITK BSplineTransform
([brainhops.io.transformations.itk][]), whose fixed parameters place
its coefficient grid in LPS.
Any such chain whose input and output are RASmm is written as a
bspline node, with the knot grid as its Domain when it was not read
from a file (nitransforms requires a Domain, and has no other grid to
give it).
Chains
A chain is stored by nitransforms (manip.py,
TransformChain.to_filename) as a string dataset
/TransformChain/<n> listing the indices of its nodes, "0/1/2".
TransformChain.map applies them in that order, f2(f1(f0(x))), which
is the order of a brainhops Sequence, so the chain "0/1/2" is read
as Sequence([t0, t1, t2]). Which nodes are read is described in
X5Transform.selection.
Metadata
The datamodel holds no metadata. The JSON Metadata of every node --
and its Domain, Inverse, Jacobian and other attributes -- is kept,
as read, on the reader (X5Transform.nodes, X5Transform.header), and
written back. A transformation built from scratch is written with no
metadata.
Not supported
These raise an error when the transformation is read (its raw nodes are still read, and written back unchanged):
Type = "composite": the draft lists it, but does not say how its parts are stored, and neither nitransforms nor fslpy writes one;ArrayLength > 1: a stack of affines, one per volume of a series (nitransforms'LinearTransformsMapping), which the datamodel has no transformation for;- domains that are not regular 3-D cartesian grids (surfaces).
These are refused when written: a transformation that does not map
RASmm to RASmm, or that is neither an affine, a dense field, nor a
cubic B-spline with a zero boundary.
Classes
X5BSplineField
X5BSplineField(
_transformations: tuple[Transformation, ...]
| None = None,
)
Bases: _X5RASDisplacements
A nonlinear X5 transform of SubType bspline.
The field holds, at each knot of a regular grid, the cubic B-spline
coefficients of a displacement in RAS millimetres; the grid's
voxel-to-RAS affine is the node's AdditionalParameters (its
Domain is the reference grid, which the transform does not
depend on). The displacement of a point x is
u(x) = sum_k c_k B3(i(x) - k), where i(x) are the coordinates of
x in the knot grid, B3 is the tensor-product centred cubic
B-spline and coefficients beyond the grid are zero; the field maps
RAS to RAS as x -> x + u(x).
| Slot | Transformation |
|---|---|
ras2voxel |
RAS world coordinates to the knot grid |
displacement |
the coefficients, in knot-grid units (coeff) |
voxel2ras |
the knot grid back to RAS world |
Attributes
ras2voxel
property
ras2voxel: Transformation
The affine from RAS world coordinates to the field's voxels.
displacement
property
displacement: Transformation
The displacement field, in the voxel units of its grid.
Methods:
from_dict
classmethod
Create an instance of the class from a dictionary-like object.
Only keys in the dictionary that match keyword-like fields of
this class, or the keywords its constructor takes without
storing them (its InitVars, such as the matrix= of an
Affine), will be used. Other keys are ignored, but see
from_other,
which refuses them.
Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.
A key naming a field that this class fixes (a field that cannot
be passed to its constructor) is checked instead of used: a
dictionary that sets it to anything other than None or the
value of this class is refused with a ValueError.
from_instance
classmethod
Create an instance of the class from an instance of a similar class.
Only attributes of the other instance that match keyword-like
fields of this class will be used. An attribute that is None
is unset, and leaves the default of this class in place.
Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.
Unless the other instance is already an instance of this class,
an attribute naming a field that this class fixes (a field that
cannot be passed to its constructor) is checked instead of used:
an instance that sets it to anything other than None or the
value of this class is refused with a ValueError. A
generic Axis whose orientation is right-to-left, for example,
cannot be read as a LeftToRightAxis.
from_other
classmethod
Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.
A similar class is this class or one of its parents within the
data model, or another member of a polymorphic family this class
belongs to: calling a polymorphic class such as Axis builds the
subclass its arguments select, so a "generic" axis is usually an
instance of a sibling (a RightToLeftAxis, a TimeAxis) rather
than of a parent. Any other object, including an instance of a
parent that is not a data model (such as a plain object), is
passed to the constructor.
Unlike from_dict,
a dictionary with a key that matches no field of this class is
refused with a TypeError naming the keys, so that a
misspelt key is not silently dropped.
compute
compute(
mode: ModeLike = True,
*,
simplify: SimplifyLike = "analytic",
factor: bool = False,
) -> Transformation
Compute the resulting transform of the sequence of transformations.
Assuming that mode=True:
-
If all transformations in the sequence are affine-like transformations,
compute()returns an affine-like transform. -
If the first (= rightmost) transform in the sequence is a coordinate field,
compute()returns a coordinate field. -
If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform,
compute()returns a sequence of two transformations: -
the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and
- the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters
mode : [list of] name or type, optional
Kinds of transformations to compose.
* If True (default): compose every kind in the sequence.
* If False: compose nothing (simplify-only).
* If a (list of) transformation type(s): compose only pairs
of transformations of these kinds.
simplify : simplify policy, default="analytic"
Whether to simplify sub-transformations prior to composition,
and how hard to try to simplify them.
* "analytic" (the default) looks at the type structure only;
* "numeric" looks at the numeric values of the transformation;
* False/"none"/None disables simplification.
factor : bool, default=False
Whether to rewrite the sequence into its axis-group normal
form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any),
one axis-preserving subspace factor per group of axes that
transform together, and a trailing reindex permutation. Off
by default, so the result is byte-for-byte the plain
compute() result. Nothing is ever composed across groups;
mode still decides whether the restricted pieces inside a
group compose. A chain that creates or drops axes is left
unfactored. With mode=False nothing is computed, so
factor has nothing to act on and is ignored.
simplify
simplify(
policy: SimplifyLike = "analytic",
*,
compute: ModeLike | bool | None = False,
) -> Self
Simplify this transformation under a per-kind policy.
Convenience sugar for
compute: t.simplify(policy, compute=mode) is
t.compute(mode, simplify=policy).
By default simplify() does no computation at all: compute=False
maps to mode=False, which composes nothing (no matrices multiplied,
no fields sampled, no lazy inverse materialized). It only downcasts
each leaf under policy (analytic by default). Pass an explicit
compute=<mode> to also compose that kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
simplify policy
|
The simplify policy, in the grammar |
"analytic"
|
compute
|
[list of] name or type
|
The compose mode. The default, |
False
|
square
square(compute: bool = False, **kwargs) -> Transformation
Return the square of this transformation, self @ self.
The square is the sequence [self, self], which composes when it
is computed. It is defined for a transformation that maps a space
to itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute
|
bool
|
Whether to compute the result now rather than return it lazily. |
False
|
**kwargs
|
Passed to |
{}
|
Raises:
| Type | Description |
|---|---|
DomainError
|
If the transformation does not map a space to itself. |
sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation
Return the principal square root of this chain.
The chain is first simplified, which costs nothing. A chain
[P, *X, P^-1], where P^-1 is the lazy inverse of P, or both
are affines whose product is exactly the identity, is a change of
coordinates around X, and its square root is
[P, sqrt(X), P^-1]: a field stored in voxels between a
world-to-voxel affine and its lazy inverse keeps that form. Any
other chain is composed now, and the square root of the
transformation it composes to is returned.
Raises:
| Type | Description |
|---|---|
DomainError
|
If the chain does not map a space to itself, or if the square root of what it reduces to is not defined. |
NotImplementedError
|
If the chain does not compose to a single transformation. |
to
to(
cls: Type[Transformation] | None = None, **kwargs
) -> Transformation
Convert this chain to a different type or encoding.
See Transformation.to. A chain has no tangent of its own -- the tangent of a
composition is not the sum of the tangents -- so log= re-encodes
the transformation it reduces to, and anything else is refused
before it is computed:
- a chain that simplifies to one transformation is that one;
- a change of coordinates
[P, *X, P^-1](seesqrt) keeps its ends, and re-encodesX: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way; - a chain of affines is composed, which is cheap and exact.
Any other chain -- one with a field, between ends that do not undo
each other -- raises ConversionError.
from_ras
classmethod
from_ras(vectors: ArrayProtocol, vox2ras: ndarray) -> Self
Build the field from RAS vectors and their grid.
X5CoordinatesField
X5CoordinatesField(
_transformations: tuple[Transformation, ...]
| None = None,
)
Bases: ImmutableSequence
A nonlinear X5 transform that stores absolute coordinates.
Each sample of the field holds the RAS coordinates, in millimetres,
that the world point at its centre maps to. The Domain/Mapping of
the node is the voxel-to-RAS affine of its grid.
| Slot | Transformation |
|---|---|
ras2voxel |
RAS world coordinates to the field's voxels |
coordinates |
the field of RAS coordinates |
Attributes
ras2voxel
property
ras2voxel: Transformation
The affine from RAS world coordinates to the field's voxels.
coordinates
property
coordinates: Transformation
The field of RAS coordinates, defined on the field's voxels.
Methods:
from_dict
classmethod
Create an instance of the class from a dictionary-like object.
Only keys in the dictionary that match keyword-like fields of
this class, or the keywords its constructor takes without
storing them (its InitVars, such as the matrix= of an
Affine), will be used. Other keys are ignored, but see
from_other,
which refuses them.
Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.
A key naming a field that this class fixes (a field that cannot
be passed to its constructor) is checked instead of used: a
dictionary that sets it to anything other than None or the
value of this class is refused with a ValueError.
from_instance
classmethod
Create an instance of the class from an instance of a similar class.
Only attributes of the other instance that match keyword-like
fields of this class will be used. An attribute that is None
is unset, and leaves the default of this class in place.
Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.
Unless the other instance is already an instance of this class,
an attribute naming a field that this class fixes (a field that
cannot be passed to its constructor) is checked instead of used:
an instance that sets it to anything other than None or the
value of this class is refused with a ValueError. A
generic Axis whose orientation is right-to-left, for example,
cannot be read as a LeftToRightAxis.
from_other
classmethod
Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.
A similar class is this class or one of its parents within the
data model, or another member of a polymorphic family this class
belongs to: calling a polymorphic class such as Axis builds the
subclass its arguments select, so a "generic" axis is usually an
instance of a sibling (a RightToLeftAxis, a TimeAxis) rather
than of a parent. Any other object, including an instance of a
parent that is not a data model (such as a plain object), is
passed to the constructor.
Unlike from_dict,
a dictionary with a key that matches no field of this class is
refused with a TypeError naming the keys, so that a
misspelt key is not silently dropped.
compute
compute(
mode: ModeLike = True,
*,
simplify: SimplifyLike = "analytic",
factor: bool = False,
) -> Transformation
Compute the resulting transform of the sequence of transformations.
Assuming that mode=True:
-
If all transformations in the sequence are affine-like transformations,
compute()returns an affine-like transform. -
If the first (= rightmost) transform in the sequence is a coordinate field,
compute()returns a coordinate field. -
If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform,
compute()returns a sequence of two transformations: -
the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and
- the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters
mode : [list of] name or type, optional
Kinds of transformations to compose.
* If True (default): compose every kind in the sequence.
* If False: compose nothing (simplify-only).
* If a (list of) transformation type(s): compose only pairs
of transformations of these kinds.
simplify : simplify policy, default="analytic"
Whether to simplify sub-transformations prior to composition,
and how hard to try to simplify them.
* "analytic" (the default) looks at the type structure only;
* "numeric" looks at the numeric values of the transformation;
* False/"none"/None disables simplification.
factor : bool, default=False
Whether to rewrite the sequence into its axis-group normal
form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any),
one axis-preserving subspace factor per group of axes that
transform together, and a trailing reindex permutation. Off
by default, so the result is byte-for-byte the plain
compute() result. Nothing is ever composed across groups;
mode still decides whether the restricted pieces inside a
group compose. A chain that creates or drops axes is left
unfactored. With mode=False nothing is computed, so
factor has nothing to act on and is ignored.
simplify
simplify(
policy: SimplifyLike = "analytic",
*,
compute: ModeLike | bool | None = False,
) -> Self
Simplify this transformation under a per-kind policy.
Convenience sugar for
compute: t.simplify(policy, compute=mode) is
t.compute(mode, simplify=policy).
By default simplify() does no computation at all: compute=False
maps to mode=False, which composes nothing (no matrices multiplied,
no fields sampled, no lazy inverse materialized). It only downcasts
each leaf under policy (analytic by default). Pass an explicit
compute=<mode> to also compose that kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
simplify policy
|
The simplify policy, in the grammar |
"analytic"
|
compute
|
[list of] name or type
|
The compose mode. The default, |
False
|
square
square(compute: bool = False, **kwargs) -> Transformation
Return the square of this transformation, self @ self.
The square is the sequence [self, self], which composes when it
is computed. It is defined for a transformation that maps a space
to itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute
|
bool
|
Whether to compute the result now rather than return it lazily. |
False
|
**kwargs
|
Passed to |
{}
|
Raises:
| Type | Description |
|---|---|
DomainError
|
If the transformation does not map a space to itself. |
sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation
Return the principal square root of this chain.
The chain is first simplified, which costs nothing. A chain
[P, *X, P^-1], where P^-1 is the lazy inverse of P, or both
are affines whose product is exactly the identity, is a change of
coordinates around X, and its square root is
[P, sqrt(X), P^-1]: a field stored in voxels between a
world-to-voxel affine and its lazy inverse keeps that form. Any
other chain is composed now, and the square root of the
transformation it composes to is returned.
Raises:
| Type | Description |
|---|---|
DomainError
|
If the chain does not map a space to itself, or if the square root of what it reduces to is not defined. |
NotImplementedError
|
If the chain does not compose to a single transformation. |
to
to(
cls: Type[Transformation] | None = None, **kwargs
) -> Transformation
Convert this chain to a different type or encoding.
See Transformation.to. A chain has no tangent of its own -- the tangent of a
composition is not the sum of the tangents -- so log= re-encodes
the transformation it reduces to, and anything else is refused
before it is computed:
- a chain that simplifies to one transformation is that one;
- a change of coordinates
[P, *X, P^-1](seesqrt) keeps its ends, and re-encodesX: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way; - a chain of affines is composed, which is cheap and exact.
Any other chain -- one with a field, between ends that do not undo
each other -- raises ConversionError.
from_ras
classmethod
from_ras(
coordinates: ArrayProtocol, vox2ras: ndarray
) -> Self
Build the field from RAS coordinates and their grid.
X5DisplacementField
X5DisplacementField(
_transformations: tuple[Transformation, ...]
| None = None,
)
Bases: _X5RASDisplacements
A nonlinear X5 transform that stores relative displacements.
Each sample of the field holds the displacement, in RAS millimetres,
of the world point at its centre: the field maps RAS to RAS as
x -> x + u(x). The Domain/Mapping of the node is the voxel-to-RAS
affine of its grid.
| Slot | Transformation |
|---|---|
ras2voxel |
RAS world coordinates to the field's voxels |
displacement |
the displacement field, in voxel units |
voxel2ras |
the field's voxels back to RAS world |
Attributes
bound
class-attribute
bound: BoundaryCondition = BoundaryCondition.nearest
The boundary condition used outside of the field of view.
coeff
class-attribute
coeff: bool = False
Whether the field holds spline coefficients rather than values.
ras2voxel
property
ras2voxel: Transformation
The affine from RAS world coordinates to the field's voxels.
displacement
property
displacement: Transformation
The displacement field, in the voxel units of its grid.
Methods:
from_dict
classmethod
Create an instance of the class from a dictionary-like object.
Only keys in the dictionary that match keyword-like fields of
this class, or the keywords its constructor takes without
storing them (its InitVars, such as the matrix= of an
Affine), will be used. Other keys are ignored, but see
from_other,
which refuses them.
Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.
A key naming a field that this class fixes (a field that cannot
be passed to its constructor) is checked instead of used: a
dictionary that sets it to anything other than None or the
value of this class is refused with a ValueError.
from_instance
classmethod
Create an instance of the class from an instance of a similar class.
Only attributes of the other instance that match keyword-like
fields of this class will be used. An attribute that is None
is unset, and leaves the default of this class in place.
Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.
Unless the other instance is already an instance of this class,
an attribute naming a field that this class fixes (a field that
cannot be passed to its constructor) is checked instead of used:
an instance that sets it to anything other than None or the
value of this class is refused with a ValueError. A
generic Axis whose orientation is right-to-left, for example,
cannot be read as a LeftToRightAxis.
from_other
classmethod
Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.
A similar class is this class or one of its parents within the
data model, or another member of a polymorphic family this class
belongs to: calling a polymorphic class such as Axis builds the
subclass its arguments select, so a "generic" axis is usually an
instance of a sibling (a RightToLeftAxis, a TimeAxis) rather
than of a parent. Any other object, including an instance of a
parent that is not a data model (such as a plain object), is
passed to the constructor.
Unlike from_dict,
a dictionary with a key that matches no field of this class is
refused with a TypeError naming the keys, so that a
misspelt key is not silently dropped.
compute
compute(
mode: ModeLike = True,
*,
simplify: SimplifyLike = "analytic",
factor: bool = False,
) -> Transformation
Compute the resulting transform of the sequence of transformations.
Assuming that mode=True:
-
If all transformations in the sequence are affine-like transformations,
compute()returns an affine-like transform. -
If the first (= rightmost) transform in the sequence is a coordinate field,
compute()returns a coordinate field. -
If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform,
compute()returns a sequence of two transformations: -
the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and
- the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters
mode : [list of] name or type, optional
Kinds of transformations to compose.
* If True (default): compose every kind in the sequence.
* If False: compose nothing (simplify-only).
* If a (list of) transformation type(s): compose only pairs
of transformations of these kinds.
simplify : simplify policy, default="analytic"
Whether to simplify sub-transformations prior to composition,
and how hard to try to simplify them.
* "analytic" (the default) looks at the type structure only;
* "numeric" looks at the numeric values of the transformation;
* False/"none"/None disables simplification.
factor : bool, default=False
Whether to rewrite the sequence into its axis-group normal
form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any),
one axis-preserving subspace factor per group of axes that
transform together, and a trailing reindex permutation. Off
by default, so the result is byte-for-byte the plain
compute() result. Nothing is ever composed across groups;
mode still decides whether the restricted pieces inside a
group compose. A chain that creates or drops axes is left
unfactored. With mode=False nothing is computed, so
factor has nothing to act on and is ignored.
simplify
simplify(
policy: SimplifyLike = "analytic",
*,
compute: ModeLike | bool | None = False,
) -> Self
Simplify this transformation under a per-kind policy.
Convenience sugar for
compute: t.simplify(policy, compute=mode) is
t.compute(mode, simplify=policy).
By default simplify() does no computation at all: compute=False
maps to mode=False, which composes nothing (no matrices multiplied,
no fields sampled, no lazy inverse materialized). It only downcasts
each leaf under policy (analytic by default). Pass an explicit
compute=<mode> to also compose that kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
simplify policy
|
The simplify policy, in the grammar |
"analytic"
|
compute
|
[list of] name or type
|
The compose mode. The default, |
False
|
square
square(compute: bool = False, **kwargs) -> Transformation
Return the square of this transformation, self @ self.
The square is the sequence [self, self], which composes when it
is computed. It is defined for a transformation that maps a space
to itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute
|
bool
|
Whether to compute the result now rather than return it lazily. |
False
|
**kwargs
|
Passed to |
{}
|
Raises:
| Type | Description |
|---|---|
DomainError
|
If the transformation does not map a space to itself. |
sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation
Return the principal square root of this chain.
The chain is first simplified, which costs nothing. A chain
[P, *X, P^-1], where P^-1 is the lazy inverse of P, or both
are affines whose product is exactly the identity, is a change of
coordinates around X, and its square root is
[P, sqrt(X), P^-1]: a field stored in voxels between a
world-to-voxel affine and its lazy inverse keeps that form. Any
other chain is composed now, and the square root of the
transformation it composes to is returned.
Raises:
| Type | Description |
|---|---|
DomainError
|
If the chain does not map a space to itself, or if the square root of what it reduces to is not defined. |
NotImplementedError
|
If the chain does not compose to a single transformation. |
to
to(
cls: Type[Transformation] | None = None, **kwargs
) -> Transformation
Convert this chain to a different type or encoding.
See Transformation.to. A chain has no tangent of its own -- the tangent of a
composition is not the sum of the tangents -- so log= re-encodes
the transformation it reduces to, and anything else is refused
before it is computed:
- a chain that simplifies to one transformation is that one;
- a change of coordinates
[P, *X, P^-1](seesqrt) keeps its ends, and re-encodesX: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way; - a chain of affines is composed, which is cheap and exact.
Any other chain -- one with a field, between ends that do not undo
each other -- raises ConversionError.
from_ras
classmethod
from_ras(vectors: ArrayProtocol, vox2ras: ndarray) -> Self
Build the field from RAS vectors and their grid.
X5Domain
magic
X5Domain(
grid: bool = True,
size: tuple[int, ...] = (),
mapping: Any = None,
coordinates: str | None = None,
)
Bases: Magic
The Domain group of a transform: the grid it is sampled on.
REQUIRED for a nonlinear transform, RECOMMENDED for a linear one.
Attributes
grid
class-attribute
instance-attribute
grid: bool = True
Whether the samples lie on a regular grid (Grid dataset).
size
class-attribute
instance-attribute
size: tuple[int, ...] = ()
The number of samples per dimension (Size dataset).
mapping
class-attribute
instance-attribute
mapping: Any = None
The (D + 1, D + 1) affine from sample indices to world (RAS)
coordinates (Mapping dataset): the voxel-to-RAS affine of the grid.
coordinates
class-attribute
instance-attribute
coordinates: str | None = None
The kind of world coordinates (Coordinates attribute), e.g.
"cartesian".
X5Header
magic
X5Header(
format: str = X5_FORMAT,
version: Any = X5_VERSION,
attrs: dict[str, Any] = Factory(dict),
chains: list[tuple[int, ...]] = Factory(list),
legacy: bool = False,
)
Bases: Magic
The root of an X5 file: its attributes and its chains.
Attributes
version
class-attribute
instance-attribute
version: Any = X5_VERSION
The root Version attribute, as read: 1 for the current draft,
"0.1.0" for fslpy's earlier layout.
attrs
class-attribute
instance-attribute
Any other root attribute, as read.
chains
class-attribute
instance-attribute
The chains of /TransformChain, in order: each lists, in the order
they are applied, the indices of the transforms it chains.
legacy
class-attribute
instance-attribute
legacy: bool = False
Whether the file used fslpy's earlier (0.x) layout.
X5Node
magic
X5Node(
type: str = "linear",
transform: Any = None,
subtype: str | None = None,
representation: str | None = None,
metadata: Any = None,
dimension_kinds: tuple[str, ...] | None = None,
domain: X5Domain | None = None,
inverse: Any = None,
jacobian: Any = None,
additional_parameters: Any = None,
array_length: int = 1,
attrs: dict[str, Any] = Factory(dict),
)
Bases: Magic
One numbered group /TransformGroup/<i> of an X5 file.
Every field mirrors an attribute or a dataset of the group. Large
datasets (Transform, Inverse, Jacobian) are read lazily when
the file is opened with load=False.
Attributes
type
class-attribute
instance-attribute
type: str = 'linear'
Type: "linear", "nonlinear" or "composite". fslpy's
"affine" is read as "linear".
transform
class-attribute
instance-attribute
transform: Any = None
Transform: the parameters -- a (D + 1, D + 1) matrix, a stack
of them, or a dense field.
subtype
class-attribute
instance-attribute
subtype: str | None = None
SubType, e.g. "affine", "densefield" or "bspline".
representation
class-attribute
instance-attribute
representation: str | None = None
Representation, e.g. "matrix", "displacements" or
"deformations".
metadata
class-attribute
instance-attribute
metadata: Any = None
Metadata: the JSON attribute, decoded (a dict), or the raw
string if it is not valid JSON.
dimension_kinds
class-attribute
instance-attribute
dimension_kinds: tuple[str, ...] | None = None
DimensionKinds: what each axis of transform holds, e.g.
("space", "space", "space", "vector").
inverse
class-attribute
instance-attribute
inverse: Any = None
Inverse: an optional precomputed inverse.
jacobian
class-attribute
instance-attribute
jacobian: Any = None
Jacobian: an optional cached Jacobian determinant.
additional_parameters
class-attribute
instance-attribute
additional_parameters: Any = None
AdditionalParameters: subtype-specific parameters (for a
bspline, the affine of the grid of knots).
array_length
class-attribute
instance-attribute
array_length: int = 1
ArrayLength: how many transforms transform stacks.
X5Transform
magic
X5Transform(
header: X5Header = Factory(X5Header, repr=False),
nodes: list[X5Node] = Factory(list, repr=False),
chain: int | None = None,
position: int | None = None,
file: File | None = None,
)
Bases: X5TransformParser, Sequence, WritableFileBasedTransformation
A transformation stored in a BIDS X5 (.x5) file.
It is the Sequence
of the transforms that the file chains, in the order in which they
are applied (see selection). Every transform maps
RAS world coordinates, in millimetres, to RAS world coordinates:
| X5 node | Transformation |
|---|---|
linear, a 4x4 matrix |
Affine (RASmm to RASmm) |
nonlinear, displacements |
X5DisplacementField |
nonlinear, deformations |
X5CoordinatesField |
nonlinear, bspline |
X5BSplineField |
The raw content of the file -- every node, with its JSON
Metadata, its Domain, its precomputed Inverse and any other
attribute -- is kept in header and nodes.
What is written
A transformation read from a file, whose chain has not been
assigned, is written back as it was read: every node and chain
of the file, in the current layout. One whose transformations
were assigned -- including one built from scratch -- is written
as the nodes those transformations encode, plus one
/TransformChain that applies them in order when there are
several. An element that is one of the transformations read
from a node is written as that node, unchanged, so its metadata
survives. The package documentation lists what can be encoded.
Attributes
PREFIXES
class-attribute
PREFIXES: tuple[str, ...] = ()
Filename prefixes required by this parser, e.g. ("y_", "iy_").
An empty tuple means "no constraint". A parser that constrains the prefix is more specific than one that does not, and wins ties.
Declaring EXTENSIONS and PREFIXES separately states the
cross-product implicitly, which is how these conventions actually
work: SPM's four names are {y_, iy_} x {.nii, .nii.gz}.
PRIORITY
class-attribute
PRIORITY: int = 0
Explicit tie-breaker, consulted only when specificity cannot decide.
Higher wins. Leave at 0 unless two parsers genuinely collide.
header
class-attribute
instance-attribute
The root attributes and the chains of the file.
nodes
class-attribute
instance-attribute
Every transform of /TransformGroup, as stored.
chain
class-attribute
instance-attribute
chain: int | None = None
Which chain of /TransformChain the transformation is, if any.
See X5Transform.selection.
position
class-attribute
instance-attribute
position: int | None = None
Which single transform of /TransformGroup the transformation is,
if any. See X5Transform.selection.
file
class-attribute
instance-attribute
The open HDF5 file, when read with keep_open=True.
selection
property
selection: tuple[int, ...]
The indices of the nodes this transformation chains, in order.
- The chain
chainof/TransformChain, if one was asked for. - The node
position, if one was asked for. - Otherwise the first chain of
/TransformChain, if the file has one, as nitransforms'TransformChain.from_filenamedoes. - Otherwise the file's single node.
- Otherwise, in a file with several nodes and no chain, the first
node, as nitransforms'
Affine.from_filenameandDenseFieldTransform.from_filenamedo, with a warning: the draft says nothing of how unchained nodes relate.
Methods:
sniff
classmethod
sniff(
file: FileOrContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read
file. On a concrete format, score how confident it is that
file, in any supported form, is its own.
sniff_file
classmethod
Score a path, open HDF5 file, or binary stream.
sniff_filename
classmethod
sniff_filename(
filename: str | PathLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Score the HDF5 file found at a path.
sniff_fileobj
classmethod
Score an open, seekable binary stream.
sniff_content
classmethod
sniff_content(
content: ContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read the content (text or bytes). On a concrete format, score how confident it is that the content is its own.
sniff_bytes
classmethod
Score the bytes of an HDF5 file.
sniff_text
classmethod
On a dispatcher, identify which registered format would read the text. On a concrete format, score how confident it is that the text is its own.
sniff_lines
classmethod
sniff_lines(
lines: Iterable[str],
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read the lines. On a concrete format, score how confident it is that the lines are its own.
sniff_line
classmethod
On a dispatcher, identify which registered format would read the line. On a concrete format, score how confident it is that the line is its own.
load
classmethod
load(other: FileOrContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and
build an instance of it from other. On a concrete format,
build an instance of this class from other, in any supported
form.
from_spec
classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self
Load a structured source specification through this dispatcher.
from_file
classmethod
Build an object from a file (path, file-like object, or HDF5 file).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
str | PathLike | IO | File
|
Input file. |
required |
keep_open
|
bool
|
If True, keep the HDF5 file open after loading.
If False, close the file after loading.
If |
False
|
load
|
bool
|
If True, read large datasets into memory. If False, keep them on disk. |
True
|
from_filename
classmethod
from_filename(
filename: str | PathLike,
keep_open: bool = False,
load: bool = True,
**kwargs,
) -> Self
Build an object from the HDF5 file found at a path.
from_fileobj
classmethod
Build an object from an open, seekable binary stream.
from_content
classmethod
from_content(content: ContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and build an instance of it from the content (text or bytes). On a concrete format, build an instance of this class from the content.
from_bytes
classmethod
from_bytes(content: BinaryContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and build an instance of it from the bytes. On a concrete format, build an instance of this class from the bytes.
from_text
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the text. On a concrete format, build an instance of this class from the text.
from_lines
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the lines. On a concrete format, build an instance of this class from the lines.
from_line
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the line. On a concrete format, build an instance of this class from the line.
save
save(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
This is the generic front door to the to_* family. It is named
save rather than to because to already means something else
on the data models these parsers are mixed into: Transformation.to
converts an object to another type. A writer's to was shadowed
by it on every writable transformation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_file
to_file(file: H5Like, **kwargs) -> None
Write to a path, an open binary stream, or an HDF5 file.
to_filename
Write to the file found at a path, replacing it.
to_text
to_text(**kwargs) -> str
Return a text version of the file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A text version of the file. |
to_lines
Return a text version of the file as an iterable of lines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
Iterator[str]
|
An iterable of lines representing the object. |
to_line
to_line(**kwargs) -> str
Return a line representing the object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A line representing the object. |
from_dict
classmethod
Create an instance of the class from a dictionary-like object.
Only keys in the dictionary that match keyword-like fields of
this class, or the keywords its constructor takes without
storing them (its InitVars, such as the matrix= of an
Affine), will be used. Other keys are ignored, but see
from_other,
which refuses them.
Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.
A key naming a field that this class fixes (a field that cannot
be passed to its constructor) is checked instead of used: a
dictionary that sets it to anything other than None or the
value of this class is refused with a ValueError.
from_instance
classmethod
Create an instance from an instance of a similar class.
The data model copies the fields both classes share, by name.
A field that a file format declares for its own use -- such as
the nibabel image and header of the NIfTI and MGH formats
-- is only copied from an object of that same format: from any
other object, a field of the same name holds something else
(a NIfTI image is no MGH image), so this class's default is
kept instead. Saving a NIfTI image to MGH, or the converse,
therefore converts the data model only, and the format-specific
state is rebuilt by the writer.
from_other
classmethod
Create an instance from a file, or from anything the data model reads.
A path (str or os.PathLike), an open file, bytes or a
structured source (SourceSpec)
is read with load: on a dispatcher such as FileBasedImage,
the best-matching registered format reads it, and on a concrete
format, that format does. Any other value is handed to the data
model's own from_other, which reads a mapping field by field,
copies an instance of a similar class, and passes anything else
to the constructor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Any
|
A file, its content, a mapping, or an instance of a similar class. |
required |
*args
|
Constructor arguments. A file is read with keyword options only. |
()
|
|
**kwargs
|
Format-specific options when reading a file, and field values otherwise. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The object that was built. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If positional arguments come with a file to read. |
compute
compute(
mode: ModeLike = True,
*,
simplify: SimplifyLike = "analytic",
factor: bool = False,
) -> Transformation
Compute the resulting transform of the sequence of transformations.
Assuming that mode=True:
-
If all transformations in the sequence are affine-like transformations,
compute()returns an affine-like transform. -
If the first (= rightmost) transform in the sequence is a coordinate field,
compute()returns a coordinate field. -
If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform,
compute()returns a sequence of two transformations: -
the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and
- the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters
mode : [list of] name or type, optional
Kinds of transformations to compose.
* If True (default): compose every kind in the sequence.
* If False: compose nothing (simplify-only).
* If a (list of) transformation type(s): compose only pairs
of transformations of these kinds.
simplify : simplify policy, default="analytic"
Whether to simplify sub-transformations prior to composition,
and how hard to try to simplify them.
* "analytic" (the default) looks at the type structure only;
* "numeric" looks at the numeric values of the transformation;
* False/"none"/None disables simplification.
factor : bool, default=False
Whether to rewrite the sequence into its axis-group normal
form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any),
one axis-preserving subspace factor per group of axes that
transform together, and a trailing reindex permutation. Off
by default, so the result is byte-for-byte the plain
compute() result. Nothing is ever composed across groups;
mode still decides whether the restricted pieces inside a
group compose. A chain that creates or drops axes is left
unfactored. With mode=False nothing is computed, so
factor has nothing to act on and is ignored.
simplify
simplify(
policy: SimplifyLike = "analytic",
*,
compute: ModeLike | bool | None = False,
) -> Self
Simplify this transformation under a per-kind policy.
Convenience sugar for
compute: t.simplify(policy, compute=mode) is
t.compute(mode, simplify=policy).
By default simplify() does no computation at all: compute=False
maps to mode=False, which composes nothing (no matrices multiplied,
no fields sampled, no lazy inverse materialized). It only downcasts
each leaf under policy (analytic by default). Pass an explicit
compute=<mode> to also compose that kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
simplify policy
|
The simplify policy, in the grammar |
"analytic"
|
compute
|
[list of] name or type
|
The compose mode. The default, |
False
|
square
square(compute: bool = False, **kwargs) -> Transformation
Return the square of this transformation, self @ self.
The square is the sequence [self, self], which composes when it
is computed. It is defined for a transformation that maps a space
to itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute
|
bool
|
Whether to compute the result now rather than return it lazily. |
False
|
**kwargs
|
Passed to |
{}
|
Raises:
| Type | Description |
|---|---|
DomainError
|
If the transformation does not map a space to itself. |
sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation
Return the principal square root of this chain.
The chain is first simplified, which costs nothing. A chain
[P, *X, P^-1], where P^-1 is the lazy inverse of P, or both
are affines whose product is exactly the identity, is a change of
coordinates around X, and its square root is
[P, sqrt(X), P^-1]: a field stored in voxels between a
world-to-voxel affine and its lazy inverse keeps that form. Any
other chain is composed now, and the square root of the
transformation it composes to is returned.
Raises:
| Type | Description |
|---|---|
DomainError
|
If the chain does not map a space to itself, or if the square root of what it reduces to is not defined. |
NotImplementedError
|
If the chain does not compose to a single transformation. |
to
to(
cls: Type[Transformation] | None = None, **kwargs
) -> Transformation
Convert this chain to a different type or encoding.
See Transformation.to. A chain has no tangent of its own -- the tangent of a
composition is not the sum of the tangents -- so log= re-encodes
the transformation it reduces to, and anything else is refused
before it is computed:
- a chain that simplifies to one transformation is that one;
- a change of coordinates
[P, *X, P^-1](seesqrt) keeps its ends, and re-encodesX: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way; - a chain of affines is composed, which is cheap and exact.
Any other chain -- one with a field, between ends that do not undo
each other -- raises ConversionError.
sniff_h5
classmethod
Score an open HDF5 file: an X5 file says so in its root
Format attribute.
from_h5
classmethod
from_h5(
h5file: File,
keep_open: bool = False,
load: bool = True,
chain: int | None = None,
position: int | None = None,
**kwargs,
) -> Self
Build an object from an open HDF5 file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
Input HDF5 file. |
required |
keep_open
|
bool
|
Keep the file open after reading it. |
False
|
load
|
bool
|
Read the fields into memory. If |
True
|
chain
|
int
|
Which chain of |
None
|
position
|
int
|
Which single transform of |
None
|
node_transformation
node_transformation(index: int) -> Transformation
The transformation that node index encodes.
It is decoded once, and the same object is returned afterwards, which is how the writer recognises it.
transformations
transformations() -> tuple[Transformation, ...]
The chain of transformations, in the order they are applied.
It is decoded from the nodes on first access, and cached, as a tuple. Assigning to it overrides the decoded chain, and is what the writer then encodes.
X5TransformParser
magic
X5TransformParser(
header: X5Header = Factory(X5Header, repr=False),
nodes: list[X5Node] = Factory(list, repr=False),
chain: int | None = None,
position: int | None = None,
file: File | None = None,
)
Bases: Magic, Hdf5ParserWriter
Reads and writes the raw content of a BIDS X5 file.
Attributes
EXTENSIONS
class-attribute
EXTENSIONS: tuple[str, ...] = ()
File extensions handled by this parser, e.g. (".nii", ".nii.gz").
Used as a first, cheap dispatch pass. When several parsers match,
the longest matching extension wins, so a parser declaring
".nii.gz" takes precedence over one declaring ".gz".
PREFIXES
class-attribute
PREFIXES: tuple[str, ...] = ()
Filename prefixes required by this parser, e.g. ("y_", "iy_").
An empty tuple means "no constraint". A parser that constrains the prefix is more specific than one that does not, and wins ties.
Declaring EXTENSIONS and PREFIXES separately states the
cross-product implicitly, which is how these conventions actually
work: SPM's four names are {y_, iy_} x {.nii, .nii.gz}.
PRIORITY
class-attribute
PRIORITY: int = 0
Explicit tie-breaker, consulted only when specificity cannot decide.
Higher wins. Leave at 0 unless two parsers genuinely collide.
header
class-attribute
instance-attribute
The root attributes and the chains of the file.
nodes
class-attribute
instance-attribute
Every transform of /TransformGroup, as stored.
chain
class-attribute
instance-attribute
chain: int | None = None
Which chain of /TransformChain the transformation is, if any.
See X5Transform.selection.
position
class-attribute
instance-attribute
position: int | None = None
Which single transform of /TransformGroup the transformation is,
if any. See X5Transform.selection.
file
class-attribute
instance-attribute
The open HDF5 file, when read with keep_open=True.
Methods:
sniff
classmethod
sniff(
file: FileOrContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given file is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileOrContentLike
|
The file to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the file cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the file is of this type, in |
sniff_file
classmethod
Score a path, open HDF5 file, or binary stream.
sniff_filename
classmethod
sniff_filename(
filename: str | PathLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Score the HDF5 file found at a path.
sniff_fileobj
classmethod
Score an open, seekable binary stream.
sniff_content
classmethod
sniff_content(
content: ContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given content is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
ContentLike
|
The content to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the content cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the content is of this type, in |
sniff_bytes
classmethod
Score the bytes of an HDF5 file.
sniff_text
classmethod
Determine if the given text is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the content cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the text is of this type, in |
sniff_lines
classmethod
Determine if the given lines are of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines
|
Iterable[str]
|
The lines to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the content cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the lines is of this type, in |
sniff_line
classmethod
Determine if the given line is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
str
|
The line to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the content cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the line is of this type, in |
load
classmethod
load(other: FileOrContentLike, **kwargs) -> Self
Build an object from a file (path, file-like object or iterable of lines).
This is the generic front door to the from_* family: it looks
at what it was handed and calls the right one.
A str is always a path, whether or not the file exists, so a
missing file raises FileNotFoundError whichever way its path
was spelled. Text held in memory is read with from_text or
from_content.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
FileOrContentLike
|
Input file, or its content. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
Raises:
| Type | Description |
|---|---|
ParserExistsError
|
If |
from_spec
classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self
Build an object from an unqualified structured source.
from_file
classmethod
Build an object from a file (path, file-like object, or HDF5 file).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
str | PathLike | IO | File
|
Input file. |
required |
keep_open
|
bool
|
If True, keep the HDF5 file open after loading.
If False, close the file after loading.
If |
False
|
load
|
bool
|
If True, read large datasets into memory. If False, keep them on disk. |
True
|
from_filename
classmethod
from_filename(
filename: str | PathLike,
keep_open: bool = False,
load: bool = True,
**kwargs,
) -> Self
Build an object from the HDF5 file found at a path.
from_fileobj
classmethod
Build an object from an open, seekable binary stream.
from_content
classmethod
from_content(content: ContentLike, **kwargs) -> Self
Build an object from a file content (bytes, str, or iterable of lines).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
ContentLike
|
The content to parse. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_bytes
classmethod
from_bytes(content: BinaryContentLike, **kwargs) -> Self
Build an object from a binary representation of a file.
If the class implements from_fileobj itself, the bytes are
wrapped in an io.BytesIO stream and handed to from_fileobj.
Otherwise, this raises ParserNotImplementedError: the default
from_fileobj delegates to from_bytes, so falling back to it
would recurse. A from_fileobj override that only forwards to
super().from_fileobj should be decorated with
_passthrough_from_fileobj; if it is not, the loop is still
detected when from_bytes is re-entered for the same class, and
ParserNotImplementedError is raised.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
BinaryContentLike
|
The content to parse. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
Raises:
| Type | Description |
|---|---|
ParserNotImplementedError
|
If neither |
from_text
classmethod
Build an object from a text representation of a file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to parse. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_lines
classmethod
from_line
classmethod
Build an object from a single line of text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
str
|
The line to parse. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
save
save(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
This is the generic front door to the to_* family. It is named
save rather than to because to already means something else
on the data models these parsers are mixed into: Transformation.to
converts an object to another type. A writer's to was shadowed
by it on every writable transformation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_file
to_file(file: H5Like, **kwargs) -> None
Write to a path, an open binary stream, or an HDF5 file.
to_filename
Write to the file found at a path, replacing it.
to_text
to_text(**kwargs) -> str
Return a text version of the file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A text version of the file. |
to_lines
Return a text version of the file as an iterable of lines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
Iterator[str]
|
An iterable of lines representing the object. |
to_line
to_line(**kwargs) -> str
Return a line representing the object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A line representing the object. |
sniff_h5
classmethod
Score an open HDF5 file: an X5 file says so in its root
Format attribute.
from_h5
classmethod
from_h5(
h5file: File,
keep_open: bool = False,
load: bool = True,
chain: int | None = None,
position: int | None = None,
**kwargs,
) -> Self
Build an object from an open HDF5 file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
h5file
|
File
|
Input HDF5 file. |
required |
keep_open
|
bool
|
Keep the file open after reading it. |
False
|
load
|
bool
|
Read the fields into memory. If |
True
|
chain
|
int
|
Which chain of |
None
|
position
|
int
|
Which single transform of |
None
|
to_struct
The header and the nodes that encode this object.