coordinax.frames#

The coordinax.frames module provides reference frames and frame-transition construction for relating different spatial observers and coordinate perspectives.

Overview#

Frames represent spatial observers. The transform operators themselves live in coordinax.transforms (typically imported as cxfm), and coordinax.frames constructs frame transitions using those operators.

For design philosophy, reference frame models, and practical workflows, see Working With Frames. For background math, see spec § Frame Transforms.

Transformation Groups#

Transformation groups classify transformations by the geometric properties they preserve:

Group

Parent

Preserves

Intuition

Identity

Everything (null)

Do nothing

Diffeomorphism

Smooth structure

Any smooth invertible map

Affine

Diffeomorphism

Parallelism, hyperplanes

Linear + translation

Euclidean

Affine

Distances, angles

Rotations + slides

Orthogonal

Affine

Angles (fixes origin)

Rotations/reflections through origin

Special Orthogonal

Orthogonal

Orientation (det=+1)

Proper rotations only

Poincaré

Diffeomorphism

Spacetime intervals

Lorentz boosts + translations

Lorentz

Minkowski metric

Proper & improper boosts

Proper Orthochronous Lorentz

Lorentz

Space+time orient.

Physical relativistic transforms

For detailed semantics and use cases of each group, see Working With Frames.

Quick Start#

import coordinax.frames as cxf
import coordinax.transforms as cxfm
import coordinax.main as cx

# Create transformation between frames
transform = cxf.frame_transition(cxf.alice, cxf.alex)

# Apply to vector
v = cx.Point.from_([1, 2, 3], "m")
v_transformed = cxfm.act(transform, None, v)

See Working With Frames for composition, inversion, and simplification patterns.

Functional API#

Frame Operations#

  • frame_transition(frame1, frame2): construct a transformation operator from one frame to another

  • AbstractReferenceFrame: base class for defining reference frames

Transform Operations#

Transform operations and transform classes are in coordinax.transforms.

Built-in Frames#

  • Alice, Alex: example stationary frames

  • NoFrame: identity frame

  • TransformedReferenceFrame: frame defined relative to a base frame

Transformation Group Classes (Markers)#

Transformation-group marker classes are in coordinax.transforms.

Design & Integration#

For reference frame models, custom frame design, and active transformation semantics, see Working With Frames. For JAX integration patterns (vmap, jit), see Working With Frames.

Reference frames and transformations between them.

Examples

>>> import quaxed.numpy as jnp
>>> import unxt as u
>>> import coordinax.vectors as cxv
>>> import coordinax.frames as cxf

Let’s transform a position from Alice’s frame to Alex’s frame:

>>> op = cxf.frame_transition(cxf.alice, cxf.alex)
>>> op
Composed((
    Translate(
        {'x': Q(i64[], 'm'), 'y': Q(i64[], 'm'), 'z': Q(i64[], 'm')},
        chart=Cart3D(M=Rn(3))
    ),
    Rotate(f64[3,3](jax))
))
>>> q_alice = cxv.Point.from_([0, 0, 0], "km")
>>> t = u.Q(2.5, "yr")
>>> q_alex = op(t, q_alice)
>>> print(q_alex.round(3))
<Point: chart=Cart3D (x, y, z) [km]
    [0.   0.01 0.  ]>

Now let’s create a new transformed frame and work with it:

>>> import coordinax.transforms as cxfm
>>> R = cxfm.Rotate([[0., -1, 0], [1, 0, 0], [0, 0, 1]])
>>> frame = cxf.TransformedReferenceFrame(cxf.alice, R)
>>> frame
TransformedReferenceFrame(base_frame=Alice(), xop=Rotate(R=f64[3,3]))

Let’s transform a position from the base frame to the transformed frame:

>>> op = cxf.frame_transition(cxf.alice, frame)
>>> q_icrs = cxv.Point.from_([1, 0, 0], "kpc")
>>> q_frame = op(q_icrs)
>>> print(q_frame)
<Point: chart=Cart3D (x, y, z) [kpc]
    [0. 1. 0.]>
>>> op.inverse(q_frame) == q_icrs
Array(True, dtype=bool)
coordinax.frames.frame_transition(*args: Any, **kwargs: Any)#

Return the transform operator that maps coordinates from one frame to another.

Given a source frame and a target frame, frame_transition computes the AbstractTransform (or composed chain of transforms) that, when applied to coordinates expressed in from_frame, yields coordinates expressed in to_frame.

Notes

  • Each pair of concrete frame types registers its own dispatch. Calling frame_transition(frame_a, frame_a) returns Identity().

  • For TransformedReferenceFrame, the transition is constructed automatically by composing the base-frame transition with the stored xop.

  • The returned transform is invertible: op.inverse gives the to_framefrom_frame direction.

  • This function uses multiple dispatch. To inspect all registered pairs:

    >>> import coordinax.frames as cxf
    >>> cxf.frame_transition.methods
    List of 20 method(s):
        [0] frame_transition(from_frame: ...)
    

See also

coordinax.frames.act

Apply a transform to coordinates

coordinax.frames.compose

Compose two transforms into one

Examples

>>> import coordinax.frames as cxf

Same-to-same frame (identity):

>>> cxf.frame_transition(cxf.alice, cxf.alice)
Identity()

Alice → Alex:

>>> op = cxf.frame_transition(cxf.alice, cxf.alex)
>>> op
Composed(( Translate(...), Rotate(...) ))

Alex → Alice (inverse direction):

>>> op = cxf.frame_transition(cxf.alex, cxf.alice)
>>> op
Composed(( Rotate(...), Translate(...) ))

Using a TransformedReferenceFrame:

>>> import coordinax.transforms as cxfm
>>> import quaxed.numpy as jnp
>>> from coordinax.astro import ICRS
>>> R = cxfm.Rotate(jnp.asarray([[0., -1, 0], [1, 0, 0], [0, 0, 1]]))
>>> frame = cxf.TransformedReferenceFrame(ICRS(), R)
>>> op = cxf.frame_transition(ICRS(), frame)
>>> type(op).__name__
'Composed'
coordinax.frames.frame_transition(from_frame: AbstractReferenceFrame, to_frame: AbstractReferenceFrame, /) Identity
Parameters:
Return type:

Any

Return an identity operator for frames that are the same.

>>> import coordinax.frames as cxf
>>> cxf.frame_transition(cxf.alice, cxf.alice)
Identity()
>>> cxf.frame_transition(cxf.alex, cxf.alex)
Identity()
>>> cxf.frame_transition(cxf.bob, cxf.bob)
Identity()
coordinax.frames.frame_transition(from_frame: Alice, to_frame: Alex, /) Composed
Parameters:
Return type:

Any

Transform from Alice’s frame to Alex’s frame.

>>> import unxt as u
>>> import coordinax.main as cx
>>> op = cxf.frame_transition(cxf.alice, cxf.alex)
>>> print(op)
Composed(( Translate(...), Rotate(...) ))
coordinax.frames.frame_transition(from_frame: Alice, to_frame: Bob, /) Composed
Parameters:
Return type:

Any

Transform from Alice’s frame to Bob’s frame.

This is an example of a reference frame transformation that includes both a spatial translation (Translate) and a velocity boost (Boost).

The Boost has well-defined actions on kinematic roles:

  • Point: identity (points are unchanged by a Galilean boost)

  • Pos: identity (displacements are Galilean invariant)

  • Vel: adds $v_0$

  • PhysAcc: identity (for constant boost)

Examples

>>> import unxt as u
>>> import coordinax.main as cx
>>> import coordinax.frames as cxf
>>> alice = cxf.Alice()
>>> bob = cxf.Bob()
>>> op = cxf.frame_transition(alice, bob)
>>> print(op)
Composed(( Translate(...), Boost(...) ))
coordinax.frames.frame_transition(from_frame: AbstractReferenceFrame, to_frame: AbstractReferenceFrame, /) Composed
Parameters:
Return type:

Any

Transform back.

>>> import unxt as u
>>> import coordinax.main as cx
>>> cxf.frame_transition(cxf.alex, cxf.alice)
Composed(( Rotate(...), Translate(...) ))
>>> cxf.frame_transition(cxf.bob, cxf.alice)
Composed((
  Boost( {...}, chart=Cart3D(M=Rn(3)) ),
  Translate( {...}, chart=Cart3D(M=Rn(3)) )
))
coordinax.frames.frame_transition(from_frame: NoFrame, to_frame: NoFrame, /) Identity
Parameters:
Return type:

Any

Null-to-null frame transition is always the identity.

When both source and target frames are noframe (i.e. the vector is frame-agnostic) there is nothing to transform, so the result is the identity operation.

>>> import coordinax.frames as cxf
>>> import coordinax.transforms as cxfm
>>> op = cxf.frame_transition(cxf.noframe, cxf.noframe)
>>> isinstance(op, cxfm.Identity)
True
coordinax.frames.frame_transition(from_frame: NoFrame, to_frame: AbstractReferenceFrame, /) NoReturn
Parameters:
Return type:

Any

Cannot transform from the null frame.

>>> import coordinax.frames as cxf
>>> try:
...     cxf.frame_transition(cxf.noframe, cxf.alice)
... except cxf.FrameTransformError as e:
...     print(e)
Cannot transform from the null frame.
coordinax.frames.frame_transition(from_frame: AbstractReferenceFrame, to_frame: NoFrame, /) NoReturn
Parameters:
Return type:

Any

Cannot transform to the null frame.

>>> import coordinax.frames as cxf
>>> try:
...     cxf.frame_transition(cxf.alice, cxf.noframe)
... except cxf.FrameTransformError as e:
...     print(e)
Cannot transform to the null frame.
coordinax.frames.frame_transition(from_frame: AbstractReferenceFrame, to_frame: TransformedReferenceFrame) AbstractTransform
Parameters:
Return type:

Any

Return a frame transform operator to a transformed frame.

>>> import quaxed.numpy as jnp
>>> import coordinax.vectors as cxv
>>> import coordinax.frames as cxf
>>> import coordinax.transforms as cxfm
>>> from coordinax.astro import ICRS
>>> R = cxfm.Rotate(jnp.asarray([[0., -1, 0], [1, 0, 0], [0, 0, 1]]))
>>> frame = cxf.TransformedReferenceFrame(ICRS(), R)
>>> frame
TransformedReferenceFrame(base_frame=ICRS(), xop=Rotate(R=f64[3,3]))

Let’s transform a position from the base frame to the transformed frame:

>>> op = cxf.frame_transition(ICRS(), frame)
>>> q_icrs = cxv.Point.from_([1, 0, 0], "kpc")
>>> q_frame = op(q_icrs)
>>> print(q_frame)
<Point: chart=Cart3D (x, y, z) [kpc]
    [0. 1. 0.]>
coordinax.frames.frame_transition(from_frame: TransformedReferenceFrame, to_frame: AbstractReferenceFrame) AbstractTransform
Parameters:
Return type:

Any

Return a frame transform operator from a transformed frame.

>>> import quaxed.numpy as jnp
>>> import coordinax.vectors as cxv
>>> import coordinax.frames as cxf
>>> import coordinax.transforms as cxfm
>>> from coordinax.astro import ICRS
>>> R = cxfm.Rotate(jnp.asarray([[0., -1, 0], [1, 0, 0], [0, 0, 1]]))
>>> frame = cxf.TransformedReferenceFrame(ICRS(), R)
>>> frame
TransformedReferenceFrame(base_frame=ICRS(), xop=Rotate(R=f64[3,3]))

Let’s transform a position from the base frame to the transformed frame:

>>> op = cxf.frame_transition(frame, ICRS())
>>> q_icrs = cxv.Point.from_([0, 1, 0], "kpc")
>>> q_frame = op(q_icrs)
>>> print(q_frame)
<Point: chart=Cart3D (x, y, z) [kpc]
    [1. 0. 0.]>
coordinax.frames.frame_transition(from_frame: TransformedReferenceFrame, to_frame: TransformedReferenceFrame) AbstractTransform
Parameters:
Return type:

Any

Return a frame transform operator between two transformed frames.

When from_frame and to_frame are the same object the result is the identity transform.

>>> import quaxed.numpy as jnp
>>> import coordinax.vectors as cxv
>>> import coordinax.frames as cxf
>>> import coordinax.transforms as cxfm
>>> from coordinax.astro import ICRS
>>> R = cxfm.Rotate(jnp.asarray([[0., -1, 0], [1, 0, 0], [0, 0, 1]]))
>>> frame1 = cxf.TransformedReferenceFrame(ICRS(), R)

Same frame → identity:

>>> cxf.frame_transition(frame1, frame1)
Identity()
>>> shift = cxfm.Translate.from_([1, 0, 0], "kpc")
>>> frame2 = cxf.TransformedReferenceFrame(frame1, shift)
>>> op1to2 = cxf.frame_transition(frame1, frame2)
>>> q_frame1 = cxv.Point.from_([0, -1, 0], "kpc")
>>> q_frame2 = op1to2(q_frame1)
>>> print(q_frame2)
<Point: chart=Cart3D (x, y, z) [kpc]
    [ 1. -1.  0.]>
coordinax.frames.frame_transition(from_frame: AbstractSpaceFrame, to_frame: AbstractSpaceFrame, /) Composed
Parameters:
Return type:

Any

Compute frame transformations with ICRS as the intermediary.

>>> import plum
>>> import unxt as u
>>> import coordinax.frames as cxf
>>> import coordinax.astro as cxastro
>>> class MySpaceFrame(cxastro.AbstractSpaceFrame):
...     pass
>>> @plum.dispatch
... def frame_transition(from_frame: MySpaceFrame, to_frame: ICRS, /) -> cxfm.AbstractTransform:
...     return cxfm.Rotate.from_euler("z", u.Q(10, "deg"))

We can transform from MySpaceFrame to a Galactocentric frame, even though we don’t have a direct transformation defined:

>>> my_frame = MySpaceFrame()
>>> gcf_frame = cxastro.Galactocentric()
>>> op = cxf.frame_transition(my_frame, gcf_frame)
>>> op
Composed((
  Rotate(f64[3,3](jax)),
  Rotate(f64[3,3](jax)),
  Translate( {...}, chart=Cart3D(M=Rn(3)) ),
  Rotate(f64[3,3](jax))
))
coordinax.frames.frame_transition(from_frame: ICRS, to_frame: ICRS, /) Identity
Parameters:
Return type:

Any

Return an identity operator for the ICRS->ICRS transformation.

>>> import coordinax.frames as cxf
>>> import coordinax.astro as cxastro
>>> icrs_frame = cxastro.ICRS()
>>> frame_op = cxf.frame_transition(icrs_frame, icrs_frame)
>>> frame_op
Identity()
coordinax.frames.frame_transition(from_frame: Galactocentric, to_frame: Galactocentric, /) Composed
Parameters:
Return type:

Any

Return a sequence of operators for the Galactocentric frame self transformation.

>>> import unxt as u
>>> import coordinax.frames as cxf
>>> import coordinax.astro as cxastro
>>> gcf_frame = cxastro.Galactocentric()
>>> frame_op = cxf.frame_transition(gcf_frame, gcf_frame)
>>> frame_op
Composed(Identity())
>>> gcf_frame2 = cxastro.Galactocentric(roll=u.Q(10, "deg"))
>>> frame_op2 = cxf.frame_transition(gcf_frame, gcf_frame2)
>>> frame_op2
Composed((
  Rotate(f64[3,3](jax)),
  Translate( {...}, chart=Cart3D(M=Rn(3)) ),
  Rotate(f64[3,3](jax)),
  Rotate(f64[3,3](jax)),
  Translate( {...}, chart=Cart3D(M=Rn(3)) ),
  Rotate(f64[3,3](jax))
))
coordinax.frames.frame_transition(from_frame: ICRS, to_frame: Galactocentric, /) Composed
Parameters:
Return type:

Any

Return an ICRS to Galactocentric frame transformation operator.

This transformation applies a series of Galilean transformations to convert coordinates from the ICRS frame to a Galactocentric frame. The transformation accounts for:

  1. Rotation to align with the Galactic coordinate system

  2. Translation to the Galactic center

  3. Tilt correction for the Sun’s height above the Galactic plane

  4. Velocity boost to the Galactocentric rest frame

Examples

>>> import unxt as u
>>> import coordinax.main as cx
>>> import coordinax.astro as cxastro

Create the frames:

>>> icrs_frame = cxastro.ICRS()
>>> gcf_frame = cxastro.Galactocentric()

Define the transformation operator:

>>> frame_op = cx.frame_transition(icrs_frame, gcf_frame)
>>> frame_op
Composed((
  Rotate(f64[3,3](jax)),
  Translate( {...}, chart=Cart3D(M=Rn(3)) ),
  Rotate(f64[3,3](jax))
))

Transform a position at the origin of ICRS to Galactocentric:

>>> q = cx.Point.from_([0, 0, 0], "pc")
>>> print(frame_op(q))
<Point: chart=Cart3D (x, y, z) [pc]
    [-8121.973     0.       20.8  ]>

The result shows the Sun’s position in Galactocentric coordinates: the Sun is about 8.1 kpc from the Galactic center along the x-axis and about 21 pc above the Galactic plane.

Works with unxt Quantities too:

>>> q = u.Q([0, 0, 0], "pc")
>>> frame_op(q)
Q([-8121.97336612,     0.        ,    20.8       ], 'pc')

Transform a star position in spherical coordinates:

>>> star_q = cx.Point.from_(
...     {"lon": u.Q(279.23, "deg"), "lat": u.Q(38.78, "deg"),
...      "distance": u.Q(25, "pc")}, cx.lonlat_sph3d)
>>> gcf_q = frame_op(star_q)
>>> gcf_q = gcf_q.cconvert(cx.cart3d)
>>> print(gcf_q)
<Point: chart=Cart3D (x, y, z) [pc]
    [-8112.898    21.798    29.015]>

Notes

The transformation is composed of:

  • R: Combined rotation matrix (longitude x latitude x roll)

  • offset_q: Translation by the Galactic center distance

  • H: Rotation to account for Sun’s height above plane

  • offset_v: Velocity boost to Galactocentric rest frame

The default Galactocentric frame uses parameters from the Astropy default values (as of v4.0), which are based on various literature sources.

coordinax.frames.frame_transition(from_frame: Galactocentric, to_frame: ICRS, /) Composed
Parameters:
Return type:

Any

Return a Galactocentric to ICRS frame transformation operator.

This transformation inverts the ICRS→Galactocentric transformation, converting coordinates from a Galactocentric frame back to ICRS.

Examples

>>> import unxt as u
>>> import coordinax.main as cx
>>> import coordinax.astro as cxastro

Create the frames:

>>> icrs_frame = cxastro.ICRS()
>>> gcf_frame = cxastro.Galactocentric()

Define the transformation operator:

>>> frame_op = cx.frame_transition(gcf_frame, icrs_frame)

Transform from Galactocentric origin to ICRS:

>>> q = cx.Point.from_([0, 0, 0], "pc")
>>> print(frame_op(q).round(0))
<Point: chart=Cart3D (x, y, z) [pc]
    [ -446. -7094. -3930.]>

This shows the Galactic center’s position in ICRS coordinates from the Sun’s perspective.

Works with unxt Quantities:

>>> q = u.Q([0, 0, 0], "pc")
>>> frame_op(q).round(0)
Q([ -446., -7094., -3930.], 'pc')

Transform a star in Galactocentric coordinates back to ICRS:

>>> star_q = cx.Point.from_([-8112.9, 21.8, 29.0], "pc")
>>> icrs_q = frame_op(star_q)
>>> icrs_q = icrs_q.cconvert(cx.lonlat_sph3d)
>>> print(icrs_q.uconvert({u.dimension("angle"): "deg", u.dimension("length"): "pc"}))
<Point: chart=LonLatSpherical3D (lon[deg], lat[deg], distance[pc])
    [-80.728  38.775  24.996]>

Notes

This transformation is implemented by computing the inverse of the ICRS→Galactocentric transformation. The operator pipeline is simplified automatically for computational efficiency.

Parameters:
Return type:

Any

class coordinax.frames.AbstractReferenceFrame#

Bases: Module

Base class for all reference frames.

classmethod from_(cls: type[AbstractReferenceFrame], obj: Any, /)#

Construct a reference frame.

from_(cls: type[AbstractReferenceFrame], obj: Mapping[str, Any], /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from a mapping.

>>> import coordinax.frames as cxf
>>> alice = cxf.Alice.from_({})
>>> alice
Alice()
>>> alex = cxf.Alex.from_({})
>>> print(alex)
Alex()
from_(cls: type[AbstractReferenceFrame], obj: AbstractReferenceFrame, /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from another reference frame.

Raises:

TypeError – If the input object is not a subclass of the target class.

Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Examples

>>> import coordinax.frames as cxf
>>> cxf.AbstractReferenceFrame.from_(cxf.alice) is cxf.alice
True
>>> import coordinax.astro as cxastro
>>> try:
...     cxastro.Galactocentric.from_(cxf.alice)
... except TypeError as e:
...     print(e)
Cannot construct 'Galactocentric' from Alice()
from_(cls: type[ICRS], obj: ICRS, /) ICRS
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.ICRS.

>>> import coordinax.astro as cxastro
>>> from plum import convert
>>> import astropy.coordinates as apyc
>>> apy_frame = apyc.ICRS()
>>> cx_frame = convert(apy_frame, cxastro.ICRS)
>>> isinstance(cx_frame, cxastro.ICRS)
True
>>> cxastro.ICRS.from_(apy_frame)
ICRS()
from_(cls: type[Galactocentric], frame: Galactocentric, /) Galactocentric
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.Galactocentric.

>>> import astropy.coordinates as apyc
>>> import coordinax.frames as cxf
>>> apy_gcf = apyc.Galactocentric()
>>> apy_gcf
<Galactocentric Frame (galcen_coord=<ICRS Coordinate: (ra, dec) in deg
(266.4051, -28.936175)>, galcen_distance=8.122 kpc, galcen_v_sun=(12.9, 245.6, 7.78) km / s, z_sun=20.8 pc, roll=0.0 deg)>
>>> gcf = cxf.Galactocentric.from_(apy_gcf)
>>> gcf
Galactocentric(
  galcen=Point(
    { 'lon': Q(f64[], 'deg'), 'lat': Q(f64[], 'deg'), 'distance': Q(f64[], 'kpc') },
    chart=LonLatSpherical3D(M=Rn(3)), frame=ICRS()
  ),
  roll=Angle(f64[], 'deg'),
  z_sun=Quantity(f64[], 'pc')
)

Checking equality

>>> (gcf.galcen["lon"].ustrip("deg") == apy_gcf.galcen_coord.ra.to_value("deg")
...  and gcf.galcen["lat"].ustrip("deg") == apy_gcf.galcen_coord.dec.to_value("deg")
...  and gcf.galcen["distance"].ustrip("kpc") == apy_gcf.galcen_distance.to_value("kpc") )
Array(True, dtype=bool)
Parameters:
Return type:

AbstractReferenceFrame

transform_to(to_frame: AbstractReferenceFrame, /)#

Make a frame transform operator.

Parameters:

to_frame (AbstractReferenceFrame) – The reference frame to transform to.

Returns:

The operator that transforms coordinates from this frame to to_frame.

Return type:

AbstractTransform

Examples

>>> import coordinax.frames as cxf
>>> op = cxf.alice.transform_to(cxf.alex)
>>> op
Composed(( ... ))
>>> op = cxf.alex.transform_to(cxf.alice)
>>> op
Composed(( ... ))
frame_transition(to_frame: AbstractReferenceFrame, /)#

Backward-compatible alias for {meth}`transform_to`.

Parameters:

to_frame (AbstractReferenceFrame)

Return type:

AbstractTransform

exception coordinax.frames.FrameTransformError#

Bases: Exception

An error occurred during a frame transformation.

add_note()#

Exception.add_note(note) – add a note to the exception

args#
with_traceback()#

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

final class coordinax.frames.NoFrame#

Bases: AbstractReferenceFrame

A null reference frame.

This is a reference frame that cannot be transformed to or from.

Examples

>>> import coordinax.frames as cxf
>>> try:
...     cxf.frame_transition(cxf.noframe, cxf.alice)
... except cxf.FrameTransformError as e:
...     print(e)
Cannot transform from the null frame.
>>> try:
...     cxf.frame_transition(cxf.alice, cxf.noframe)
... except cxf.FrameTransformError as e:
...     print(e)
Cannot transform to the null frame.
frame_transition(to_frame: AbstractReferenceFrame, /)#

Backward-compatible alias for {meth}`transform_to`.

Parameters:

to_frame (AbstractReferenceFrame)

Return type:

AbstractTransform

classmethod from_(cls: type[AbstractReferenceFrame], obj: Any, /)#

Construct a reference frame.

from_(cls: type[AbstractReferenceFrame], obj: Mapping[str, Any], /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from a mapping.

>>> import coordinax.frames as cxf
>>> alice = cxf.Alice.from_({})
>>> alice
Alice()
>>> alex = cxf.Alex.from_({})
>>> print(alex)
Alex()
from_(cls: type[AbstractReferenceFrame], obj: AbstractReferenceFrame, /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from another reference frame.

Raises:

TypeError – If the input object is not a subclass of the target class.

Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Examples

>>> import coordinax.frames as cxf
>>> cxf.AbstractReferenceFrame.from_(cxf.alice) is cxf.alice
True
>>> import coordinax.astro as cxastro
>>> try:
...     cxastro.Galactocentric.from_(cxf.alice)
... except TypeError as e:
...     print(e)
Cannot construct 'Galactocentric' from Alice()
from_(cls: type[ICRS], obj: ICRS, /) ICRS
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.ICRS.

>>> import coordinax.astro as cxastro
>>> from plum import convert
>>> import astropy.coordinates as apyc
>>> apy_frame = apyc.ICRS()
>>> cx_frame = convert(apy_frame, cxastro.ICRS)
>>> isinstance(cx_frame, cxastro.ICRS)
True
>>> cxastro.ICRS.from_(apy_frame)
ICRS()
from_(cls: type[Galactocentric], frame: Galactocentric, /) Galactocentric
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.Galactocentric.

>>> import astropy.coordinates as apyc
>>> import coordinax.frames as cxf
>>> apy_gcf = apyc.Galactocentric()
>>> apy_gcf
<Galactocentric Frame (galcen_coord=<ICRS Coordinate: (ra, dec) in deg
(266.4051, -28.936175)>, galcen_distance=8.122 kpc, galcen_v_sun=(12.9, 245.6, 7.78) km / s, z_sun=20.8 pc, roll=0.0 deg)>
>>> gcf = cxf.Galactocentric.from_(apy_gcf)
>>> gcf
Galactocentric(
  galcen=Point(
    { 'lon': Q(f64[], 'deg'), 'lat': Q(f64[], 'deg'), 'distance': Q(f64[], 'kpc') },
    chart=LonLatSpherical3D(M=Rn(3)), frame=ICRS()
  ),
  roll=Angle(f64[], 'deg'),
  z_sun=Quantity(f64[], 'pc')
)

Checking equality

>>> (gcf.galcen["lon"].ustrip("deg") == apy_gcf.galcen_coord.ra.to_value("deg")
...  and gcf.galcen["lat"].ustrip("deg") == apy_gcf.galcen_coord.dec.to_value("deg")
...  and gcf.galcen["distance"].ustrip("kpc") == apy_gcf.galcen_distance.to_value("kpc") )
Array(True, dtype=bool)
Parameters:
Return type:

AbstractReferenceFrame

transform_to(to_frame: AbstractReferenceFrame, /)#

Make a frame transform operator.

Parameters:

to_frame (AbstractReferenceFrame) – The reference frame to transform to.

Returns:

The operator that transforms coordinates from this frame to to_frame.

Return type:

AbstractTransform

Examples

>>> import coordinax.frames as cxf
>>> op = cxf.alice.transform_to(cxf.alex)
>>> op
Composed(( ... ))
>>> op = cxf.alex.transform_to(cxf.alice)
>>> op
Composed(( ... ))
class coordinax.frames.AbstractTransformedReferenceFrame(base_frame: FrameT, xop: AbstractTransform)#

Bases: AbstractReferenceFrame, Generic[FrameT]

Transformations relative to a base reference frame.

This class represents a reference frame that is defined relative to a base reference frame. The transformation from the base reference frame to this reference frame is stored as an coordinax.operators.AbstractTransform.

```{warning}

The transformation operator ops is the transformation of the points, not a passive re-labeling of coordinates. Frame transitions in coordinax use active semantics: coordinates are transformed by direct application of the operator.

```

Examples

>>> import quaxed.numpy as jnp
>>> import unxt as u
>>> import coordinax.vectors as cxv
>>> import coordinax.frames as cxf
>>> import coordinax.transforms as cxfm
>>> from coordinax.astro import ICRS
>>> R = cxfm.Rotate(jnp.asarray([[0., -1, 0], [1, 0, 0], [0, 0, 1]]))
>>> frame = cxf.TransformedReferenceFrame(ICRS(), R)
>>> frame
TransformedReferenceFrame(base_frame=ICRS(), xop=Rotate(R=f64[3,3]))

Let’s transform a position from the base frame to the transformed frame:

>>> op = cxf.frame_transition(ICRS(), frame)
>>> q_icrs = cxv.Point.from_([1, 0, 0], "kpc")
>>> t = u.Q(1, "Myr")
>>> q_frame = op(t, q_icrs)
>>> print(q_frame)
<Point: chart=Cart3D (x, y, z) [kpc]
    [0. 1. 0.]>
>>> op.inverse(q_frame) == q_icrs
Array(True, dtype=bool)
Parameters:
base_frame: FrameT#

The base reference frame.

xop: AbstractTransform#

The transformation from the base frame to this frame. This is an active transformation. To transform coordinates from base_frame into this frame, apply this operator directly.

frame_transition(to_frame: AbstractReferenceFrame, /)#

Backward-compatible alias for {meth}`transform_to`.

Parameters:

to_frame (AbstractReferenceFrame)

Return type:

AbstractTransform

classmethod from_(cls: type[AbstractReferenceFrame], obj: Any, /)#

Construct a reference frame.

from_(cls: type[AbstractReferenceFrame], obj: Mapping[str, Any], /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from a mapping.

>>> import coordinax.frames as cxf
>>> alice = cxf.Alice.from_({})
>>> alice
Alice()
>>> alex = cxf.Alex.from_({})
>>> print(alex)
Alex()
from_(cls: type[AbstractReferenceFrame], obj: AbstractReferenceFrame, /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from another reference frame.

Raises:

TypeError – If the input object is not a subclass of the target class.

Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Examples

>>> import coordinax.frames as cxf
>>> cxf.AbstractReferenceFrame.from_(cxf.alice) is cxf.alice
True
>>> import coordinax.astro as cxastro
>>> try:
...     cxastro.Galactocentric.from_(cxf.alice)
... except TypeError as e:
...     print(e)
Cannot construct 'Galactocentric' from Alice()
from_(cls: type[ICRS], obj: ICRS, /) ICRS
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.ICRS.

>>> import coordinax.astro as cxastro
>>> from plum import convert
>>> import astropy.coordinates as apyc
>>> apy_frame = apyc.ICRS()
>>> cx_frame = convert(apy_frame, cxastro.ICRS)
>>> isinstance(cx_frame, cxastro.ICRS)
True
>>> cxastro.ICRS.from_(apy_frame)
ICRS()
from_(cls: type[Galactocentric], frame: Galactocentric, /) Galactocentric
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.Galactocentric.

>>> import astropy.coordinates as apyc
>>> import coordinax.frames as cxf
>>> apy_gcf = apyc.Galactocentric()
>>> apy_gcf
<Galactocentric Frame (galcen_coord=<ICRS Coordinate: (ra, dec) in deg
(266.4051, -28.936175)>, galcen_distance=8.122 kpc, galcen_v_sun=(12.9, 245.6, 7.78) km / s, z_sun=20.8 pc, roll=0.0 deg)>
>>> gcf = cxf.Galactocentric.from_(apy_gcf)
>>> gcf
Galactocentric(
  galcen=Point(
    { 'lon': Q(f64[], 'deg'), 'lat': Q(f64[], 'deg'), 'distance': Q(f64[], 'kpc') },
    chart=LonLatSpherical3D(M=Rn(3)), frame=ICRS()
  ),
  roll=Angle(f64[], 'deg'),
  z_sun=Quantity(f64[], 'pc')
)

Checking equality

>>> (gcf.galcen["lon"].ustrip("deg") == apy_gcf.galcen_coord.ra.to_value("deg")
...  and gcf.galcen["lat"].ustrip("deg") == apy_gcf.galcen_coord.dec.to_value("deg")
...  and gcf.galcen["distance"].ustrip("kpc") == apy_gcf.galcen_distance.to_value("kpc") )
Array(True, dtype=bool)
Parameters:
Return type:

AbstractReferenceFrame

transform_to(to_frame: AbstractReferenceFrame, /)#

Make a frame transform operator.

Parameters:

to_frame (AbstractReferenceFrame) – The reference frame to transform to.

Returns:

The operator that transforms coordinates from this frame to to_frame.

Return type:

AbstractTransform

Examples

>>> import coordinax.frames as cxf
>>> op = cxf.alice.transform_to(cxf.alex)
>>> op
Composed(( ... ))
>>> op = cxf.alex.transform_to(cxf.alice)
>>> op
Composed(( ... ))
final class coordinax.frames.TransformedReferenceFrame(base_frame: FrameT, xop: AbstractTransform)#

Bases: AbstractTransformedReferenceFrame[FrameT]

Transformations relative to a base reference frame.

This class represents a reference frame that is defined relative to a base reference frame. The transformation from the base reference frame to this reference frame is stored as an coordinax.operators.AbstractTransform.

```{warning}

The transformation operator ops is the transformation of the points, not a passive re-labeling of coordinates. Frame transitions in coordinax use active semantics: coordinates are transformed by direct application of the operator.

```

Examples

>>> import quaxed.numpy as jnp
>>> import unxt as u
>>> import coordinax.vectors as cxv
>>> import coordinax.frames as cxf
>>> import coordinax.transforms as cxfm
>>> from coordinax.astro import ICRS
>>> R = cxfm.Rotate(jnp.asarray([[0., -1, 0], [1, 0, 0], [0, 0, 1]]))
>>> frame = cxf.TransformedReferenceFrame(ICRS(), R)
>>> frame
TransformedReferenceFrame(base_frame=ICRS(), xop=Rotate(R=f64[3,3]))

Let’s transform a position from the base frame to the transformed frame:

>>> op = cxf.frame_transition(ICRS(), frame)
>>> q_icrs = cxv.Point.from_([1, 0, 0], "kpc")
>>> t = u.Q(1, "Myr")
>>> q_frame = op(t, q_icrs)
>>> print(q_frame)
<Point: chart=Cart3D (x, y, z) [kpc]
    [0. 1. 0.]>
>>> op.inverse(q_frame) == q_icrs
Array(True, dtype=bool)
Parameters:
base_frame: FrameT#

The base reference frame.

xop: AbstractTransform#

The transformation from the base frame to this frame. This is an active transformation. To transform coordinates from base_frame into this frame, apply this operator directly.

frame_transition(to_frame: AbstractReferenceFrame, /)#

Backward-compatible alias for {meth}`transform_to`.

Parameters:

to_frame (AbstractReferenceFrame)

Return type:

AbstractTransform

classmethod from_(cls: type[AbstractReferenceFrame], obj: Any, /)#

Construct a reference frame.

from_(cls: type[AbstractReferenceFrame], obj: Mapping[str, Any], /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from a mapping.

>>> import coordinax.frames as cxf
>>> alice = cxf.Alice.from_({})
>>> alice
Alice()
>>> alex = cxf.Alex.from_({})
>>> print(alex)
Alex()
from_(cls: type[AbstractReferenceFrame], obj: AbstractReferenceFrame, /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from another reference frame.

Raises:

TypeError – If the input object is not a subclass of the target class.

Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Examples

>>> import coordinax.frames as cxf
>>> cxf.AbstractReferenceFrame.from_(cxf.alice) is cxf.alice
True
>>> import coordinax.astro as cxastro
>>> try:
...     cxastro.Galactocentric.from_(cxf.alice)
... except TypeError as e:
...     print(e)
Cannot construct 'Galactocentric' from Alice()
from_(cls: type[ICRS], obj: ICRS, /) ICRS
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.ICRS.

>>> import coordinax.astro as cxastro
>>> from plum import convert
>>> import astropy.coordinates as apyc
>>> apy_frame = apyc.ICRS()
>>> cx_frame = convert(apy_frame, cxastro.ICRS)
>>> isinstance(cx_frame, cxastro.ICRS)
True
>>> cxastro.ICRS.from_(apy_frame)
ICRS()
from_(cls: type[Galactocentric], frame: Galactocentric, /) Galactocentric
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.Galactocentric.

>>> import astropy.coordinates as apyc
>>> import coordinax.frames as cxf
>>> apy_gcf = apyc.Galactocentric()
>>> apy_gcf
<Galactocentric Frame (galcen_coord=<ICRS Coordinate: (ra, dec) in deg
(266.4051, -28.936175)>, galcen_distance=8.122 kpc, galcen_v_sun=(12.9, 245.6, 7.78) km / s, z_sun=20.8 pc, roll=0.0 deg)>
>>> gcf = cxf.Galactocentric.from_(apy_gcf)
>>> gcf
Galactocentric(
  galcen=Point(
    { 'lon': Q(f64[], 'deg'), 'lat': Q(f64[], 'deg'), 'distance': Q(f64[], 'kpc') },
    chart=LonLatSpherical3D(M=Rn(3)), frame=ICRS()
  ),
  roll=Angle(f64[], 'deg'),
  z_sun=Quantity(f64[], 'pc')
)

Checking equality

>>> (gcf.galcen["lon"].ustrip("deg") == apy_gcf.galcen_coord.ra.to_value("deg")
...  and gcf.galcen["lat"].ustrip("deg") == apy_gcf.galcen_coord.dec.to_value("deg")
...  and gcf.galcen["distance"].ustrip("kpc") == apy_gcf.galcen_distance.to_value("kpc") )
Array(True, dtype=bool)
Parameters:
Return type:

AbstractReferenceFrame

transform_to(to_frame: AbstractReferenceFrame, /)#

Make a frame transform operator.

Parameters:

to_frame (AbstractReferenceFrame) – The reference frame to transform to.

Returns:

The operator that transforms coordinates from this frame to to_frame.

Return type:

AbstractTransform

Examples

>>> import coordinax.frames as cxf
>>> op = cxf.alice.transform_to(cxf.alex)
>>> op
Composed(( ... ))
>>> op = cxf.alex.transform_to(cxf.alice)
>>> op
Composed(( ... ))
final class coordinax.frames.Alice#

Bases: AbstractReferenceFrame

A stationary lab reference frame at the origin.

Alice serves as the “home” reference frame for the example frame system. Her frame is fixed at the origin with standard (Cartesian) orientation. All other example frames — Alex and Bob — are defined by their transformations relative to Alice.

Frame relationships:

  • Alice → Alex: translate +10 m along Alice’s x-axis, then rotate +90 ° about the z-axis.

  • Alice → Bob: translate [100 000 km, 10 000 km, 0] from Alice’s origin, then apply a Galilean velocity boost of ≈ 269 813 km s⁻¹ (≈ 0.9 c) along Alice’s x-axis.

Examples

>>> import coordinax.frames as cxf
>>> import jax

Identity transition back to Alice’s own frame:

>>> cxf.frame_transition(cxf.alice, cxf.alice)
Identity()

Transition to Alex’s frame (translate then rotate):

>>> op = cxf.frame_transition(cxf.alice, cxf.alex)
>>> print(jax.tree.map(lambda x: x.round(2), op))
Composed((
  Translate({'x': Q(10, 'm'), 'y': Q(0, 'm'), 'z': Q(0, 'm')},
            chart=Cart3D(M=Rn(3))),
  Rotate([[ 0. -1.  0.]
          [ 1.  0.  0.]
          [ 0.  0.  1.]])
))
frame_transition(to_frame: AbstractReferenceFrame, /)#

Backward-compatible alias for {meth}`transform_to`.

Parameters:

to_frame (AbstractReferenceFrame)

Return type:

AbstractTransform

classmethod from_(cls: type[AbstractReferenceFrame], obj: Any, /)#

Construct a reference frame.

from_(cls: type[AbstractReferenceFrame], obj: Mapping[str, Any], /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from a mapping.

>>> import coordinax.frames as cxf
>>> alice = cxf.Alice.from_({})
>>> alice
Alice()
>>> alex = cxf.Alex.from_({})
>>> print(alex)
Alex()
from_(cls: type[AbstractReferenceFrame], obj: AbstractReferenceFrame, /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from another reference frame.

Raises:

TypeError – If the input object is not a subclass of the target class.

Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Examples

>>> import coordinax.frames as cxf
>>> cxf.AbstractReferenceFrame.from_(cxf.alice) is cxf.alice
True
>>> import coordinax.astro as cxastro
>>> try:
...     cxastro.Galactocentric.from_(cxf.alice)
... except TypeError as e:
...     print(e)
Cannot construct 'Galactocentric' from Alice()
from_(cls: type[ICRS], obj: ICRS, /) ICRS
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.ICRS.

>>> import coordinax.astro as cxastro
>>> from plum import convert
>>> import astropy.coordinates as apyc
>>> apy_frame = apyc.ICRS()
>>> cx_frame = convert(apy_frame, cxastro.ICRS)
>>> isinstance(cx_frame, cxastro.ICRS)
True
>>> cxastro.ICRS.from_(apy_frame)
ICRS()
from_(cls: type[Galactocentric], frame: Galactocentric, /) Galactocentric
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.Galactocentric.

>>> import astropy.coordinates as apyc
>>> import coordinax.frames as cxf
>>> apy_gcf = apyc.Galactocentric()
>>> apy_gcf
<Galactocentric Frame (galcen_coord=<ICRS Coordinate: (ra, dec) in deg
(266.4051, -28.936175)>, galcen_distance=8.122 kpc, galcen_v_sun=(12.9, 245.6, 7.78) km / s, z_sun=20.8 pc, roll=0.0 deg)>
>>> gcf = cxf.Galactocentric.from_(apy_gcf)
>>> gcf
Galactocentric(
  galcen=Point(
    { 'lon': Q(f64[], 'deg'), 'lat': Q(f64[], 'deg'), 'distance': Q(f64[], 'kpc') },
    chart=LonLatSpherical3D(M=Rn(3)), frame=ICRS()
  ),
  roll=Angle(f64[], 'deg'),
  z_sun=Quantity(f64[], 'pc')
)

Checking equality

>>> (gcf.galcen["lon"].ustrip("deg") == apy_gcf.galcen_coord.ra.to_value("deg")
...  and gcf.galcen["lat"].ustrip("deg") == apy_gcf.galcen_coord.dec.to_value("deg")
...  and gcf.galcen["distance"].ustrip("kpc") == apy_gcf.galcen_distance.to_value("kpc") )
Array(True, dtype=bool)
Parameters:
Return type:

AbstractReferenceFrame

transform_to(to_frame: AbstractReferenceFrame, /)#

Make a frame transform operator.

Parameters:

to_frame (AbstractReferenceFrame) – The reference frame to transform to.

Returns:

The operator that transforms coordinates from this frame to to_frame.

Return type:

AbstractTransform

Examples

>>> import coordinax.frames as cxf
>>> op = cxf.alice.transform_to(cxf.alex)
>>> op
Composed(( ... ))
>>> op = cxf.alex.transform_to(cxf.alice)
>>> op
Composed(( ... ))
final class coordinax.frames.Alex#

Bases: AbstractReferenceFrame

A reference frame displaced and rotated relative to Alice’s frame.

Alex is an observer who is stationary (like Alice) but occupies a different location and orientation in space:

  • Origin: +10 m along Alice’s x-axis.

  • Orientation: rotated +90 ° about the shared z-axis relative to Alice, so what Alice calls her y-axis points along Alex’s x-axis.

The transformation Alice → Alex is therefore a translate-then-rotate composition:

Alice → Alex:  Translate([10, 0, 0] m) | Rotate(Z, +90°)
Alex → Alice:  Rotate(Z, -90°) | Translate([-10, 0, 0] m)

Examples

>>> import coordinax.frames as cxf

Identity transition within Alex’s own frame:

>>> cxf.frame_transition(cxf.alex, cxf.alex)
Identity()
frame_transition(to_frame: AbstractReferenceFrame, /)#

Backward-compatible alias for {meth}`transform_to`.

Parameters:

to_frame (AbstractReferenceFrame)

Return type:

AbstractTransform

classmethod from_(cls: type[AbstractReferenceFrame], obj: Any, /)#

Construct a reference frame.

from_(cls: type[AbstractReferenceFrame], obj: Mapping[str, Any], /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from a mapping.

>>> import coordinax.frames as cxf
>>> alice = cxf.Alice.from_({})
>>> alice
Alice()
>>> alex = cxf.Alex.from_({})
>>> print(alex)
Alex()
from_(cls: type[AbstractReferenceFrame], obj: AbstractReferenceFrame, /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from another reference frame.

Raises:

TypeError – If the input object is not a subclass of the target class.

Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Examples

>>> import coordinax.frames as cxf
>>> cxf.AbstractReferenceFrame.from_(cxf.alice) is cxf.alice
True
>>> import coordinax.astro as cxastro
>>> try:
...     cxastro.Galactocentric.from_(cxf.alice)
... except TypeError as e:
...     print(e)
Cannot construct 'Galactocentric' from Alice()
from_(cls: type[ICRS], obj: ICRS, /) ICRS
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.ICRS.

>>> import coordinax.astro as cxastro
>>> from plum import convert
>>> import astropy.coordinates as apyc
>>> apy_frame = apyc.ICRS()
>>> cx_frame = convert(apy_frame, cxastro.ICRS)
>>> isinstance(cx_frame, cxastro.ICRS)
True
>>> cxastro.ICRS.from_(apy_frame)
ICRS()
from_(cls: type[Galactocentric], frame: Galactocentric, /) Galactocentric
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.Galactocentric.

>>> import astropy.coordinates as apyc
>>> import coordinax.frames as cxf
>>> apy_gcf = apyc.Galactocentric()
>>> apy_gcf
<Galactocentric Frame (galcen_coord=<ICRS Coordinate: (ra, dec) in deg
(266.4051, -28.936175)>, galcen_distance=8.122 kpc, galcen_v_sun=(12.9, 245.6, 7.78) km / s, z_sun=20.8 pc, roll=0.0 deg)>
>>> gcf = cxf.Galactocentric.from_(apy_gcf)
>>> gcf
Galactocentric(
  galcen=Point(
    { 'lon': Q(f64[], 'deg'), 'lat': Q(f64[], 'deg'), 'distance': Q(f64[], 'kpc') },
    chart=LonLatSpherical3D(M=Rn(3)), frame=ICRS()
  ),
  roll=Angle(f64[], 'deg'),
  z_sun=Quantity(f64[], 'pc')
)

Checking equality

>>> (gcf.galcen["lon"].ustrip("deg") == apy_gcf.galcen_coord.ra.to_value("deg")
...  and gcf.galcen["lat"].ustrip("deg") == apy_gcf.galcen_coord.dec.to_value("deg")
...  and gcf.galcen["distance"].ustrip("kpc") == apy_gcf.galcen_distance.to_value("kpc") )
Array(True, dtype=bool)
Parameters:
Return type:

AbstractReferenceFrame

transform_to(to_frame: AbstractReferenceFrame, /)#

Make a frame transform operator.

Parameters:

to_frame (AbstractReferenceFrame) – The reference frame to transform to.

Returns:

The operator that transforms coordinates from this frame to to_frame.

Return type:

AbstractTransform

Examples

>>> import coordinax.frames as cxf
>>> op = cxf.alice.transform_to(cxf.alex)
>>> op
Composed(( ... ))
>>> op = cxf.alex.transform_to(cxf.alice)
>>> op
Composed(( ... ))
final class coordinax.frames.Bob#

Bases: AbstractReferenceFrame

An inertial frame moving at constant velocity relative to Alice.

Bob is a non-rotating observer in uniform motion with respect to Alice. His frame is characterised by:

  • Spatial offset from Alice’s origin: [100 000 km, 10 000 km, 0 km].

  • Velocity relative to Alice: ≈ 269 813 km s⁻¹ (≈ 0.9 c) along Alice’s x-axis.

Because Bob is non-rotating, no rotation operator is required; the transformation only needs a spatial translation and a Galilean boost.

Examples

>>> import coordinax.frames as cxf

Identity transition within Bob’s own frame:

>>> cxf.frame_transition(cxf.bob, cxf.bob)
Identity()

Transition from Alice’s frame to Bob’s frame (translate then boost):

>>> op = cxf.frame_transition(cxf.alice, cxf.bob)
>>> print(op)
Composed((
  Translate( {...}, chart=Cart3D(M=Rn(3)) ),
  Boost( {...}, chart=Cart3D(M=Rn(3)) )
))

Applying the Alice -> Bob transform to a bare array is not supported, because the boost cannot infer whether the array represents a position or a velocity:

>>> import jax.numpy as jnp
>>> import unxt as u
>>> import coordinax.transforms as cxfm
>>> x = jnp.asarray([0.0, 0.0, 0.0])
>>> cxfm.act(
...     op, None, x, usys=u.unitsystems.si
... )
Traceback (most recent call last):
plum._resolver.NotFoundLookupError: ...

Applying the Alice -> Bob transform to a Quantity works:

>>> q = u.Q([0.0, 0.0, 0.0], "km")
>>> op(None, q)
Q([100000.,  10000.,      0.], 'km')

Applying the same transform to a component dictionary (cdict) also works:

>>> import coordinax.main as cx
>>> d = cx.cdict(u.Q([0.0, 0.0, 0.0], "km"))
>>> op(None, d)
{'x': Q(100000., 'km'), 'y': Q(10000., 'km'), 'z': Q(0., 'km')}
frame_transition(to_frame: AbstractReferenceFrame, /)#

Backward-compatible alias for {meth}`transform_to`.

Parameters:

to_frame (AbstractReferenceFrame)

Return type:

AbstractTransform

classmethod from_(cls: type[AbstractReferenceFrame], obj: Any, /)#

Construct a reference frame.

from_(cls: type[AbstractReferenceFrame], obj: Mapping[str, Any], /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from a mapping.

>>> import coordinax.frames as cxf
>>> alice = cxf.Alice.from_({})
>>> alice
Alice()
>>> alex = cxf.Alex.from_({})
>>> print(alex)
Alex()
from_(cls: type[AbstractReferenceFrame], obj: AbstractReferenceFrame, /) AbstractReferenceFrame
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct a reference frame from another reference frame.

Raises:

TypeError – If the input object is not a subclass of the target class.

Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Examples

>>> import coordinax.frames as cxf
>>> cxf.AbstractReferenceFrame.from_(cxf.alice) is cxf.alice
True
>>> import coordinax.astro as cxastro
>>> try:
...     cxastro.Galactocentric.from_(cxf.alice)
... except TypeError as e:
...     print(e)
Cannot construct 'Galactocentric' from Alice()
from_(cls: type[ICRS], obj: ICRS, /) ICRS
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.ICRS.

>>> import coordinax.astro as cxastro
>>> from plum import convert
>>> import astropy.coordinates as apyc
>>> apy_frame = apyc.ICRS()
>>> cx_frame = convert(apy_frame, cxastro.ICRS)
>>> isinstance(cx_frame, cxastro.ICRS)
True
>>> cxastro.ICRS.from_(apy_frame)
ICRS()
from_(cls: type[Galactocentric], frame: Galactocentric, /) Galactocentric
Parameters:

obj (Any)

Return type:

AbstractReferenceFrame

Construct from a astropy.coordinates.Galactocentric.

>>> import astropy.coordinates as apyc
>>> import coordinax.frames as cxf
>>> apy_gcf = apyc.Galactocentric()
>>> apy_gcf
<Galactocentric Frame (galcen_coord=<ICRS Coordinate: (ra, dec) in deg
(266.4051, -28.936175)>, galcen_distance=8.122 kpc, galcen_v_sun=(12.9, 245.6, 7.78) km / s, z_sun=20.8 pc, roll=0.0 deg)>
>>> gcf = cxf.Galactocentric.from_(apy_gcf)
>>> gcf
Galactocentric(
  galcen=Point(
    { 'lon': Q(f64[], 'deg'), 'lat': Q(f64[], 'deg'), 'distance': Q(f64[], 'kpc') },
    chart=LonLatSpherical3D(M=Rn(3)), frame=ICRS()
  ),
  roll=Angle(f64[], 'deg'),
  z_sun=Quantity(f64[], 'pc')
)

Checking equality

>>> (gcf.galcen["lon"].ustrip("deg") == apy_gcf.galcen_coord.ra.to_value("deg")
...  and gcf.galcen["lat"].ustrip("deg") == apy_gcf.galcen_coord.dec.to_value("deg")
...  and gcf.galcen["distance"].ustrip("kpc") == apy_gcf.galcen_distance.to_value("kpc") )
Array(True, dtype=bool)
Parameters:
Return type:

AbstractReferenceFrame

transform_to(to_frame: AbstractReferenceFrame, /)#

Make a frame transform operator.

Parameters:

to_frame (AbstractReferenceFrame) – The reference frame to transform to.

Returns:

The operator that transforms coordinates from this frame to to_frame.

Return type:

AbstractTransform

Examples

>>> import coordinax.frames as cxf
>>> op = cxf.alice.transform_to(cxf.alex)
>>> op
Composed(( ... ))
>>> op = cxf.alex.transform_to(cxf.alice)
>>> op
Composed(( ... ))