larmor.types#

The core data types: grids, volumes, tractograms, surfaces, gradients and labels.

GradientTable

The diffusion weighting of each volume of a DWI, in the order of the volumes.

Grid

The voxel grid an object (Volume, Tractogram) lives on.

Label

One entry of a lookup table: a label's name and colour.

Surface

A triangle mesh in world coordinates, with named values per vertex.

Tractogram

A set of streamlines, stored as one flat array of points and their offsets.

Volume

Volume from an MRI acquisition.

class larmor.types.GradientTable(bvals, bvecs, b0_threshold=50.0, shell_epsilon=80.0)#

The diffusion weighting of each volume of a DWI, in the order of the volumes.

On construction the table is checked, then normalised: each b-value is scaled by the squared length of its vector (the b-value actually applied), and each vector is scaled to unit length. A vector of length 0.5 at b = 2800 therefore becomes a unit vector at b = 700. The caller’s arrays are copied, not changed.

The checks run only on construction: change a table through flip and permute, not by assigning its fields.

Parameters:
  • bvals (ndarray) – (N,) b-values in s/mm^2.

  • bvecs (ndarray) – (N, 3) gradient directions in world coordinates (RAS+), unitless. A row of NaN means no direction, like (0, 0, 0).

  • b0_threshold (float) – b-values at or below this, in s/mm^2, count as b=0. Defaults to 50.0.

  • shell_epsilon (float) – A gap larger than this between sorted b-values, in s/mm^2, starts a new shell. Defaults to 80.0.

Raises:

ValueError – If the table is empty, the shapes are not (N,) and (N, 3), a b-value is negative, NaN or infinite, a vector has an infinite component, or a volume above b0_threshold has no direction.

property b0_mask: ndarray#

b-value at or below b0_threshold.

Returns:

np.ndarray – (N,) bool.

Type:

Which volumes are b0s

property b_matrix: ndarray#

The six distinct elements of b * g g^T for each volume.

In the order (gx^2, 2 gx gy, 2 gx gz, gy^2, 2 gy gz, gz^2) times b, with the factor 2 of the off-diagonal elements included (MRIToolkit’s convention).

Returns:

np.ndarray – (N, 6) in s/mm^2.

property shells: ndarray#

The b-value of each shell (the mean of its volumes), ascending.

Returns:

np.ndarray – (K,) in s/mm^2; empty when every volume is a b0.

count_shells(*, above=0.0)#

The number of distinct shells, as shells groups them, above a b-value.

b-values spread around a shell (995, 1000, 1005, …) count as one shell, and b0s never count.

Parameters:

above (float) – Count only the shells whose b-value is above this, in s/mm^2. Defaults to 0: every shell.

Returns:

int – The number of shells.

Return type:

int

property shell_index: ndarray#

Each volume’s index in shells, or -1 for a b0.

The b-values of the weighted volumes are sorted, and a gap larger than shell_epsilon between neighbours starts a new shell.

Returns:

np.ndarray – (N,) int.

flip(axis)#

Negates one component of every direction, in place.

Corrects a table that is wrong for its data (for example a y sign reversed by the scanner export). Reorienting a volume never needs it.

Parameters:

axis (int) – The world axis to negate: 0 (x), 1 (y) or 2 (z).

Raises:

ValueError – If axis is not 0, 1 or 2.

permute(order)#

Reorders the components of every direction, in place.

New component j is old component order[j]. Like flip, it corrects a wrong table and is never needed for reorienting a volume.

Parameters:

order (tuple[int, int, int]) – A permutation of (0, 1, 2).

Raises:

ValueError – If order is not a permutation of (0, 1, 2).

class larmor.types.Grid(shape, affine)#

The voxel grid an object (Volume, Tractogram) lives on.

Compare grids with matches, not ==: equality on a dataclass holding an array would compare element by element.

shape#

The number of voxels along each spatial axis.

Type:

tuple[int, int, int]

affine#

(4, 4) float64, read-only, voxel indices to world coordinates (RAS+) in mm.

Type:

numpy.ndarray

property orientation: tuple[str, str, str]#

Closest RAS+ direction of each voxel axis, such as (“R”, “A”, “S”).

canonical()#

Returns the same grid with its axes permuted and flipped to RAS.

The voxels are the same in the world; only the order and direction of the axes change.

Returns:

Grid – The grid with RAS axes.

Return type:

Grid

matches(other, *, atol=0.001)#

Checks whether two grids are the same voxels in the world.

Grids that differ only in the order and direction of their axes (for example a volume and the same volume reoriented) match.

Parameters:
  • other (Grid) – The grid to compare against.

  • atol (float) – Tolerance on the affines, in mm. Defaults to 1e-3, because TRK files store their affine in float32.

Returns:

True if other is this grid with its axes permuted and flipped – same shape after the permutation, and affines equal within atol.

Return type:

bool

class larmor.types.Label(name, rgb)#

One entry of a lookup table: a label’s name and colour.

name#

The label’s name.

Type:

str

rgb#

The colour as (red, green, blue), each from 0 to 255.

Type:

tuple[int, int, int]

class larmor.types.Surface(vertices, faces, vertex_data=<factory>, reference=None)#

A triangle mesh in world coordinates, with named values per vertex.

Surfaces compare by identity (== is is); compare the arrays to compare contents.

Parameters:
  • vertices (ndarray) – (V, 3) float32, the vertices in world coordinates (RAS+) in mm. Converted to float32 if needed.

  • faces (ndarray) – (F, 3) uint32, the vertex indices of each triangle, counter-clockwise seen from outside, so normals point out. Converted to uint32 if needed.

  • vertex_data (dict[str, ndarray]) – Named values per vertex, each with first axis V, such as “curv”, “thickness” or label keys. Empty by default.

  • reference (Grid | None) – The voxel grid of the volume the surface was made on, if known, such as the one in a FreeSurfer file’s footer. Defaults to None (unknown).

Raises:

ValueError – If vertices is not (V, 3) or faces is not (F, 3), the faces are not integers or an index is outside [0, V), or a vertex_data value does not have V entries along its first axis.

property num_vertices: int#

The number of vertices, V.

property num_faces: int#

The number of faces, F.

class larmor.types.Tractogram(points, offsets, point_data=<factory>, streamline_data=<factory>, reference=None)#

A set of streamlines, stored as one flat array of points and their offsets.

Streamline s is points[offsets[s]:offsets[s + 1]]. Index a tractogram with an integer to get one streamline’s points, or with a slice, a list or array of indices, or a boolean mask to get a new tractogram with those streamlines. Tractograms compare by identity (== is is); compare the arrays to compare contents.

Parameters:
  • points (ndarray) – (P, 3) float32, all points of all streamlines, in world coordinates (RAS+) in mm. Converted to float32 if needed.

  • offsets (ndarray) – (S + 1,) int64, where each streamline starts; the last entry is P. Converted to int64 if needed.

  • point_data (dict[str, ndarray]) – Named values per point, each with first axis P, such as an FA sampled along the streamlines. Empty by default.

  • streamline_data (dict[str, ndarray]) – Named values per streamline, each with first axis S, such as a length or a cluster label. Empty by default.

  • reference (Grid | None) – The voxel grid of the image the tractogram was made on, if known. Defaults to None (unknown).

Raises:

ValueError – If points is not (P, 3), offsets are not integers that start at 0, never decrease and end at P, or a point_data or streamline_data value does not have P or S entries along its first axis.

property num_streamlines: int#

The number of streamlines, S.

property num_points: int#

The number of points of all streamlines together, P.

subsample(n, *, seed=None)#

Returns a new tractogram with n streamlines chosen at random.

Parameters:
  • n (int) – The number of streamlines to keep, at most S.

  • seed (int | None) – Seed for the random choice. Defaults to None (a different subset each time).

Returns:

Tractogram –

The selected streamlines with their data and the same

reference.

Raises:

ValueError – If n is negative or larger than the number of streamlines.

Return type:

Tractogram

subsample_indices(n, *, seed=None)#

The streamlines subsample keeps for the same n and seed.

Parameters:
  • n (int) – The number of streamlines to keep, at most S.

  • seed (int | None) – Seed for the random choice. Defaults to None (a different subset each time).

Returns:

np.ndarray – (n,) int64, the indices of the kept streamlines, ascending.

Raises:

ValueError – If n is negative or larger than the number of streamlines.

Return type:

ndarray

class larmor.types.Volume(data, affine, slope=1.0, intercept=0.0)#

Volume from an MRI acquisition.

data and affine are read-only. Reorientation replaces them with new arrays instead of writing to them. The affine is copied; the data is not (it can be large), so the caller must not change the array it passed in. The checks run only on construction, so assigning new values to the fields afterwards is not supported. Volumes compare by identity: == is is.

Parameters:
  • data (ndarray) – The stored values, unscaled, as (X, Y, Z) or (X, Y, Z, N). The last axis of a 4D volume is its series (DWI volumes, FOD coefficients).

  • affine (ndarray) – (4, 4) float64, voxel indices to world coordinates (RAS+) in mm. Its last row must be [0, 0, 0, 1].

  • slope (float) – Scaling, value = data * slope + intercept. Defaults to 1.0; 0, NaN or infinity means no scaling, as in nibabel.

  • intercept (float) – Scaling offset. Defaults to 0.0.

Raises:

ValueError – If data is not 3D or 4D, affine is not a finite 4x4 matrix with last row [0, 0, 0, 1] and non-zero axes, or the slope is used but the intercept is not finite.

property voxel_sizes: ndarray#

The voxel size along each voxel axis, as a (3,) array in mm.

property orientation: tuple[str, str, str]#

Closest RAS+ direction of each voxel axis, such as (“R”, “A”, “S”).

property grid: Grid#

the spatial shape (X, Y, Z) and the affine.

Type:

The volume’s voxel grid

as_float(*, dtype=<class 'numpy.float32'>)#

Returns the scaled values, data * slope + intercept, as a float array.

When the data already has dtype and the scaling is trivial, this returns data itself (read-only), without a copy.

Note that the data * slope + intercept operation can cause overflow.

Parameters:

dtype (DTypeLike) – A floating-point type. Defaults to float32.

Returns:

The scaled values, with the shape of data.

Raises:

ValueError – If dtype is not a floating-point type.

Return type:

ndarray

with_data(data)#

Returns a new volume with the same affine, the given data and no scaling.

Parameters:

data (ndarray) – The new values, (X, Y, Z) or (X, Y, Z, N), on the same spatial grid.

Returns:

Volume – The new volume, with slope 1 and intercept 0.

Raises:

ValueError – If the spatial shape of data differs from this volume’s.

Return type:

Volume

flip_axis(axis)#

Reverses a spatial voxel axis in place, keeping every voxel’s world position.

The affine is updated to match, and the data becomes a flipped view (no copy).

Parameters:

axis (int) – The voxel axis to flip: 0, 1 or 2.

Raises:

ValueError – If axis is not 0, 1 or 2.

permute_axes(order)#

Reorders the spatial voxel axes in place, keeping world positions.

The affine is updated to match, and the data becomes a transposed view.

Parameters:

order (tuple[int, int, int]) – A permutation of (0, 1, 2).

Raises:

ValueError – If order is not a permutation of (0, 1, 2).

to_orientation(codes)#

Reorients the volume in place to the given orientation, such as “RAS”.

Only permutes and flips axes (no resampling, no copy of the data), so every voxel keeps its world position.

Parameters:

codes (str | Sequence[str]) – The orientation to reach: one of R/L, A/P and S/I each.

Raises:

ValueError – If codes is not a valid orientation.

to_closest_canonical()#

Reorients the volume in place to its closest RAS orientation.