# trackvis¶

Read and write trackvis files (old interface)

See nibabel.streamlines for the new interface.

We will deprecate this, the old interface, in some future release.

 DataError Error in trackvis data HeaderError Error in trackvis header TrackvisFile(streamlines[, mapping, …]) Convenience class to encapsulate trackvis file information TrackvisFileError Error from TrackvisFile class aff_from_hdr(trk_hdr[, atleast_v2]) Return voxel to mm affine from trackvis header aff_to_hdr(affine, trk_hdr[, pos_vox, set_order]) Set affine affine into trackvis header trk_hdr empty_header([endianness, version]) Empty trackvis header read(fileobj[, as_generator, points_space, …]) Read trackvis file from fileobj, return streamlines, header write(fileobj, streamlines[, hdr_mapping, …]) Write header and streamlines to trackvis file fileobj

## DataError¶

class nibabel.trackvis.DataError

Bases: Exception

Error in trackvis data

__init__($self, /, *args, **kwargs) Initialize self. See help(type(self)) for accurate signature. ## HeaderError¶ class nibabel.trackvis.HeaderError Bases: Exception Error in trackvis header __init__($self, /, *args, **kwargs)

Initialize self. See help(type(self)) for accurate signature.

## TrackvisFile¶

class nibabel.trackvis.TrackvisFile(streamlines, mapping=None, endianness=None, filename=None, points_space=None, affine=None)

Bases: object

Convenience class to encapsulate trackvis file information

Parameters
streamlinessequence

sequence of streamlines. This object does not accept generic iterables as input because these can be consumed and make the object unusable. Please use the function interface to work with generators / iterables

mappingNone or mapping

endianness{None, ‘<’, ‘>’}

Set here explicit endianness if required. Endianness otherwise inferred from streamlines

filenameNone or str, optional

filename

points_space{None, ‘voxel’, ‘rasmm’}, optional

Space in which streamline points are expressed in memory. Default (None) means streamlines contain points in trackvis voxmm space (voxel positions * voxel sizes). ‘voxel’ means points are in voxel space (and need to be multiplied by voxel size for saving in file). ‘rasmm’ mean the points are expressed in mm space according to the affine. See read and write function docstrings for more detail.

affineNone or (4,4) ndarray, optional

Affine expressing relationship of voxels in an image to mm in RAS mm space. If ‘points_space’ is not None, you can use this to give the relationship between voxels, rasmm and voxmm space (above).

• deprecated from version: 2.5.0

• Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 4.0.0

__init__(streamlines, mapping=None, endianness=None, filename=None, points_space=None, affine=None)

• deprecated from version: 2.5.0

• Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 4.0.0

classmethod from_file(file_like, points_space=None)
get_affine(atleast_v2=True)

Get affine from header in object

Returns
aff(4,4) ndarray

atleast_v2None or bool, optional

See aff_from_hdr docstring for detail. If True, require valid affine in vox_to_ras field of header.

Notes

This method currently works for trackvis version 1 headers, but we consider it unsafe for version 1 headers, and in future versions of nibabel we will raise an error for trackvis headers < version 2.

set_affine(affine, pos_vox=True, set_order=True)

Set affine affine into trackvis header

Affine is mapping from voxel space to Nifti RAS) output coordinate system convention; x: Left -> Right, y: Posterior -> Anterior, z: Inferior -> Superior. Sets affine if possible, and voxel sizes, and voxel axis ordering.

Parameters
affine(4,4) array-like

Affine voxel to mm transformation

pos_vosNone or bool, optional

If None, currently defaults to False - this will change in future versions of nibabel. If False, allow negative voxel sizes in header to record axis flips. Negative voxels cause problems for trackvis (the application). If True, enforce positive voxel sizes.

set_orderNone or bool, optional

If None, currently defaults to False - this will change in future versions of nibabel. If False, do not set voxel_order field in trk_hdr. If True, calculcate voxel_order from affine and set into trk_hdr.

Returns
None
to_file(file_like)

## TrackvisFileError¶

class nibabel.trackvis.TrackvisFileError

Bases: Exception

Error from TrackvisFile class

__init__(\$self, /, *args, **kwargs)

Initialize self. See help(type(self)) for accurate signature.

## aff_from_hdr¶

nibabel.trackvis.aff_from_hdr(trk_hdr, atleast_v2=True)

Return voxel to mm affine from trackvis header

• deprecated from version: 2.5.0

• Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 4.0.0

Affine is mapping from voxel space to Nifti (RAS) output coordinate system convention; x: Left -> Right, y: Posterior -> Anterior, z: Inferior -> Superior.

Parameters
trk_hdrmapping

Mapping with trackvis header keys version. If version == 2, we also expect vox_to_ras.

atleast_v2None or bool

If None, currently defaults to False. This will change to True in future versions. If True, require that there is a valid ‘vox_to_ras’ affine, raise HeaderError otherwise. If False, look for valid ‘vox_to_ras’ affine, but fall back to best guess from version 1 fields otherwise.

Returns
aff(4,4) array

affine giving mapping from voxel coordinates (affine applied on the left to points on the right) to millimeter coordinates in the RAS coordinate system

Notes

Our initial idea was to try and work round the deficiencies of the version 1 format by using the DICOM orientation fields to store the affine. This proved difficult in practice because trackvis (the application) doesn’t allow negative voxel sizes (needed for recording axis flips) and sets the origin field to 0. In future, we’ll raise an error rather than try and estimate the affine from version 1 fields

## aff_to_hdr¶

nibabel.trackvis.aff_to_hdr(affine, trk_hdr, pos_vox=True, set_order=True)

Set affine affine into trackvis header trk_hdr

• deprecated from version: 2.5.0

• Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 4.0.0

Affine is mapping from voxel space to Nifti RAS) output coordinate system convention; x: Left -> Right, y: Posterior -> Anterior, z: Inferior -> Superior. Sets affine if possible, and voxel sizes, and voxel axis ordering.

Parameters
affine(4,4) array-like

Affine voxel to mm transformation

trk_hdrmapping

Mapping implementing __setitem__

pos_vosNone or bool

If None, currently defaults to False - this will change in future versions of nibabel. If False, allow negative voxel sizes in header to record axis flips. Negative voxels cause problems for trackvis (the application). If True, enforce positive voxel sizes.

set_orderNone or bool

If None, currently defaults to False - this will change in future versions of nibabel. If False, do not set voxel_order field in trk_hdr. If True, calculcate voxel_order from affine and set into trk_hdr.

Returns
None

Notes

version 2 of the trackvis header has a dedicated field for the nifti RAS affine. In theory trackvis 1 has enough information to store an affine, with the fields ‘origin’, ‘voxel_size’ and ‘image_orientation_patient’. Unfortunately, to be able to store any affine, we’d need to be able to set negative voxel sizes, to encode axis flips. This is because ‘image_orientation_patient’ is only two columns of the 3x3 rotation matrix, and we need to know the number of flips to reconstruct the third column reliably. It turns out that negative flips upset trackvis (the application). The application also ignores the origin field, and may not use the ‘image_orientation_patient’ field.

nibabel.trackvis.empty_header(endianness=None, version=2)

• deprecated from version: 2.5.0

• Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 4.0.0

Parameters
endianness{‘<’,’>’}, optional

Endianness of empty header to return. Default is native endian.

versionint, optional

Header version. 1 or 2. Default is 2

Returns
hdrstructured array

structured array containing empty trackvis header

Notes

The trackvis header can store enough information to give an affine mapping between voxel and world space. Often this information is missing. We make no attempt to fill it with sensible defaults on the basis that, if the information is missing, it is better to be explicit.

Examples

>>> hdr = empty_header()
>>> print(hdr['version'])
2
>>> hdr['id_string'].item() == b'TRACK'
True
>>> endian_codes[hdr['version'].dtype.byteorder] == native_code
True
>>> endian_codes[hdr['version'].dtype.byteorder] == swapped_code
True
>>> print(hdr['version'])
1


nibabel.trackvis.read(fileobj, as_generator=False, points_space=None, strict=True)

• deprecated from version: 2.5.0

• Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 4.0.0

Parameters
fileobjstring or file-like object

If string, a filename; otherwise an open file-like object pointing to trackvis file (and ready to read from the beginning of the trackvis header data)

as_generatorbool, optional

Whether to return tracks as sequence (False, default) or as a generator (True).

points_space{None, ‘voxel’, ‘rasmm’}, optional

The coordinates in which you want the points in the output streamlines expressed. If None, then return the points exactly as they are stored in the trackvis file. The points will probably be in trackvis voxmm space - see Notes for write function. If ‘voxel’, we convert the points to voxel space simply by dividing by the recorded voxel size. If ‘rasmm’ we’ll convert the points to RAS mm space (real space). For ‘rasmm’ we check if the affine is set and matches the voxel sizes and voxel order.

strict{True, False}, optional

If True, raise error on read for badly-formed file. If False, let pass files with last track having too few points.

Returns
streamlinessequence or generator

Returns sequence if as_generator is False, generator if True. Value is sequence or generator of 3 element sequences with elements:

1. points : ndarray shape (N,3) where N is the number of points

2. scalars : None or ndarray shape (N, M) where M is the number of scalars per point

3. properties : None or ndarray shape (P,) where P is the number of properties

hdrstructured array

structured array with trackvis header fields

Notes

The endianness of the input data can be deduced from the endianness of the returned hdr or streamlines

Points are in trackvis voxel mm. Each track has N points, each with 3 coordinates, x, y, z, where x is the floating point voxel coordinate along the first image axis, multiplied by the voxel size for that axis.

## write¶

nibabel.trackvis.write(fileobj, streamlines, hdr_mapping=None, endianness=None, points_space=None)

Write header and streamlines to trackvis file fileobj

• deprecated from version: 2.5.0

• Will raise <class ‘nibabel.deprecator.ExpiredDeprecationError’> as of version: 4.0.0

The parameters from the streamlines override conflicting parameters in the hdr_mapping information. In particular, the number of streamlines, the number of scalars, and the number of properties are written according to streamlines rather than hdr_mapping.

Parameters
fileobjfilename or file-like

If filename, open file as ‘wb’, otherwise fileobj should be an open file-like object, with a write method.

streamlinesiterable

iterable returning 3 element sequences with elements:

1. points : ndarray shape (N,3) where N is the number of points

2. scalars : None or ndarray shape (N, M) where M is the number of scalars per point

3. properties : None or ndarray shape (P,) where P is the number of properties

If streamlines has a len (for example, it is a list or a tuple), then we can write the number of streamlines into the header. Otherwise we write 0 for the number of streamlines (a valid trackvis header) and write streamlines into the file until the iterable is exhausted. M - the number of scalars - has to be the same for each streamline in streamlines. Similarly for P. See points_space and Notes for more detail on the coordinate system for points above.

hdr_mappingNone, ndarray or mapping, optional

Information for filling header fields. Can be something dict-like (implementing items) or a structured numpy array

endianness{None, ‘<’, ‘>’}, optional

Endianness of file to be written. ‘<’ is little-endian, ‘>’ is big-endian. None (the default) is to use the endianness of the streamlines data.

points_space{None, ‘voxel’, ‘rasmm’}, optional

The coordinates in which the points in the input streamlines are expressed. If None, then assume the points are as you want them (probably trackvis voxmm space - see Notes). If ‘voxel’, the points are in voxel space, and we will transform them to trackvis voxmm space. If ‘rasmm’ the points are in RAS mm space (real space). We transform them to trackvis voxmm space. If ‘voxel’ or ‘rasmm’ we insist that the voxel sizes and ordering are set to non-default values. If ‘rasmm’ we also check if the affine is set and matches the voxel sizes

Returns
None

Notes

Trackvis (the application) expects the points in the streamlines be in what we call trackvis voxmm coordinates. If we have a point (x, y, z) in voxmm coordinates, and voxel_size has the voxel sizes for each of the 3 dimensions, then x, y, z refer to mm in voxel space. Thus if i, j, k is a point in voxel coordinates, then x = i * voxel_size[0]; y = j * voxel_size[1]; z = k * voxel_size[2]. The spatial direction of x, y and z are defined with the “voxel_order” field. For example, if the original image had RAS voxel ordering then “voxel_order” would be “RAS”. RAS here refers to the spatial direction of the voxel axes: “R” means that moving along first voxel axis moves from left to right in space, “A” -> second axis goes from posterior to anterior, “S” -> inferior to superior. If “voxel_order” is empty we assume “LPS”.

This information comes from some helpful replies on the trackvis forum about interpreting point coordiantes

Examples

>>> from io import BytesIO
>>> file_obj = BytesIO()
>>> pts0 = np.random.uniform(size=(10,3))
>>> pts1 = np.random.uniform(size=(10,3))
>>> streamlines = ([(pts0, None, None), (pts1, None, None)])
>>> write(file_obj, streamlines)
>>> _ = file_obj.seek(0) # returns 0 in python 3
>>> len(streams)
2


If there are too many streamlines to fit in memory, you can pass an iterable thing instead of a list

>>> file_obj = BytesIO()
>>> def gen():
...     yield (pts0, None, None)
...     yield (pts0, None, None)
>>> write(file_obj, gen())
>>> _ = file_obj.seek(0)