brainhops.io.base.nrrd
The shared NRRD-reading and NRRD-writing machinery behind every NRRD-based format.
A NRRD ("Nearly Raw Raster Data") file is a text header followed by the
sample values. The header and the values are either in the same file
(attached, .nrrd) or the header names the file(s) that hold them
(detached, .nhdr with its .raw, .raw.gz, ...).
NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: short
dimension: 4
space: left-posterior-superior
sizes: 3 64 64 32
space directions: none (2,0,0) (0,2,0) (0,0,2.5)
kinds: vector domain domain domain
endian: little
encoding: gzip
space origin: (-63,-63,-40)
measurement frame: (1,0,0) (0,1,0) (0,0,1)
DWMRI_b-value:=1000
<data>
The conventions below follow the format specification (https://teem.sourceforge.net/nrrd/format.html).
- Magic. The first line is
NRRD000X, withXthe version (1-5). - Lines.
field: valuelines (the field names are matched without regard to case, and the spellings without a space --datafile,byteskip,axismins,centerings, ... -- are accepted),key:=valuepairs (\nand\\are escapes in both), and#comments. The header ends at the first empty line, after which an attached header's data start; a detached header may also end at the end of its file. - Types. Every spelling of the specification (
short,int16,int16_t,signed short int, ...) of the signed and unsigned 8 to 64 bit integers,floatanddouble.blockis not supported. - Encodings.
raw,ascii(txt,text),hex,gzip(gz) andbzip2(bz2).endianis required for multi-byte types in a binary encoding. - Data files.
data file: <name>, relative to the header's directory unless absolute;data file: <format> <min> <max> <step> [<subdim>], aprintfpattern expanded over the inclusive range; anddata file: LIST [<subdim>], followed by one file name per line until the end of the header. Several files are read in order and concatenated, each holding as many samples. - Skips.
line skiplines are skipped first, in the file as stored.byte skipbytes are then skipped -- after decompression forgzipandbzip2(aspynrrdand teem do) -- andbyte skip: -1means that the data are the last bytes of the (decompressed) file.
Reading an attached raw file, or a detached one with a single raw data
file, from a local path memory-maps the values, so nothing but the header
is read until they are indexed.
Why not pynrrd
NRRD headers are simple text, and pynrrd covers fewer of them than
this parser does: it reads neither the LIST nor the pattern forms
of data file, nor the hex encoding, and always reads the values
into memory. A dedicated parser keeps the dependencies to numpy and
the standard library (gzip, bz2).
Attributes
NRRD_MAGIC
module-attribute
The first seven bytes of every NRRD file; a version digit follows.
SPACES
module-attribute
SPACES = {
"right-anterior-superior": ("RAS", 3),
"left-anterior-superior": ("LAS", 3),
"left-posterior-superior": ("LPS", 3),
"right-anterior-superior-time": ("RAST", 4),
"left-anterior-superior-time": ("LAST", 4),
"left-posterior-superior-time": ("LPST", 4),
"scanner-xyz": ("scanner-xyz", 3),
"scanner-xyz-time": ("scanner-xyz-time", 4),
"3d-right-handed": ("3D-right-handed", 3),
"3d-left-handed": ("3D-left-handed", 3),
"3d-right-handed-time": ("3D-right-handed-time", 4),
"3d-left-handed-time": ("3D-left-handed-time", 4),
}
Each space of the specification: its abbreviation and dimension.
Classes
NrrdHeader
magic
NrrdHeader(
version: int = 5,
fields: dict[str, str] = Factory(dict),
keyvalue: dict[str, str] = Factory(dict),
data_files: tuple[str, ...] = (),
)
Bases: Magic
A NRRD header: its fields and key/value pairs, as written.
The fields are kept as text, under their canonical names ("data
file", "space directions", ...), so that every one of them is
written back as it was read. The methods decode the ones that the
readers need.
Attributes
version
class-attribute
instance-attribute
version: int = 5
The version of the magic line (NRRD000X).
fields
class-attribute
instance-attribute
The fields, by canonical name, as text, in the order they were
read. The file names of a data file: LIST are in data_files.
keyvalue
class-attribute
instance-attribute
The key:=value pairs, unescaped.
data_files
class-attribute
instance-attribute
data_files: tuple[str, ...] = ()
The data files of a detached header, in order (the LIST and
pattern forms expanded); empty for an attached header.
space
property
space: str | None
The canonical space ("left-posterior-superior", ...), or
None when the header has none.
space_dimension
property
space_dimension: int | None
The dimension of the world space, from space or space
dimension; None when the header has neither.
space_directions
property
One vector per axis (None for a non-spatial axis), or None
when the header has no space directions.
space_origin
property
The position of the centre of the first sample, or None.
measurement_frame
property
The measurement frame, one vector per column, or None.
space_units
property
space_units: list[str | None]
The unit of each world axis (None when not given).
Methods:
from_lines
classmethod
from_lines(
lines: Iterable[str], version: int = 5
) -> NrrdHeader
Parse the lines of a header, after its magic line and up to the empty line that ends it.
from_fileobj
classmethod
from_fileobj(file: BinaryIO) -> tuple[NrrdHeader, int]
Read a header from a binary stream, from its magic line.
Returns the header and the offset, relative to the start of the stream, of the first byte after the header (where attached data start).
to_text
to_text() -> str
The text of the header, from its magic line, without the empty line that separates it from attached data.
NrrdParser
magic
NrrdParser(
_header: NrrdHeader | None = None,
dataobj: Any | None = None,
)
Bases: DataModelBase, BinaryFileParserWriter
Base class for objects that are encoded by a NRRD file.
It reads and writes the container -- the header and the sample
values -- for every NRRD-based format. What the values mean is for
the concrete format to say, through _nrrd_header and _nrrd_data
when writing.
Reading a raw file from a local path memory-maps the values, so
nothing but the header is read until they are indexed.
Attributes
header
property
writable
header: NrrdHeader | None
The NRRD 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
Build the object from a NRRD file (path or file object).
from_filename
classmethod
from_filename(
filename: FilenameLike, mmap: bool = True, **kwargs
) -> Self
Build the object from the path of a .nrrd or .nhdr file.
The values of a raw local data file are memory-mapped unless
mmap is false. Detached data files are found relative to the
header's directory.
from_fileobj
classmethod
Build the object from an open NRRD file object.
Detached data files are resolved against the stream's name,
when it has one.
from_bytes
classmethod
Build the object from the bytes of an attached NRRD file.
sniff_fileobj
classmethod
Score how confident the class is that a stream holds a NRRD file of its own kind.
sniff_bytes
classmethod
Score how confident the class is that bytes hold a NRRD file of its own kind.
to_filename
to_filename(
filename: FilenameLike,
data_file: str | None = None,
**kwargs,
) -> None
Write to a path: an attached file, or, for a .nhdr name (or when
data_file is given), a detached header and its data file.
The data file of a detached header is named after it, with an
extension that says its encoding (.raw, .raw.gz, .raw.bz2,
.txt, .hex), unless data_file names it (relative to the
header's directory).
to_file
to_file(file: FileLike, **kwargs) -> None
Write to a path (variant chosen by extension) or a stream.
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
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 |
sniff_filename
classmethod
sniff_filename(
filename: FilenameLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given filename is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
FilenameLike
|
The filename to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the filename cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the filename is of this type, in |
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_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_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
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_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 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.
Functions:
nrrd_dtype
The numpy type of a NRRD type, in the byte order of endian
("little" or "big"; the native order when it is not given).
Raises:
| Type | Description |
|---|---|
ParserContentError
|
If the type is unknown, or is |
dtype_to_nrrd
The NRRD type of a numpy type (or of a NRRD type name).
Booleans are stored as uint8 and half floats as float.
Raises:
| Type | Description |
|---|---|
WriterError
|
If NRRD has no type for it (complex numbers, strings, ...). |
read_data
read_data(
header: NrrdHeader,
file: Any,
offset: int,
mmap: bool = True,
) -> ndarray
The values of a NRRD image, as an array of shape sizes in F order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
header
|
NrrdHeader
|
The header. |
required |
file
|
path | bytes
|
The header file (path) or its content (bytes), used when the data are attached, and to find detached data files. |
required |
offset
|
int
|
The offset of the first byte after the header. |
required |
mmap
|
bool
|
Memory-map a single uncompressed local data file. |
True
|
encode_data
encode_data(header: NrrdHeader, data: Any) -> bytes
Encode an array of shape sizes (indexed in NRRD axis order) into the
bytes of the data file, in the header's type, byte order and encoding.