Skip to content

brainhops.io.base.afni

The shared AFNI-reading and AFNI-writing machinery behind every AFNI image and transformation format.

An AFNI dataset is a pair of files that share a prefix and a view:

  • prefix+view.HEAD, a text header made of attributes;
  • prefix+view.BRIK, the raw voxel values, optionally compressed (.BRIK.gz, .BRIK.bz2).

The view is one of orig (the original, scanner-based coordinates), acpc (AC-PC aligned) and tlrc (Talairach, or any other template).

The conventions below were checked against the AFNI sources (README.attributes, 3ddata.h, mrilib.h, thd_atr.c, thd_writeatr.c, thd_dsetdblk.c, thd_initdblk.c, thd_editdaxes.c, thd_matdaxes.c, thd_dsetatr.c, thd_niftiread.c, thd_niftiwrite.c, thd_compress.h).

Attributes. Each attribute is three lines -- type = <kind>-attribute, name = <NAME>, count = <n> -- followed by its n values. The kind is integer, float or string. The numbers are separated by any white space. A string is n characters that follow a single quote ', in which ~ stands for a NUL character (AFNI writes a ~ of the string itself as *). A string attribute ends with a NUL, and may hold several NUL-separated sub-strings (the sub-brick labels of BRICK_LABS). An attribute with a count of zero is skipped, as AFNI does. A header whose first kilobyte holds <AFNI_ is AFNI's alternative NIML (XML) header, which is not read here.

Shape. DATASET_DIMENSIONS holds the number of voxels along the three axes, nx, ny, nz, and DATASET_RANK[1] the number of sub-bricks (nvals): the volumes of a time series, the statistics of a "bucket", or the components of a warp. The BRIK holds the sub-bricks one after the other, each with x fastest: the data are a Fortran-ordered (nx, ny, nz, nvals) array.

Types and scaling. BRICK_TYPES holds one code per sub-brick (mrilib.h): 0 = uint8, 1 = int16, 2 = int32, 3 = float32, 4 = float64, 5 = complex64 (6 = RGB and 7 = RGBA are not read). It is int16 when absent, and a list shorter than nvals repeats its last code. BYTEORDER_STRING is LSB_FIRST or MSB_FIRST, and the native order when absent. BRICK_FLOAT_FACS holds one factor per sub-brick: a stored value v means v * f, and a factor of zero means no scaling.

Orientation. ORIENT_SPECIFIC holds one code per voxel axis, saying which way it runs: 0 = right-to-left, 1 = left-to-right, 2 = posterior-to-anterior, 3 = anterior-to-posterior, 4 = inferior-to-superior, 5 = superior-to-inferior.

World coordinates. AFNI's world is "DICOM order": x increases to the left, y to the back and z up -- LPS millimetres, which AFNI also calls RAI (R, A and I are negative). ORIGIN[i] is the DICOM coordinate of the centre of voxel 0 along the DICOM axis voxel axis i runs along, and DELTA[i] is the signed voxel size along it, so that the centre of voxel n is at ORIGIN[i] + n * DELTA[i]: DELTA is negative for an axis that runs towards R, A or I. The voxel to DICOM matrix is therefore a signed permutation (THD_daxes_to_mat44): row ORIENT_SPECIFIC[i] // 2, column i, holds DELTA[i], and the same row of the last column holds ORIGIN[i]. This is the cardinal matrix, which AFNI computes from ORIENT_SPECIFIC, ORIGIN and DELTA whenever it reads a header (the IJK_TO_DICOM attribute it writes is the same matrix, and is ignored on reading).

Obliquity. IJK_TO_DICOM_REAL, when present, is the true (possibly oblique) voxel-to-DICOM matrix, as 12 values (three rows of four). AFNI programs compute on the cardinal grid, ignoring obliquity, but AFNI's own NIfTI export (3dAFNItoNIFTI) stores the real matrix (with x and y negated into RAS) as the sform. When a matrix is turned back into ORIENT_SPECIFIC, ORIGIN and DELTA (THD_daxes_from_mat44), each axis gets the closest orientation, its voxel size is the length of its column (signed by the orientation), and its origin is the projection of the translation on the unit column (signed by the orientation).

View. SCENE_DATA[0] is the view: 0 = orig, 1 = acpc, 2 = tlrc. A NIfTI file read by AFNI goes to tlrc when its form names a template (Talairach, MNI, other template), and to orig otherwise.

Time. A time series has TAXIS_NUMS ([ntt, nslices, units], with units 77001 = ms, 77002 = s, 77003 = Hz) and TAXIS_FLOATS ([origin, TR, duration, z origin, z step]).

This module holds what an image reader and a transformation reader (an AFNI warp, for instance) share: the header, the geometry, the decoding of the voxel data and their encoding. Every AFNI format derives from AfniFormat, so that the "afni" hint selects them all.

Attributes

AFNI_VIEWS module-attribute

AFNI_VIEWS: tuple[str, ...] = ('orig', 'acpc', 'tlrc')

The views, by their SCENE_DATA[0] code.

AFNI_ORIENTATIONS module-attribute

AFNI_ORIENTATIONS: tuple[str, ...] = (
    "right-to-left",
    "left-to-right",
    "posterior-to-anterior",
    "anterior-to-posterior",
    "inferior-to-superior",
    "superior-to-inferior",
)

The anatomical orientation of each ORIENT_SPECIFIC code.

DICOM_TO_RAS module-attribute

DICOM_TO_RAS: ndarray = np.diag([-1.0, -1.0, 1.0, 1.0])

The (4, 4) matrix from AFNI's DICOM (LPS) coordinates to RAS. It is its own inverse.

Classes

AfniFormat

A format of the AFNI family, whatever it stores.

It is the shared base of the AFNI image formats (BRIK/HEAD datasets) and transformation formats, and carries the "afni" hint they all answer to. Each format adds its own hints ("brik", ...), which are then also reachable as "afni.brik", ...

AfniHeader magic

AfniHeader(attributes: dict[str, _Value])

Bases: Magic

The attributes of an AFNI .HEAD file.

The attributes are kept in the order of the file, by name: a string attribute as a str (its sub-strings separated by NUL characters), a numeric one as a tuple of int or of float. The properties decode the ones that describe the data and the geometry; the others (HISTORY_NOTE, BRICK_LABS, BRICK_STATAUX, ...) are kept as they are and written back.

Attributes

attributes instance-attribute
attributes: dict[str, _Value]

Every attribute of the header, by name, in the order of the file.

shape property
shape: tuple[int, int, int]

The number of voxels along each axis, (nx, ny, nz).

nvals property
nvals: int

The number of sub-bricks.

brick_types property
brick_types: tuple[int, ...]

The type code of each sub-brick (int16 when absent; a short list repeats its last code).

byteorder property
byteorder: str

The byte order of the BRIK: "<", ">", or "=" (native) when the header does not say.

dtypes property
dtypes: tuple[dtype, ...]

The stored data type of each sub-brick, with its byte order.

nbytes property
nbytes: int

The size of the (uncompressed) BRIK, in bytes.

float_facs property
float_facs: tuple[float, ...]

The scaling factor of each sub-brick; 0 means "not scaled".

labels property
labels: list[str] | None

The label of each sub-brick (BRICK_LABS), or None.

view property
view: str

The view: "orig", "acpc" or "tlrc" (SCENE_DATA[0]); "orig" when the header does not say.

real_matrix property
real_matrix: ndarray | None

The (4, 4) voxel-to-DICOM matrix of IJK_TO_DICOM_REAL, or None when the header has none.

orient property
orient: tuple[int, int, int]

The orientation code of each axis (ORIENT_SPECIFIC).

origin property
origin: tuple[float, float, float]

The DICOM coordinate of the centre of voxel 0 along each axis (ORIGIN).

delta property
delta: tuple[float, float, float]

The signed voxel size along each axis (DELTA).

cardinal_matrix property
cardinal_matrix: ndarray

The (4, 4) cardinal voxel-to-DICOM matrix, from ORIENT_SPECIFIC, ORIGIN and DELTA: the grid AFNI programs compute on.

voxel_to_dicom property
voxel_to_dicom: ndarray

The (4, 4) true voxel-to-DICOM matrix: IJK_TO_DICOM_REAL when the header has one, else the cardinal matrix.

is_oblique property
is_oblique: bool

Whether the true matrix differs from the cardinal one.

taxis property
taxis: tuple[float, str | None] | None

(TR, unit) of a time series, or None when the header has no time axis. The unit is "millisecond", "second", "hertz", or None when unknown.

Methods:

get
get(name: str, default: Any = None) -> Any

The value of an attribute, or default if it is absent.

validate
validate() -> AfniHeader

Check that the header describes a dataset that can be read.

Raises:

Type Description
ParserContentError

If a mandatory attribute is missing or invalid.

from_text classmethod
from_text(text: str) -> AfniHeader

Parse the text of a .HEAD file.

from_bytes classmethod
from_bytes(content: bytes) -> AfniHeader

Parse the bytes of a .HEAD file.

to_text
to_text() -> str

The text of the .HEAD file, as AFNI writes it.

replace
replace(**attributes: _Value | None) -> AfniHeader

A copy with some attributes set, or removed when None.

AfniParser magic

AfniParser(
    _header: AfniHeader | None = None,
    dataobj: Any | None = None,
)

Bases: DataModelBase, AfniFormat, BinaryFileParserWriter

Base class for objects that are encoded by an AFNI dataset (.HEAD + .BRIK).

It reads and writes the container -- the header and the sub-bricks -- for every AFNI dataset-based format: an image, and later a warp. What the values mean is for the concrete format to say, through _from_header when reading, and _afni_header and _afni_data when writing.

Reading from a local path memory-maps an uncompressed BRIK, so nothing but the header is read until the data are indexed. A compressed BRIK is read into memory.

Attributes

header property writable
header: AfniHeader | None

The AFNI header this object was read from, if any.

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.

Methods:

from_file classmethod
from_file(file: FileLike, **kwargs) -> Self

Build the object from an AFNI dataset (path or file object).

from_filename classmethod
from_filename(
    filename: FilenameLike, mmap: bool = True, **kwargs
) -> Self

Build the object from the path of a .HEAD, of a .BRIK (.BRIK.gz, .BRIK.bz2), or of the dataset without extension.

An uncompressed local BRIK is memory-mapped unless mmap is false.

from_fileobj classmethod
from_fileobj(file: BinaryIO, **kwargs) -> Self

Build the object from an open .HEAD (or .BRIK) file object.

The other file of the dataset is found from the stream's name, which it must therefore have.

from_bytes classmethod
from_bytes(content: bytes, **kwargs) -> Self

An AFNI dataset is two files, so bytes alone cannot hold one.

sniff_filename classmethod
sniff_filename(
    filename: FilenameLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Score how confident the class is that a path names an AFNI dataset: its .HEAD is read, whichever of its files is named.

sniff_fileobj classmethod
sniff_fileobj(
    file: IO,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Score how confident the class is that a stream holds an AFNI header.

sniff_bytes classmethod
sniff_bytes(
    content: bytes,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Score how confident the class is that bytes hold an AFNI header.

to_filename
to_filename(filename: FilenameLike, **kwargs) -> None

Write the dataset: its .HEAD and its .BRIK.

The path may name the .HEAD, the .BRIK (.BRIK.gz or .BRIK.bz2 to compress it), or the dataset without extension (out+orig). Another BRIK of the same dataset, compressed differently, is removed (as AFNI does), so that it cannot be read in place of the new one.

to_file
to_file(file: FileLike, **kwargs) -> None

Write to a path; an AFNI dataset cannot be written to a stream.

to_fileobj
to_fileobj(file: IO, **kwargs) -> None

An AFNI dataset is two files, which a stream cannot hold.

to_bytes
to_bytes(**kwargs) -> bytes

An AFNI dataset is two files, which bytes cannot hold.

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 [0, 1].

sniff_file classmethod
sniff_file(
    file: FileLike,
    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 FileLike

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 [0, 1].

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 [0, 1].

sniff_text classmethod
sniff_text(
    text: str,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

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 [0, 1].

sniff_lines classmethod
sniff_lines(
    lines: Iterable[str],
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

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 [0, 1].

sniff_line classmethod
sniff_line(
    line: str,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

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 [0, 1].

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 other is a path to a file that does not exist. It is a FileNotFoundError.

from_spec classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self

Build an object from an unqualified structured source.

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_text classmethod
from_text(text: str, **kwargs) -> Self

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_lines(lines: Iterable[str], **kwargs) -> Self

Build an object from an iterable of lines (e.g., the content of a file).

Parameters:

Name Type Description Default
lines Iterable[str]

The lines to sniff.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

from_line classmethod
from_line(line: str, **kwargs) -> Self

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_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
to_lines(**kwargs) -> Iterator[str]

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
from_dict(other: Mapping, *args, **kwargs) -> Self

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
from_instance(other: Self, *args, **kwargs) -> Self

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
from_other(other: Any, *args, **kwargs) -> Self

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.

Functions:

afni_cardinal_matrix

afni_cardinal_matrix(
    orient: Sequence[int],
    origin: Sequence[float],
    delta: Sequence[float],
) -> ndarray

The (4, 4) cardinal voxel-to-DICOM matrix (THD_daxes_to_mat44).

Voxel axis i runs along DICOM axis orient[i] // 2: that row of column i holds delta[i], and that row of the last column holds origin[i].

Raises:

Type Description
ValueError

If the orientation codes are not valid or do not name three different DICOM axes.

afni_geometry_from_matrix

afni_geometry_from_matrix(
    matrix: ndarray,
) -> tuple[
    tuple[int, int, int],
    tuple[float, float, float],
    tuple[float, float, float],
]

Decompose a voxel-to-DICOM matrix into AFNI's orientation codes, origin and voxel sizes (THD_daxes_from_mat44).

Each voxel axis is given the DICOM axis and direction its column is closest to, among the assignments that give the three axes different DICOM axes. Its voxel size is the length of its column, and its origin is the projection of the translation on the unit column, both negated for an orientation that runs towards R, A or I. A cardinal matrix gives back exactly its ORIGIN and DELTA.

Returns:

Name Type Description
orient (int, int, int)
origin (float, float, float)
delta (float, float, float)

afni_voxel_to_dicom

afni_voxel_to_dicom(xform: Transformation) -> ndarray

The (4, 4) voxel-to-DICOM (LPS) matrix of a voxel-to-world transformation.

The transformation is reduced to an affine (a Scaling, a Sequence of affines, ...), embedded in three dimensions, turned into RAS from the anatomical orientation of its world axes (a world with no orientation is taken to be RAS already, as every format does), and then into DICOM.

Raises:

Type Description
UnrepresentableTransformationError

If the transformation has no affine representation.

WriterError

If it maps more than three spatial dimensions.

afni_world

afni_world(name: str) -> LPSmm

The DICOM (LPS millimetre) world space of an AFNI dataset, named after its view ("orig", "tlrc", ...).

afni_view

afni_view(name: Any) -> str | None

The AFNI view a name stands for, or None.

name may be a view ("tlrc"), the name of a world space ("talairach" and "mni" mean tlrc, "orig-cardinal" means orig), or a dataset file name ("anat+tlrc.HEAD").

brick_dtype

brick_dtype(dtype: Any) -> dtype

The AFNI data type that stores an array of type dtype (without byte order), or the one named ("byte", "short", "int", "float", "double", "complex").

A type AFNI has is kept. Booleans become bytes, int8 shorts, uint16 and uint32 ints, wider integers doubles, float16 floats and complex128 complex (single precision).

brick_code

brick_code(dtype: Any) -> int

The BRICK_TYPES code of an AFNI data type.

decode_bricks

decode_bricks(header: AfniHeader, buffer: Any) -> ndarray

Decode the BRIK into a (nx, ny, nz, nvals) array.

buffer holds the (uncompressed) BRIK: bytes, a memoryview or a one-dimensional uint8 array (a memory map). The result is a Fortran-ordered view of it when every sub-brick has the same type; sub-bricks of different types are converted to a common type and copied. Scaling (BRICK_FLOAT_FACS) is not applied.

scale_bricks

scale_bricks(header: AfniHeader, stored: Any) -> Any

Apply the BRICK_FLOAT_FACS of the header to the stored values (whose last axis holds the sub-bricks, unless there is only one).

Without a factor, the stored values are returned as they are, so a memory map stays one. With one, they are read and scaled, to at least single precision.

encode_bricks

encode_bricks(
    header: AfniHeader, data: Any
) -> Iterator[bytes]

Encode a (nx, ny, nz, nvals) array (or (nx, ny, nz) for a single sub-brick) into the bytes of the BRIK, one sub-brick at a time.

The values are divided by the header's BRICK_FLOAT_FACS (where not zero) and converted to its types and byte order, rounding when a floating-point array is stored as integers.

Raises:

Type Description
WriterError

If the shape disagrees with the header, or integers do not fit the stored type.

afni_dataset_files

afni_dataset_files(
    filename: FilenameLike,
) -> tuple[Any, Any, str]

The .HEAD and .BRIK files of the dataset a path names.

The path may be that of the .HEAD, of the .BRIK (compressed or not), or the dataset's name without extension (anat+orig). The BRIK is the first one found among .BRIK, .BRIK.gz, .BRIK.bz2, .BRIK.Z (AFNI's own order), or the uncompressed name if none exists.

Returns:

Name Type Description
head Path

The .HEAD file.

brik Path

The .BRIK file (which may not exist).

stem str

The dataset's name, without directory nor extension.