Skip to content

brainhops.datamodel.systems

Coordinate systems, from unitless arrays to anatomical spaces.

Calling CoordinateSystem builds the most specific system its axes describe -- the dispatch is bagof's polymorphism, driven by the on= constraint of each class:

The axes are... ...so the system is
two or three of anything CoordinateSystem2D/3D
all spatial SpatialCoordinateSystem*
two or three, all measured in samples ArrayCoordinateSystem*
spatial and measured in samples Pixel/VoxelCoordinate…
oriented right, anterior, superior (in order) RASCoordinateSystem
... and in millimetres RASmm

and likewise for LPS and RSA. A class that inherits from two dispatch targets -- SpatialCoordinateSystem3D from CoordinateSystem3D and SpatialCoordinateSystem -- is selected on what both stand for, with no constraint of its own.

The memory order of an array is not written on its axes, so the C- and F-ordered variants are selected on order ("C", "F", or None when it is not specified), together with the axes:

order=, and the axes are... ...so the system is
"C" / "F", anything C/FArrayCoordinateSystem
... two or three C/FArrayCoordinateSystem2D/3D
... two, spatial C/FPixelCoordinateSystem
... three, spatial C/FVoxelCoordinateSystem
"F", oriented R, A, S FRASCoordinateSystem
"C", oriented S, A, R (a C-ordered CRASCoordinateSystem
grid lists its axes z, y, x)

order is a field of every system, so every class can be called with it and pass it on: CoordinateSystem(axes=<RAS axes>, order="F") builds an FRASCoordinateSystem, and so do ArrayCoordinateSystem, FArrayCoordinateSystem and FVoxelCoordinateSystem called the same way. Only an array system has an order, so a system the axes and the order do not make one of (RASmm(order="F")) refuses it.

Every row of the table says something about all the axes, so only a closed system is dispatched. An open system -- one whose axes hold ... (AxisList) -- does not know all its axes, so it is built as the class it was called as: CoordinateSystem(axes=[x, ...]) is not two-dimensional, and CoordinateSystem(axes=[R(), A(), S(), ...]) is not an RASCoordinateSystem. CoordinateSystem.expand closes it, and the closed system is dispatched like any other.

Classes

AxisSequence

Bases: Sequence[AXIS]

The axes of a coordinate system, which may leave some unknown.

An AxisSequence is a sequence of Axis that may hold one ... (Ellipsis), anywhere in it. ... stands for zero or more axes about which nothing is known.

  • A sequence that holds ... is open: its number of axes is unknown.
  • A sequence without it is closed: it lists every axis.
  • ... is an entry of the sequence, but never counts as an axis.
  • A sequence that holds ... more than once describes no axes: every method that reads the axes raises a ValueError on it. A coordinate system refuses such a sequence when it is built.

[..., TimeAxis()] says that the last axis is time, and nothing about the others. [Axis(name="x"), ...] says that the first axis is x. [...] says nothing at all.

This is the read-only base of two containers, which share all of its API, and whose methods that build a new sequence (a slice, expand, restrict, embed) build one of their own type:

  • AxisList, a list, is mutable. A coordinate system whose number of axes is not fixed by its class stores its axes as one.
  • AxisTuple, a tuple, is immutable. A coordinate system with a fixed number of axes, such as an RASCoordinateSystem, stores its axes as one.

Entries and axes

len(), iteration, equality, repr, [i] (an integer or a slice) and index are about the entries of the sequence, ... included, as in the list or tuple it is.

ndim counts the axes the sequence describes, and at, expand, restrict, embed and compatible_with place them in the space, where ... stands for as many axes as needed. A position in the space is counted from the first axis when it is non-negative, and from the last one when it is negative.

In a closed sequence, the entries are the axes, in order. In an open one, they are not: in [x, ..., t], entry 2 (axes[2]) is t, which is the last axis, and the axis at position 2 (axes.at(2)) is one of the axes that ... stands for, which has no entry. So for i in range(len(axes)): axes[i] walks the entries, not the axes.

Finding an axis

index finds the first entry that matches a query, as list.index finds the first entry equal to a value. The query is an Axis, or a name, which stands for Axis(name=...). An entry matches when it is an instance of the class of the query, and has every field that the query sets (not None), with the same value. The fields that the query leaves unset are not compared. So:

  • axes.index("t") finds the first axis named "t";
  • axes.index(TimeAxis()) finds the first time axis, whatever its unit: a TimeAxis() sets its type, and leaves its unit unspecified;
  • axes.index(Axis()) finds the first axis;
  • ... matches nothing. An unknown Axis() matches no query that sets a field, so neither does any of the axes that ... stands for.

Names

An axis can also be read by its name, as in a dict: axes["t"] is the explicit axis named "t", "t" in axes says whether there is one, and names lists the names. A name only ever matches an explicit axis, never one of the axes that ... stands for. axes["t"] is axes[axes.index("t")], but it also refuses a name that more than one axis has.

There is no keys(), values(), items(), update() or pop() by name: an axis may be unnamed, a name may be shared, and ... has no name, so a mapping view would misrepresent the sequence, and changing an axis by its name would be a trap.

Example

>>> x, t = Axis(name="x"), TimeAxis(name="t")
>>> axes = AxisList([x, ..., t])
>>> axes.ndim is None, axes.is_open
(True, True)
>>> axes.index("t"), axes.index(TimeAxis()), axes["t"] is t
(2, 2, True)
>>> "x" in axes, axes.names
(True, ('x', Ellipsis, 't'))
>>> axes[2] is t, axes.at(2), axes.at(-1) is t
(True, Axis(), True)
>>> axes.expand(4)[1:]
[Axis(), Axis(), TimeAxis(name='t')]
>>> axes.restrict([-1, 0, 1])[1:]
[Axis(name='x'), Axis()]

The type parameter is the type of the items: AxisSequence[Union[Axis, EllipsisType]] may be open, and AxisSequence[Axis] is closed.

Attributes

names property
names: tuple[str | None | _Ellipsis, ...]

The name of each entry: None for an unnamed axis, and ... in the place of ....

Example

>>> AxisList([Axis(name="x"), Axis(), ...]).names
('x', None, Ellipsis)
ndim property
ndim: int | None

The number of axes, or None when the list is open.

A closed list has one axis per entry. An open list has an unknown number of axes.

Example

>>> AxisList([Axis(), Axis()]).ndim
2
>>> AxisList([Axis(), ...]).ndim is None
True
is_open property
is_open: bool

Whether the list holds ..., so that its number of axes is unknown.

AxisList([...]), which says nothing at all, is open. The empty list is closed: it has no axis.

Methods:

__getitem__
__getitem__(key: SupportsIndex) -> AXIS
__getitem__(key: slice) -> Self
__getitem__(key: str) -> Axis

An entry (int), some entries (slice), or the axis with a name (str).

An integer or a slice indexes the entries of the sequence, as in any list or tuple, and a slice gives a sequence of the same type. A name gives the one explicit axis that has it. The axis at a position in the space is at that position.

Example

>>> x, t = Axis(name="x"), TimeAxis(name="t")
>>> AxisList([x, ..., t])["t"] is t
True
>>> AxisList([x, ..., t])[2] is t
True

Raises:

Type Description
KeyError

If no explicit axis has the name.

ValueError

If more than one explicit axis has the name.

(IndexError, TypeError)

As list indexing does.

__contains__
__contains__(item: object) -> bool

Whether an explicit axis has a name (str), or whether an entry equals item (anything else, as in any list).

index
index(
    query: Axis | str,
    start: SupportsIndex = 0,
    stop: SupportsIndex = maxsize,
) -> int

The first entry that matches an axis, or a name.

This is list.index, with a looser test than equality: an entry matches the query when it is an instance of the class of the query, and has every field that the query sets (not None), with the same value. The fields that the query leaves unset are not compared. A name stands for Axis(name=...), so it matches the axes with that name, whatever their class. ... matches nothing.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis(name="t", unit="s")
>>> axes = AxisList([x, ..., t])
>>> axes.index("t"), axes.index(SpaceAxis())
(2, 0)
>>> axes.index(Axis(unit="second")), axes.index(Axis())
(2, 0)
>>> axes.index("y")
Traceback (most recent call last):
  ...
ValueError: Axis(name='y') is not in list

Parameters:

Name Type Description Default
query Axis or str

The axis to find, or its name.

required
start int

Only the entries start to stop are searched, as in list.index.

0
stop int

Only the entries start to stop are searched, as in list.index.

0

Returns:

Type Description
int

The index of the first entry that matches. It is an entry index, which is a position in the space only in a closed list (see the class notes).

Raises:

Type Description
ValueError

If no entry matches.

TypeError

If query is neither an Axis nor a string.

expand
expand(ndim: int) -> Self

The closed list of ndim axes that this list describes.

In an open list, ... is replaced with as many unknown Axis() as needed to reach ndim axes. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> AxisList([Axis(name="x"), ...]).expand(3)
[Axis(name='x'), Axis(), Axis()]
>>> AxisList([...]).expand(2)
[Axis(), Axis()]

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
AxisList

A new, closed list of ndim axes. A closed list is returned as a copy of itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open list, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> Self

The axes at some positions, or with some names, of this list.

A reference is the position of an axis in the space (int), or the name of an explicit axis (str), as axes[name] reads it.

  • In a closed list of n axes, a position lies in [-n, n).
  • In an open list, every position is valid, because ... stands for any number of axes. A non-negative position reads the explicit axes before ..., and a negative one the explicit axes after it. Any other position falls among the axes that ... stands for, and gives an unknown Axis().

The axes are listed in the order of refs.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> AxisList([x, y, z]).restrict(["z", 0])
[Axis(name='z'), Axis(name='x')]
>>> AxisList([x, ...]).restrict([0, 1])
[Axis(name='x'), Axis()]

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
AxisList

A new, closed list of len(refs) axes.

Raises:

Type Description
IndexError

If a position lies outside a closed list.

KeyError

If no explicit axis has a name.

ValueError

If more than one explicit axis has a name, or if two references name the same axis.

TypeError

If a reference is neither an integer nor a string, or if refs is a string rather than a list of references.

embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> Self

The axes of a larger space in which this list's axes sit.

This is the inverse of restrict: axis j of this list sits at positions[j] of the result, and every other position holds an unknown Axis(). An open list is first closed to len(positions) axes, as by expand.

The positions are absolute positions in the larger space, which does not exist yet, so they cannot be names.

Example

>>> x = Axis(name="x")
>>> AxisList([x]).embed([1])
[Axis(), Axis(name='x'), Ellipsis]
>>> AxisList([x]).embed([1], ndim=3)
[Axis(), Axis(name='x'), Axis()]

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
AxisList

A new list, closed when ndim is given and open otherwise.

Raises:

Type Description
ValueError

If a position is negative or repeated, if ndim does not exceed every position, or if this list cannot be closed to len(positions) axes.

TypeError

If a position or ndim is not an integer.

compatible_with
compatible_with(other: Sequence[Any]) -> bool

Whether self and other could describe the same axes.

Two lists are compatible when some choice of the axes that each ... stands for makes them match axis by axis, each pair being compatible.

For two closed lists, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis, and [...] matches every list. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> AxisList([x, ...]).compatible_with([x, Axis(), t])
True
>>> AxisList([..., t]).compatible_with([x])
False

Parameters:

Name Type Description Default
other AxisSequence, or list or tuple of Axis

The axes to compare with. A plain list or tuple is read as an axis sequence.

required

Returns:

Type Description
bool

Whether the two lists could describe the same axes.

Raises:

Type Description
TypeError

If other is not a list or a tuple.

at
at(position: int) -> Axis

The axis at a position in the space.

Where axes[i] reads entry i of the sequence, axes.at(i) reads the axis at position i of the space it describes: counted from the first axis when i is non-negative, and from the last one when it is negative.

  • In a closed sequence, the two are the same, and a position lies in [-ndim, ndim).
  • In an open sequence, every position is valid, because ... stands for any number of axes. A non-negative position reads the explicit axes before ..., and a negative one the explicit axes after it. Any other position falls among the axes that ... stands for, and gives a new, unknown Axis().

Example

>>> x, t = Axis(name="x"), TimeAxis(name="t")
>>> axes = AxisList([x, ..., t])
>>> axes.at(0) is x, axes.at(-1) is t, axes.at(1)
(True, True, Axis())
>>> axes[2] is t, axes.at(2)
(True, Axis())

Parameters:

Name Type Description Default
position int

The position of the axis in the space.

required

Returns:

Type Description
Axis

The explicit axis at that position, or a new Axis().

Raises:

Type Description
IndexError

If the sequence is closed, and the position lies outside it.

TypeError

If the position is not an integer.

AxisTuple

Bases: tuple, AxisSequence, Generic[Unpack[AXES]]

An immutable AxisSequence.

It is a tuple, with all the API of an AxisSequence: indexing by name, [at][], [expand][] and so on. A slice, and every method that builds a new sequence, gives an AxisTuple.

A coordinate system with a fixed number of axes, such as an RASCoordinateSystem, stores its axes as one, so they are closed. The type parameters are the type of each item, in order, and fix the number of items: AxisTuple[SpaceAxis, SpaceAxis] is two spatial axes. A field of that type converts what it is given item by item, each to the type of its position, and refuses a wrong number of items, None, or ... (which is not an axis). A bare AxisTuple holds any number of items, ... included.

Example

>>> axes = RASCoordinateSystem().axes
>>> type(axes).__name__, axes.ndim, axes.names[0]
('AxisTuple', 3, 'left-to-right')
>>> axes["left-to-right"] is axes[0] is axes.at(-3)
True

Attributes

names property
names: tuple[str | None | _Ellipsis, ...]

The name of each entry: None for an unnamed axis, and ... in the place of ....

Example

>>> AxisList([Axis(name="x"), Axis(), ...]).names
('x', None, Ellipsis)
ndim property
ndim: int | None

The number of axes, or None when the list is open.

A closed list has one axis per entry. An open list has an unknown number of axes.

Example

>>> AxisList([Axis(), Axis()]).ndim
2
>>> AxisList([Axis(), ...]).ndim is None
True
is_open property
is_open: bool

Whether the list holds ..., so that its number of axes is unknown.

AxisList([...]), which says nothing at all, is open. The empty list is closed: it has no axis.

Methods:

expand
expand(ndim: int) -> Self

The closed list of ndim axes that this list describes.

In an open list, ... is replaced with as many unknown Axis() as needed to reach ndim axes. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> AxisList([Axis(name="x"), ...]).expand(3)
[Axis(name='x'), Axis(), Axis()]
>>> AxisList([...]).expand(2)
[Axis(), Axis()]

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
AxisList

A new, closed list of ndim axes. A closed list is returned as a copy of itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open list, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> Self

The axes at some positions, or with some names, of this list.

A reference is the position of an axis in the space (int), or the name of an explicit axis (str), as axes[name] reads it.

  • In a closed list of n axes, a position lies in [-n, n).
  • In an open list, every position is valid, because ... stands for any number of axes. A non-negative position reads the explicit axes before ..., and a negative one the explicit axes after it. Any other position falls among the axes that ... stands for, and gives an unknown Axis().

The axes are listed in the order of refs.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> AxisList([x, y, z]).restrict(["z", 0])
[Axis(name='z'), Axis(name='x')]
>>> AxisList([x, ...]).restrict([0, 1])
[Axis(name='x'), Axis()]

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
AxisList

A new, closed list of len(refs) axes.

Raises:

Type Description
IndexError

If a position lies outside a closed list.

KeyError

If no explicit axis has a name.

ValueError

If more than one explicit axis has a name, or if two references name the same axis.

TypeError

If a reference is neither an integer nor a string, or if refs is a string rather than a list of references.

embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> Self

The axes of a larger space in which this list's axes sit.

This is the inverse of restrict: axis j of this list sits at positions[j] of the result, and every other position holds an unknown Axis(). An open list is first closed to len(positions) axes, as by expand.

The positions are absolute positions in the larger space, which does not exist yet, so they cannot be names.

Example

>>> x = Axis(name="x")
>>> AxisList([x]).embed([1])
[Axis(), Axis(name='x'), Ellipsis]
>>> AxisList([x]).embed([1], ndim=3)
[Axis(), Axis(name='x'), Axis()]

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
AxisList

A new list, closed when ndim is given and open otherwise.

Raises:

Type Description
ValueError

If a position is negative or repeated, if ndim does not exceed every position, or if this list cannot be closed to len(positions) axes.

TypeError

If a position or ndim is not an integer.

compatible_with
compatible_with(other: Sequence[Any]) -> bool

Whether self and other could describe the same axes.

Two lists are compatible when some choice of the axes that each ... stands for makes them match axis by axis, each pair being compatible.

For two closed lists, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis, and [...] matches every list. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> AxisList([x, ...]).compatible_with([x, Axis(), t])
True
>>> AxisList([..., t]).compatible_with([x])
False

Parameters:

Name Type Description Default
other AxisSequence, or list or tuple of Axis

The axes to compare with. A plain list or tuple is read as an axis sequence.

required

Returns:

Type Description
bool

Whether the two lists could describe the same axes.

Raises:

Type Description
TypeError

If other is not a list or a tuple.

at
at(position: int) -> Axis

The axis at a position in the space.

Where axes[i] reads entry i of the sequence, axes.at(i) reads the axis at position i of the space it describes: counted from the first axis when i is non-negative, and from the last one when it is negative.

  • In a closed sequence, the two are the same, and a position lies in [-ndim, ndim).
  • In an open sequence, every position is valid, because ... stands for any number of axes. A non-negative position reads the explicit axes before ..., and a negative one the explicit axes after it. Any other position falls among the axes that ... stands for, and gives a new, unknown Axis().

Example

>>> x, t = Axis(name="x"), TimeAxis(name="t")
>>> axes = AxisList([x, ..., t])
>>> axes.at(0) is x, axes.at(-1) is t, axes.at(1)
(True, True, Axis())
>>> axes[2] is t, axes.at(2)
(True, Axis())

Parameters:

Name Type Description Default
position int

The position of the axis in the space.

required

Returns:

Type Description
Axis

The explicit axis at that position, or a new Axis().

Raises:

Type Description
IndexError

If the sequence is closed, and the position lies outside it.

TypeError

If the position is not an integer.

AxisList

Bases: AxisSequence[AXIS], list

A mutable AxisSequence.

It is a list, with all the API of an AxisSequence: indexing by name, [at][], [expand][] and so on. A slice, and every method that builds a new sequence, gives an AxisList.

A coordinate system whose number of axes is not fixed by its class stores its axes as one: a list or a tuple given to the system is converted to one, item by item, to the type of axis the class declares. Its default, [...], says nothing about the axes, and axes=None reads as that default.

The type parameter is the type of the items: AxisList[Union[Axis, EllipsisType]] may be open, and AxisList[Axis] is closed.

Example

>>> axes = CoordinateSystem(axes=[Axis(name="x"), ...]).axes
>>> type(axes).__name__, axes.is_open, axes["x"]
('AxisList', True, Axis(name='x'))
>>> axes.append(TimeAxis(name="t"))
>>> axes.at(-1)
TimeAxis(name='t')

Attributes

names property
names: tuple[str | None | _Ellipsis, ...]

The name of each entry: None for an unnamed axis, and ... in the place of ....

Example

>>> AxisList([Axis(name="x"), Axis(), ...]).names
('x', None, Ellipsis)
ndim property
ndim: int | None

The number of axes, or None when the list is open.

A closed list has one axis per entry. An open list has an unknown number of axes.

Example

>>> AxisList([Axis(), Axis()]).ndim
2
>>> AxisList([Axis(), ...]).ndim is None
True
is_open property
is_open: bool

Whether the list holds ..., so that its number of axes is unknown.

AxisList([...]), which says nothing at all, is open. The empty list is closed: it has no axis.

Methods:

__getitem__
__getitem__(key: SupportsIndex) -> AXIS
__getitem__(key: slice) -> Self
__getitem__(key: str) -> Axis

An entry (int), some entries (slice), or the axis with a name (str).

An integer or a slice indexes the entries of the sequence, as in any list or tuple, and a slice gives a sequence of the same type. A name gives the one explicit axis that has it. The axis at a position in the space is at that position.

Example

>>> x, t = Axis(name="x"), TimeAxis(name="t")
>>> AxisList([x, ..., t])["t"] is t
True
>>> AxisList([x, ..., t])[2] is t
True

Raises:

Type Description
KeyError

If no explicit axis has the name.

ValueError

If more than one explicit axis has the name.

(IndexError, TypeError)

As list indexing does.

__contains__
__contains__(item: object) -> bool

Whether an explicit axis has a name (str), or whether an entry equals item (anything else, as in any list).

index
index(
    query: Axis | str,
    start: SupportsIndex = 0,
    stop: SupportsIndex = maxsize,
) -> int

The first entry that matches an axis, or a name.

This is list.index, with a looser test than equality: an entry matches the query when it is an instance of the class of the query, and has every field that the query sets (not None), with the same value. The fields that the query leaves unset are not compared. A name stands for Axis(name=...), so it matches the axes with that name, whatever their class. ... matches nothing.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis(name="t", unit="s")
>>> axes = AxisList([x, ..., t])
>>> axes.index("t"), axes.index(SpaceAxis())
(2, 0)
>>> axes.index(Axis(unit="second")), axes.index(Axis())
(2, 0)
>>> axes.index("y")
Traceback (most recent call last):
  ...
ValueError: Axis(name='y') is not in list

Parameters:

Name Type Description Default
query Axis or str

The axis to find, or its name.

required
start int

Only the entries start to stop are searched, as in list.index.

0
stop int

Only the entries start to stop are searched, as in list.index.

0

Returns:

Type Description
int

The index of the first entry that matches. It is an entry index, which is a position in the space only in a closed list (see the class notes).

Raises:

Type Description
ValueError

If no entry matches.

TypeError

If query is neither an Axis nor a string.

expand
expand(ndim: int) -> Self

The closed list of ndim axes that this list describes.

In an open list, ... is replaced with as many unknown Axis() as needed to reach ndim axes. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> AxisList([Axis(name="x"), ...]).expand(3)
[Axis(name='x'), Axis(), Axis()]
>>> AxisList([...]).expand(2)
[Axis(), Axis()]

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
AxisList

A new, closed list of ndim axes. A closed list is returned as a copy of itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open list, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> Self

The axes at some positions, or with some names, of this list.

A reference is the position of an axis in the space (int), or the name of an explicit axis (str), as axes[name] reads it.

  • In a closed list of n axes, a position lies in [-n, n).
  • In an open list, every position is valid, because ... stands for any number of axes. A non-negative position reads the explicit axes before ..., and a negative one the explicit axes after it. Any other position falls among the axes that ... stands for, and gives an unknown Axis().

The axes are listed in the order of refs.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> AxisList([x, y, z]).restrict(["z", 0])
[Axis(name='z'), Axis(name='x')]
>>> AxisList([x, ...]).restrict([0, 1])
[Axis(name='x'), Axis()]

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
AxisList

A new, closed list of len(refs) axes.

Raises:

Type Description
IndexError

If a position lies outside a closed list.

KeyError

If no explicit axis has a name.

ValueError

If more than one explicit axis has a name, or if two references name the same axis.

TypeError

If a reference is neither an integer nor a string, or if refs is a string rather than a list of references.

embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> Self

The axes of a larger space in which this list's axes sit.

This is the inverse of restrict: axis j of this list sits at positions[j] of the result, and every other position holds an unknown Axis(). An open list is first closed to len(positions) axes, as by expand.

The positions are absolute positions in the larger space, which does not exist yet, so they cannot be names.

Example

>>> x = Axis(name="x")
>>> AxisList([x]).embed([1])
[Axis(), Axis(name='x'), Ellipsis]
>>> AxisList([x]).embed([1], ndim=3)
[Axis(), Axis(name='x'), Axis()]

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
AxisList

A new list, closed when ndim is given and open otherwise.

Raises:

Type Description
ValueError

If a position is negative or repeated, if ndim does not exceed every position, or if this list cannot be closed to len(positions) axes.

TypeError

If a position or ndim is not an integer.

compatible_with
compatible_with(other: Sequence[Any]) -> bool

Whether self and other could describe the same axes.

Two lists are compatible when some choice of the axes that each ... stands for makes them match axis by axis, each pair being compatible.

For two closed lists, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis, and [...] matches every list. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> AxisList([x, ...]).compatible_with([x, Axis(), t])
True
>>> AxisList([..., t]).compatible_with([x])
False

Parameters:

Name Type Description Default
other AxisSequence, or list or tuple of Axis

The axes to compare with. A plain list or tuple is read as an axis sequence.

required

Returns:

Type Description
bool

Whether the two lists could describe the same axes.

Raises:

Type Description
TypeError

If other is not a list or a tuple.

at
at(position: int) -> Axis

The axis at a position in the space.

Where axes[i] reads entry i of the sequence, axes.at(i) reads the axis at position i of the space it describes: counted from the first axis when i is non-negative, and from the last one when it is negative.

  • In a closed sequence, the two are the same, and a position lies in [-ndim, ndim).
  • In an open sequence, every position is valid, because ... stands for any number of axes. A non-negative position reads the explicit axes before ..., and a negative one the explicit axes after it. Any other position falls among the axes that ... stands for, and gives a new, unknown Axis().

Example

>>> x, t = Axis(name="x"), TimeAxis(name="t")
>>> axes = AxisList([x, ..., t])
>>> axes.at(0) is x, axes.at(-1) is t, axes.at(1)
(True, True, Axis())
>>> axes[2] is t, axes.at(2)
(True, Axis())

Parameters:

Name Type Description Default
position int

The position of the axis in the space.

required

Returns:

Type Description
Axis

The explicit axis at that position, or a new Axis().

Raises:

Type Description
IndexError

If the sequence is closed, and the position lies outside it.

TypeError

If the position is not an integer.

CoordinateSystem magic

CoordinateSystem(
    name: str | None = None,
    axes: _Axes[AxisList[Axis | _Ellipsis]] = [...],
    order: Literal["C", "F"] | None = None,
)

Bases: DataModelBase

A coordinate system defines the meaning of coordinates in a space.

It describes each axis in the system (name, unit and/or other properties), and can be named.

Open systems

The axes of a system are an AxisList, which may hold at most one ... (Ellipsis), anywhere in the list, that stands for zero or more axes about which nothing is known. A system with ... is open: its number of axes is unknown. A system without it is closed.

  • [..., TimeAxis()] says that the last axis is time, and nothing about the others.
  • [Axis(name="x"), ...] says that the first axis is x.
  • [...], the default, says nothing at all. axes=None reads as not giving the axes, so it is [...] too, and is stored as [...]: CoordinateSystem(axes=None) == CoordinateSystem().

A list or a tuple given as axes is stored as an AxisList. An axis is read by its name as system.axes["x"], at a position as system.axes.at(i), and found by index.

Classes with a fixed number of axes, such as CoordinateSystem3D, are always closed. They store their axes as an AxisTuple, whose type fixes the number of axes and the class of each one, so they reject .... It has the API of an AxisList, but is immutable. axes=None reads as not giving the axes there too, so it builds the class's default axes: CoordinateSystem3D(axes=None) == CoordinateSystem3D().

Calling a class builds the most specific system its axes describe (see the module), and only a closed system is dispatched: CoordinateSystem(axes=[x, y]) is a CoordinateSystem2D, whose axes are an AxisTuple, but CoordinateSystem(axes=[x, ...]) -- whose ... may stand for no axis, or for many -- stays a CoordinateSystem. Closing an open system with expand dispatches it again.

Equality

Equality is field by field: two systems are equal when they are of the same class, have the same name, and have equal axes. A system is never equal to None, not even a plain CoordinateSystem() that says nothing at all: as the endpoint of a transformation, None is no system (the transformation defers to its context for it), and a CoordinateSystem() is one, kept as given. compatible_with is the looser question of whether two systems could describe the same space.

Attributes

name class-attribute instance-attribute
name: str | None = None

The name of the coordinate system.

axes class-attribute instance-attribute
axes: _Axes[AxisList[Axis | _Ellipsis]] = [...]

The axes of the coordinate system, in order. [...], the default, says nothing about them; axes=None reads as the default.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

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.

CoordinateSystem2D magic

CoordinateSystem2D(axes: _Axes[_2Axes] = (Axis(), Axis()))

Bases: CoordinateSystem

A coordinate systems with exactly two dimensions.

Attributes

name class-attribute instance-attribute
name: str | None = None

The name of the coordinate system.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CoordinateSystem3D magic

CoordinateSystem3D(
    axes: _Axes[_3Axes] = (Axis(), Axis(), Axis()),
)

Bases: CoordinateSystem

A coordinate system with exactly three dimensions.

Attributes

name class-attribute instance-attribute
name: str | None = None

The name of the coordinate system.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

PhysicalCoordinateSystem

PhysicalCoordinateSystem(
    name: str | None = None,
    axes: _Axes[AxisList[Axis | _Ellipsis]] = [...],
    order: Literal["C", "F"] | None = None,
)

Bases: CoordinateSystem

A coordinate system whose coordinates measure physical quantities.

Every axis it states is measured in a physical unit, or in a unit not yet specified (None): a millimetre or a second, never [IndexUnit][], which says the coordinates count the samples of an array. So reversing one of its axes is a sign flip, never the origin shift a sampled axis needs, and a conversion factor to another physical system of the same kind exists as soon as the units are all given.

The unit of an axis is of the kind its axis measures: a spatial axis takes a unit of space and a time axis a unit of time. The type of the axis already enforces that -- SpaceAxis(unit="s") is refused -- so this class only refuses the index units.

It may be open, and its units may be unspecified, since neither says anything non-physical: ... stands for axes about which nothing is known, and None for a unit about which nothing is. A system with no axis at all, [], has nothing to refuse either. No array, pixel or voxel system is a physical one: their axes count samples.

This is a base to inherit deliberately rather than a dispatch target: a physical spatial system is selected as a spatial one. The concrete systems that are physical by construction -- RASmm, LPSmm, RSAmm -- compose it in, and are stricter: they are in millimetres, on every axis. Their own constraint is what dispatch selects them on, so axes in RAS order in centimetres, or with no unit, build an RASCoordinateSystem, and built by name, RASmm refuses them.

Example

>>> PhysicalCoordinateSystem(axes=[SpaceAxis(unit="mm"), ...]).ndim
>>> PhysicalCoordinateSystem(axes=[R(), A(unit="cm")]).ndim
2
>>> mm = [R(unit="mm"), A(unit="mm"), S(unit="mm")]
>>> type(PhysicalCoordinateSystem(axes=mm)).__name__
'RASmm'
>>> type(CoordinateSystem(axes=[R(), A(), S()])).__name__
'RASCoordinateSystem'

Attributes

name class-attribute instance-attribute
name: str | None = None

The name of the coordinate system.

axes class-attribute instance-attribute
axes: _Axes[AxisList[Axis | _Ellipsis]] = [...]

The axes of the coordinate system, in order. [...], the default, says nothing about them; axes=None reads as the default.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

ArrayCoordinateSystem magic

ArrayCoordinateSystem(name: str | None = 'array')

Bases: CoordinateSystem

A coordinate system for a multidimensional array.

Its coordinates count samples, so the axes it builds by default carry the index unit (see [IndexUnit][]). Its order is the memory order of the array, None when it is not specified: an ArrayCoordinateSystem says nothing about it.

It is a base rather than a dispatch target: calling it with two or three axes builds the matching fixed-arity class, and a system of two or three sampled axes is selected as one of those from CoordinateSystem too. Calling any class with order="C" or order="F" builds the C- or F-ordered class that the order and the axes select (see the module).

Attributes

axes class-attribute instance-attribute
axes: _Axes[AxisList[Axis | _Ellipsis]] = [...]

The axes of the coordinate system, in order. [...], the default, says nothing about them; axes=None reads as the default.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CArrayCoordinateSystem magic

CArrayCoordinateSystem(name: str | None = 'carray')

Bases: ArrayCoordinateSystem

A coordinate system for a C-ordered multidimensional array.

The first axis is the slowest changing in memory, and the last axis the fastest changing. It is what order="C" selects.

Attributes

axes class-attribute instance-attribute
axes: _Axes[AxisList[Axis | _Ellipsis]] = [...]

The axes of the coordinate system, in order. [...], the default, says nothing about them; axes=None reads as the default.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FArrayCoordinateSystem magic

FArrayCoordinateSystem(name: str | None = 'farray')

Bases: ArrayCoordinateSystem

A coordinate system for an F-ordered multidimensional array.

The first axis is the fastest changing in memory, and the last axis the slowest changing. It is what order="F" selects.

Attributes

axes class-attribute instance-attribute
axes: _Axes[AxisList[Axis | _Ellipsis]] = [...]

The axes of the coordinate system, in order. [...], the default, says nothing about them; axes=None reads as the default.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

ArrayCoordinateSystem2D magic

ArrayCoordinateSystem2D(
    axes: _Axes[_2Axes] = (_dim(0), _dim(1)),
)

Bases: CoordinateSystem2D, ArrayCoordinateSystem

A coordinate system for an array with two dimensions.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

ArrayCoordinateSystem3D magic

ArrayCoordinateSystem3D(
    axes: _Axes[_3Axes] = (_dim(0), _dim(1), _dim(2)),
)

Bases: CoordinateSystem3D, ArrayCoordinateSystem

A coordinate system for an array with three dimensions.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CArrayCoordinateSystem2D magic

CArrayCoordinateSystem2D(
    axes: _Axes[_2Axes] = (_dim(0), _dim(1)),
)

Bases: CoordinateSystem2D, CArrayCoordinateSystem

A coordinate system for a C-ordered array with two dimensions.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CArrayCoordinateSystem3D magic

CArrayCoordinateSystem3D(
    axes: _Axes[_3Axes] = (_dim(0), _dim(1), _dim(2)),
)

Bases: CoordinateSystem3D, CArrayCoordinateSystem

A coordinate system for a C-ordered array with three dimensions.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FArrayCoordinateSystem2D magic

FArrayCoordinateSystem2D(
    axes: _Axes[_2Axes] = (_dim(0), _dim(1)),
)

Bases: CoordinateSystem2D, FArrayCoordinateSystem

A coordinate system for an F-ordered array with two dimensions.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FArrayCoordinateSystem3D magic

FArrayCoordinateSystem3D(
    axes: _Axes[_3Axes] = (_dim(0), _dim(1), _dim(2)),
)

Bases: CoordinateSystem3D, FArrayCoordinateSystem

A coordinate system for an F-ordered array with three dimensions.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

SpatialCoordinateSystem magic

SpatialCoordinateSystem(
    axes: _Axes[AxisList[SpaceAxis | _Ellipsis]] = [...],
)

Bases: CoordinateSystem

A coordinate system, whose axes have spatial meaning.

Attributes

name class-attribute instance-attribute
name: str | None = None

The name of the coordinate system.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

SpatialCoordinateSystem2D magic

SpatialCoordinateSystem2D(
    axes: _Axes[_2SpatialAxes] = (SpaceAxis(), SpaceAxis()),
)

Bases: CoordinateSystem2D, SpatialCoordinateSystem

A 2D coordinate system, whose axes have spatial meaning.

Attributes

name class-attribute instance-attribute
name: str | None = None

The name of the coordinate system.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

SpatialCoordinateSystem3D magic

SpatialCoordinateSystem3D(
    axes: _Axes[_3SpatialAxes] = (
        SpaceAxis(),
        SpaceAxis(),
        SpaceAxis(),
    ),
)

Bases: CoordinateSystem3D, SpatialCoordinateSystem

A 3D coordinate system, whose axes have spatial meaning.

Attributes

name class-attribute instance-attribute
name: str | None = None

The name of the coordinate system.

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

PixelCoordinateSystem magic

PixelCoordinateSystem(
    name: str | None = "pixel",
    axes: _Axes[_2SpatialAxes] = (
        _space("dim0"),
        _space("dim1"),
    ),
)

Bases: SpatialCoordinateSystem2D, ArrayCoordinateSystem2D

A coordinate system for 2D pixel grids.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

VoxelCoordinateSystem magic

VoxelCoordinateSystem(
    name: str | None = "voxel",
    axes: _Axes[_3SpatialAxes] = (
        _space("dim0"),
        _space("dim1"),
        _space("dim2"),
    ),
)

Bases: SpatialCoordinateSystem3D, ArrayCoordinateSystem3D

A coordinate system for 3D voxel grids.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CPixelCoordinateSystem magic

CPixelCoordinateSystem(
    name: str | None = "cpixel",
    order: Literal["C"] = "C",
    axes: _Axes[_2SpatialAxes] = (_space("j"), _space("i")),
)

Bases: PixelCoordinateSystem, CArrayCoordinateSystem2D

A coordinate system for C-ordered 2D pixel grids.

Attributes

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FPixelCoordinateSystem magic

FPixelCoordinateSystem(
    name: str | None = "fpixel",
    order: Literal["F"] = "F",
    axes: _Axes[_2SpatialAxes] = (_space("i"), _space("j")),
)

Bases: PixelCoordinateSystem, FArrayCoordinateSystem2D

A coordinate system for F-ordered 2D pixel grids.

Attributes

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CVoxelCoordinateSystem magic

CVoxelCoordinateSystem(
    name: str | None = "cvoxel",
    axes: _Axes[_3SpatialAxes] = (
        _space("k"),
        _space("j"),
        _space("i"),
    ),
)

Bases: SpatialCoordinateSystem3D, CArrayCoordinateSystem3D

A coordinate system for C-ordered 3D voxel grids.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FVoxelCoordinateSystem magic

FVoxelCoordinateSystem(
    name: str | None = "fvoxel",
    axes: _Axes[_3SpatialAxes] = (
        _space("i"),
        _space("j"),
        _space("k"),
    ),
)

Bases: SpatialCoordinateSystem3D, FArrayCoordinateSystem3D

A coordinate system for F-ordered 3D voxel grids.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

RASCoordinateSystem magic

RASCoordinateSystem(
    name: str | None = "RAS",
    axes: _Axes[AxisTuple[AxisLR, AxisPA, AxisIS]] = (
        R(),
        A(),
        S(),
    ),
)

Bases: SpatialCoordinateSystem3D

The RAS anatomical coordinate system.

Coordinates increase toward the right, the anterior, and the superior directions. This coordinate system is used by NIfTI files, and by many other neuroimaging formats.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

LPSCoordinateSystem magic

LPSCoordinateSystem(
    name: str | None = "LPS",
    axes: _Axes[AxisTuple[AxisRL, AxisAP, AxisIS]] = (
        L(),
        P(),
        S(),
    ),
)

Bases: SpatialCoordinateSystem3D

The LPS anatomical coordinate system.

Coordinates increase toward the left, the posterior, and the superior directions. This coordinate system is used by ITK, and therefore also by ANTs, 3D Slicer, and other ITK-based tools.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

RSACoordinateSystem magic

RSACoordinateSystem(
    name: str | None = "RSA",
    axes: _Axes[AxisTuple[AxisLR, AxisIS, AxisPA]] = (
        R(),
        S(),
        A(),
    ),
)

Bases: SpatialCoordinateSystem3D

The RSA anatomical coordinate system.

Coordinates increase toward the right, the superior, and the anterior directions. This coordinate system appears in some FreeSurfer LTA files.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

RASmm magic

RASmm(
    name: str | None = "RAS",
    axes: _Axes[AxisTuple[AxisLR, AxisPA, AxisIS]] = (
        _mm(AxisLR),
        _mm(AxisPA),
        _mm(AxisIS),
    ),
)

Bases: RASCoordinateSystem, _Millimetres

RASCoordinateSystem in millimetres.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

LPSmm magic

LPSmm(
    name: str | None = "LPS",
    axes: _Axes[AxisTuple[AxisRL, AxisAP, AxisIS]] = (
        _mm(AxisRL),
        _mm(AxisAP),
        _mm(AxisIS),
    ),
)

Bases: LPSCoordinateSystem, _Millimetres

LPSCoordinateSystem in millimetres.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

RSAmm magic

RSAmm(
    name: str | None = "RSA",
    axes: _Axes[AxisTuple[AxisLR, AxisIS, AxisPA]] = (
        _mm(AxisLR),
        _mm(AxisIS),
        _mm(AxisPA),
    ),
)

Bases: RSACoordinateSystem, _Millimetres

RSACoordinateSystem in millimetres.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FRASCoordinateSystem magic

FRASCoordinateSystem(
    name: str | None = "fRAS",
    axes: _Axes[AxisTuple[AxisLR, AxisPA, AxisIS]] = (
        _sampled(AxisLR, "x"),
        _sampled(AxisPA, "y"),
        _sampled(AxisIS, "z"),
    ),
)

Bases: RASCoordinateSystem, FVoxelCoordinateSystem

Combines RASCoordinateSystem with FVoxelCoordinateSystem.

This coordinate system describes an F-ordered voxel grid whose axes already point in RAS order.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FLPSCoordinateSystem magic

FLPSCoordinateSystem(
    name: str | None = "fLPS",
    axes: _Axes[AxisTuple[AxisRL, AxisAP, AxisIS]] = (
        _sampled(AxisRL, "x"),
        _sampled(AxisAP, "y"),
        _sampled(AxisIS, "z"),
    ),
)

Bases: LPSCoordinateSystem, FVoxelCoordinateSystem

Combines LPSCoordinateSystem with FVoxelCoordinateSystem.

This coordinate system describes an F-ordered voxel grid whose axes already point in LPS order.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

FRSACoordinateSystem magic

FRSACoordinateSystem(
    name: str | None = "fRSA",
    axes: _Axes[AxisTuple[AxisLR, AxisIS, AxisPA]] = (
        _sampled(AxisLR, "x"),
        _sampled(AxisIS, "y"),
        _sampled(AxisPA, "z"),
    ),
)

Bases: RSACoordinateSystem, FVoxelCoordinateSystem

Combines RSACoordinateSystem with FVoxelCoordinateSystem.

This coordinate system describes an F-ordered voxel grid whose axes already point in RSA order.

Attributes

order class-attribute instance-attribute
order: Literal['C', 'F'] | None = None

The memory order of the array the coordinates index: "C" (the last axis changes fastest), "F" (the first axis does), or None when it is not specified. Only an ArrayCoordinateSystem indexes an array, so any other system refuses an order; the field is declared here so that every class can be called with it, and pass it on to the C- or F-ordered class it selects.

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CRASCoordinateSystem magic

CRASCoordinateSystem(
    name: str | None = "cRAS",
    order: Literal["C"] = "C",
    axes: _Axes[AxisTuple[AxisIS, AxisPA, AxisLR]] = (
        _sampled(AxisIS, "z"),
        _sampled(AxisPA, "y"),
        _sampled(AxisLR, "x"),
    ),
)

Bases: RASCoordinateSystem, CVoxelCoordinateSystem

Combines RASCoordinateSystem with CVoxelCoordinateSystem.

This coordinate system describes a C-ordered voxel grid whose axes already point in RAS order.

Attributes

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CLPSCoordinateSystem magic

CLPSCoordinateSystem(
    name: str | None = "cLPS",
    order: Literal["C"] = "C",
    axes: _Axes[AxisTuple[AxisIS, AxisAP, AxisRL]] = (
        _sampled(AxisIS, "z"),
        _sampled(AxisAP, "y"),
        _sampled(AxisRL, "x"),
    ),
)

Bases: LPSCoordinateSystem, CVoxelCoordinateSystem

Combines LPSCoordinateSystem with CVoxelCoordinateSystem.

This coordinate system describes a C-ordered voxel grid whose axes already point in LPS order.

Attributes

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.

CRSACoordinateSystem magic

CRSACoordinateSystem(
    name: str | None = "cRSA",
    order: Literal["C"] = "C",
    axes: _Axes[AxisTuple[AxisPA, AxisIS, AxisLR]] = (
        _sampled(AxisPA, "z"),
        _sampled(AxisIS, "y"),
        _sampled(AxisLR, "x"),
    ),
)

Bases: RSACoordinateSystem, CVoxelCoordinateSystem

Combines RSACoordinateSystem with CVoxelCoordinateSystem.

This coordinate system describes a C-ordered voxel grid whose axes already point in RSA order.

Attributes

ndim property
ndim: int | None

The number of axes, or None when the system is open.

A closed system has exactly len(axes) axes. An open system, whose axes hold ..., has an unknown number of axes, and its ndim is None. This is AxisSequence.ndim of its axes.

Example

>>> CoordinateSystem(axes=[Axis(), Axis()]).ndim
2
>>> CoordinateSystem(axes=[Axis(), ...]).ndim is None
True
>>> CoordinateSystem().ndim is None
True

Methods:

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.

expand
expand(ndim: int) -> Self

The closed system of ndim axes that this system describes.

The axes are expanded by AxisSequence.expand: in an open system, ... is replaced with as many unknown Axis() as needed to reach ndim axes. The class is called again with the closed axes, and the other fields, the name included, are kept: the result is of this class, or of the subclass that the closed axes select from it (an ArrayCoordinateSystem closed to two axes is an ArrayCoordinateSystem2D). Each unknown Axis() is first read as the type of axis the class declares, so a SpatialCoordinateSystem closed to three axes has three spatial axes, and is a SpatialCoordinateSystem3D. Use it once the number of axes is known, for instance from the shape of the data.

Example

>>> CoordinateSystem(axes=[Axis(name="x"), ...]).expand(4)
CoordinateSystem(axes=[Axis(name='x'), Axis(), Axis(), Axis()])
>>> CoordinateSystem().expand(2)
CoordinateSystem2D(axes=(Axis(), Axis()))

Parameters:

Name Type Description Default
ndim int

The number of axes.

required

Returns:

Type Description
CoordinateSystem

A closed system of ndim axes, of this class or of one of its subclasses. A closed system is returned as itself.

Raises:

Type Description
ValueError

If ndim is less than the number of explicit axes of an open system, or differs from the number of axes of a closed one.

TypeError

If ndim is not an integer.

restrict
restrict(refs: Iterable[int | str]) -> CoordinateSystem

The system of the axes at some positions of this system.

The axes are restricted by AxisSequence.restrict: a reference is a position in the space or a name, and a position of an open system that falls among the axes that ... stands for gives an unknown Axis(). The axes are listed in the order of refs. The result describes a different space, so the class and the name of this system are not carried over: it is the closed system that CoordinateSystem(axes=...) builds from the restricted axes, which is a CoordinateSystem2D, an RASCoordinateSystem, ... when the axes select one.

Example

>>> x, y, z = Axis(name="x"), Axis(name="y"), Axis(name="z")
>>> CoordinateSystem(axes=[x, y, z]).restrict(["z", 0])
CoordinateSystem2D(axes=(Axis(name='z'), Axis(name='x')))
>>> CoordinateSystem(axes=[x, ...]).restrict([0])
CoordinateSystem(axes=[Axis(name='x')])

Parameters:

Name Type Description Default
refs iterable of int or str

The positions or names of the axes to keep.

required

Returns:

Type Description
CoordinateSystem

A closed system of len(refs) axes.

Raises:

Type Description
(ValueError, IndexError, TypeError)
embed
embed(
    positions: Iterable[int], ndim: int | None = None
) -> CoordinateSystem

The system of a larger space in which this system's axes sit.

This is the inverse of restrict. The axes are embedded by AxisSequence.embed: axis j of this system sits at positions[j] of the result, and every other position holds an unknown Axis(). The result describes a different space, so the class and the name of this system are not carried over: it is the system that CoordinateSystem(axes=...) builds from the embedded axes -- a plain, open CoordinateSystem when ndim is not given, and the closed system the axes select when it is.

Example

>>> x = Axis(name="x")
>>> CoordinateSystem(axes=[x]).embed([1])
CoordinateSystem(axes=[Axis(), Axis(name='x'), Ellipsis])
>>> CoordinateSystem(axes=[x]).embed([1], ndim=4)
CoordinateSystem(axes=[Axis(), Axis(name='x'), Axis(), Axis()])

Parameters:

Name Type Description Default
positions iterable of int

The non-negative position of each axis in the larger space.

required
ndim int

The number of axes of the larger space. When it is not given, the number is unknown, and the result ends with ... after the last embedded axis.

None

Returns:

Type Description
CoordinateSystem

A system that is closed when ndim is given, and open otherwise.

Raises:

Type Description
(ValueError, TypeError)
compatible_with
compatible_with(other: CoordinateSystem | None) -> bool

Whether self and other could describe the same space.

Two systems are compatible when their axes are AxisSequence.compatible_with each other: some choice of the axes that each ... stands for makes them match axis by axis, each pair being Axis.compatible_with. Only the axes are compared, not the names of the systems. None is read as a system about which nothing is known, which is compatible with every system.

For two closed systems, this asks for the same number of axes, pairwise compatible. Unlike ==, an unknown Axis() matches any axis. The relation is symmetric, but not transitive.

Example

>>> x, t = SpaceAxis(name="x"), TimeAxis()
>>> CoordinateSystem(axes=[x, ...]).compatible_with(
...     CoordinateSystem(axes=[x, Axis(), t])
... )
True
>>> CoordinateSystem(axes=[..., t]).compatible_with(
...     CoordinateSystem(axes=[x])
... )
False

Parameters:

Name Type Description Default
other CoordinateSystem or None

The system to compare with.

required

Returns:

Type Description
bool

Whether the two systems could describe the same space.

Raises:

Type Description
TypeError

If other is neither a CoordinateSystem nor None.