Skip to content

Trajectory

trajectory

Trajectory

Trajectory(
    positions: Positions,
    rotations: Rotations | None = None,
    timestamps: ndarray | None = None,
    name: str = "",
    path_lengths: ndarray | None = None,
    velocity_xyz: ndarray | None = None,
    sorting: Sorting = TIME,
)

Class representing a trajectory containing synchronized position, orientation, and time data.

Attributes:

  • positions (Positions) –

    Container for spatial coordinates and coordinate reference system (EPSG) data.

  • rotations (Rotations) –

    Container for orientation data (quaternions), or None if not provided.

  • timestamps (ndarray) –

    A 1D array of timestamps corresponding to each pose.

  • name (str) –

    An identifier string for the trajectory.

  • path_lengths (ndarray) –

    A 1D array of cumulative path lengths starting from zero.

  • sorting (Sorting) –

    The current sorting strategy (Sorting.TIME or Sorting.ARC_LENGTH).

Initialize a Trajectory object.

Parameters:

  • positions (Positions) –

    Container for spatial coordinates and coordinate reference system (EPSG) data.

  • rotations (Rotations | None, default: None ) –

    Container for orientation data (quaternions). Defaults to None.

  • timestamps (ndarray | None, default: None ) –

    Array of timestamps. If None, a range index is used.

  • name (str, default: '' ) –

    Name of the trajectory. Defaults to generic counter name.

  • path_lengths (Union[ndarray, None], default: None ) –

    Pre-calculated path lengths. If None, they are computed from xyz.

  • velocity_xyz (Union[ndarray, None], default: None ) –

    Pre-calculated 3D velocities. If None, they are computed via gradient.

  • sorting (Sorting, default: TIME ) –

    Definition of the sorting logic (TIME or ARC_LENGTH). Defaults to Sorting.TIME.

Raises:

  • TrajectoryError –

    If the number of positions and rotations or timestamps do not match.

Source code in trajectopy\core\trajectory.py
def __init__(
    self,
    positions: Positions,
    rotations: Rotations | None = None,
    timestamps: np.ndarray | None = None,
    name: str = "",
    path_lengths: np.ndarray | None = None,
    velocity_xyz: np.ndarray | None = None,
    sorting: Sorting = Sorting.TIME,
) -> None:
    """
    Initialize a Trajectory object.

    Args:
        positions (Positions): Container for spatial coordinates and coordinate reference system (EPSG) data.
        rotations (Rotations | None, optional): Container for orientation data (quaternions). Defaults to None.
        timestamps (np.ndarray | None, optional): Array of timestamps. If None, a range index is used.
        name (str, optional): Name of the trajectory. Defaults to generic counter name.
        path_lengths (Union[np.ndarray, None], optional): Pre-calculated path lengths. If None, they are computed from xyz.
        velocity_xyz (Union[np.ndarray, None], optional): Pre-calculated 3D velocities. If None, they are computed via gradient.
        sorting (Sorting, optional): Definition of the sorting logic (TIME or ARC_LENGTH). Defaults to Sorting.TIME.

    Raises:
        TrajectoryError: If the number of positions and rotations or timestamps do not match.
    """
    # check dimensions
    if rotations is not None and len(positions) != len(rotations):
        raise TrajectoryError(
            f"Number of positions ({len(positions)}) and rotations ({len(rotations)}) do not match!"
        )

    self._sorting = sorting

    # pose
    self.positions = positions
    self.rotations = rotations

    # float, since timestamps are shifted and interpolated
    self.timestamps = (
        np.arange(0, len(positions), dtype=float) if timestamps is None else np.asarray(timestamps, dtype=float)
    )

    num_poses = len(self.timestamps)
    if num_poses != len(positions):
        raise TrajectoryError(f"Number of positions ({len(positions)}) and timestamps ({num_poses}) do not match!")
    velocity_xyz = (
        np.asarray(velocity_xyz) if velocity_xyz is not None and len(velocity_xyz) == num_poses else None
    )
    path_lengths = (
        np.asarray(path_lengths) if path_lengths is not None and len(path_lengths) == num_poses else None
    )

    # velocities and path lengths are derived from consecutive poses, so the data has to be in chronological
    # order with strictly increasing timestamps first
    chronological = np.argsort(self.timestamps, kind="stable")
    first_of_epoch = chronological[np.diff(self.timestamps[chronological], prepend=np.nan) != 0]

    if len(first_of_epoch) != num_poses:
        logger.warning(
            "Timestamps contain duplicates. Only the first occurrence of each unique timestamp will be kept. "
            "This may lead to loss of data if duplicates are present."
        )

    if not np.array_equal(first_of_epoch, np.arange(num_poses)):
        self.timestamps = self.timestamps[first_of_epoch]
        self.positions.xyz = self.positions.xyz[first_of_epoch, :]

        if self.rotations is not None:
            self.rotations = Rotations.from_quat(self.rotations.as_quat()[first_of_epoch, :])
        if velocity_xyz is not None:
            velocity_xyz = velocity_xyz[first_of_epoch]
        if path_lengths is not None:
            path_lengths = path_lengths[first_of_epoch]

    if velocity_xyz is not None and len(velocity_xyz) == len(self.positions):
        self._velocity_xyz = velocity_xyz
    else:
        self._velocity_xyz = gradient_3d(xyz=self.positions.xyz, tstamps=self.timestamps)
        logger.info("Speeds were not provided or had wrong dimensions. Speeds were computed instead.")

    if path_lengths is not None and len(path_lengths) == len(self.positions):
        self.path_lengths = path_lengths
    else:
        self.path_lengths = self.init_path_lengths()
        logger.info("Path lengths were not provided or had wrong dimensions. Path lengths were computed instead.")

    self.name = name or f"Trajectory {Trajectory._counter}"

    # Sort data according to initial sorting strategy
    self._apply_sorting()

    Trajectory._counter += 1

has_orientation property

has_orientation: bool

Returns True if valid rotation data is available.

is_unix_time property

is_unix_time: bool

Checks if the supplied trajectory has (likely) unix timestamps as seconds.

total_length property

total_length: float

Returns the total cumulative path length of the trajectory in meters.

sorting property

sorting: Sorting

Returns the current sorting strategy (read-only).

To change sorting, use set_sorting() which physically reorders the data.

index property

index: ndarray

Returns the independent variable currently parameterizing the trajectory. This is either the Timestamp vector or the Path Length vector, depending on self.sorting.

datetimes property

datetimes: ndarray

Returns the timestamps as an array of datetime64[ns] values (interpreted as seconds since epoch).

index_unit property

index_unit: str

Returns the unit string of the current index ('s' for Time, 'm' for Path Length).

index_label property

index_label: str

Returns the label string of the current index (e.g., 'time [s]').

data_rate property

data_rate: float

Calculates the average data rate (frequency in Hz) based on timestamp differences.

velocity_xyz property writable

velocity_xyz: ndarray

Returns the 3D velocity vectors. If not set manually, they are computed via gradient of the positions over time.

absolute_velocity property

absolute_velocity: ndarray

Returns the norm (magnitude) of the 3D velocity vectors.

xyz property

xyz: ndarray

Returns the XYZ coordinates.

Since trajectory data is always stored in sorted order (by time or arc length), this is equivalent to self.positions.xyz.

quat property

quat: ndarray

Returns the quaternions. Returns zeros if no rotations are present.

rpy property

rpy: ndarray

Returns the Roll-Pitch-Yaw angles (in radians).

se3 property writable

se3: list[ndarray]

Returns a list of SE3 poses (4x4 homogeneous transformation matrices).

time_start property

time_start: float

Returns the minimum timestamp of the trajectory.

time_end property

time_end: float

Returns the maximum timestamp of the trajectory.

from_file classmethod

from_file(
    filename: str, io_stream: bool = False
) -> Trajectory

Create a trajectory instance from a file.

The file is expected to be a CSV-like format. It handles extraction of timestamps, xyz positions, rotations, path lengths, and velocities via ascii trajectory reader.

Parameters:

  • filename (str) –

    Path to the file or string content if io_stream is True.

  • io_stream (bool, default: False ) –

    If True, filename is treated as the raw string content of the file/stream. Defaults to False.

Returns:

  • Trajectory ( Trajectory ) –

    The loaded trajectory object.

Source code in trajectopy\core\trajectory.py
@classmethod
def from_file(cls, filename: str, io_stream: bool = False) -> "Trajectory":
    """
    Create a trajectory instance from a file.

    The file is expected to be a CSV-like format. It handles extraction of
    timestamps, xyz positions, rotations, path lengths, and velocities via `ascii` trajectory reader.

    Args:
        filename (str): Path to the file or string content if io_stream is True.
        io_stream (bool, optional): If True, `filename` is treated as the raw string content
                                    of the file/stream. Defaults to False.

    Returns:
        Trajectory: The loaded trajectory object.
    """
    from trajectopy.io.trajectory_io import read_trajectory, read_trajectory_string

    return read_trajectory_string(filename) if io_stream else read_trajectory(filename)

from_arrays classmethod

from_arrays(
    xyz: ndarray,
    quat: ndarray | None = None,
    rpy: ndarray | None = None,
    epsg: int = 0,
    **kwargs: Any,
) -> Trajectory

Creates a trajectory from numpy arrays.

Parameters:

  • xyz (ndarray) –

    Positions, shape (N, 3).

  • quat (ndarray | None, default: None ) –

    Orientations as quaternions (x, y, z, w), shape (N, 4).

  • rpy (ndarray | None, default: None ) –

    Orientations as Euler angles (roll, pitch, yaw) in radians, shape (N, 3). Provide either quat or rpy.

  • epsg (int, default: 0 ) –

    EPSG code of the positions. 0 means a local, unknown system. Defaults to 0.

  • **kwargs (Any, default: {} ) –

    Further arguments of the constructor, e.g. timestamps and name.

Returns:

  • Trajectory ( Trajectory ) –

    The new trajectory.

Source code in trajectopy\core\trajectory.py
@classmethod
def from_arrays(
    cls,
    xyz: np.ndarray,
    quat: np.ndarray | None = None,
    rpy: np.ndarray | None = None,
    epsg: int = 0,
    **kwargs: Any,
) -> "Trajectory":
    """Creates a trajectory from numpy arrays.

    Args:
        xyz (np.ndarray): Positions, shape (N, 3).
        quat (np.ndarray | None, optional): Orientations as quaternions (x, y, z, w), shape (N, 4).
        rpy (np.ndarray | None, optional): Orientations as Euler angles (roll, pitch, yaw) in radians,
            shape (N, 3). Provide either ``quat`` or ``rpy``.
        epsg (int, optional): EPSG code of the positions. 0 means a local, unknown system. Defaults to 0.
        **kwargs: Further arguments of the constructor, e.g. ``timestamps`` and ``name``.

    Returns:
        Trajectory: The new trajectory.
    """

    pos_obj = Positions(xyz=xyz, epsg=epsg)

    rot_obj = None
    if quat is not None and rpy is not None:
        raise TrajectoryError("Provide quat OR rpy, not both.")

    if quat is not None:
        rot_obj = Rotations.from_quat(quat)
    elif rpy is not None:
        rot_obj = Rotations.from_euler(seq="xyz", angles=rpy)

    return cls(positions=pos_obj, rotations=rot_obj, **kwargs)

__str__

__str__() -> str

Returns a formatted string summary of the trajectory, including name, length, EPSG, and data rate.

Source code in trajectopy\core\trajectory.py
def __str__(self) -> str:
    """
    Returns a formatted string summary of the trajectory, including name, length, EPSG, and data rate.
    """
    width = 24
    return (
        f"\n _______________________________________________________\n"
        f"| ------------------ Trajectory Info ------------------ |\n"
        f"| Name:                         {self.name:<{width}}|\n"
        f"| Number of poses:              {len(self):<{width}}|\n"
        f"| Orientation available:        {'yes' if self.has_orientation else 'no':<{width}}|\n"
        f"| EPSG:                         {self.positions.epsg:<{width}}|\n"
        f"| Length [m]:                   {self.total_length:<{width}.3f}|\n"
        f"| Data rate [Hz]:               {self.data_rate:<{width}.3f}|\n"
        f"| Function of:                  {self.index_label:<{width}}|\n"
        f"|_______________________________________________________|\n"
    )

__len__

__len__() -> int

Returns the number of poses in the trajectory.

Source code in trajectopy\core\trajectory.py
def __len__(self) -> int:
    """Returns the number of poses in the trajectory."""
    return len(self.positions.xyz)

__iter__

__iter__() -> Iterator[Pose]

Iterates over the trajectory, yielding a pose for each timestamp.

Yields:

  • Pose ( Pose ) –

    A Pose instance for each timestamp.

Source code in trajectopy\core\trajectory.py
def __iter__(self) -> Iterator[Pose]:
    """
    Iterates over the trajectory, yielding a pose for each timestamp.

    Yields:
        Pose: A Pose instance for each timestamp.
    """
    rpy = self.rpy if self.has_orientation else np.zeros((len(self), 3))
    for t, l, pos, rot, velocity in zip(self.timestamps, self.path_lengths, self.xyz, rpy, self.velocity_xyz):
        yield Pose(
            timestamp=t,
            path_length=l,
            position=(pos[0], pos[1], pos[2]),
            rpy=(rot[0], rot[1], rot[2]),
            velocity=velocity,
            epsg=self.positions.epsg,
        )

__eq__

__eq__(other: object) -> bool

Checks equality between two trajectories using np.allclose for numerical arrays. Compares positions, rotations, timestamps, path lengths, velocities, and names.

Source code in trajectopy\core\trajectory.py
def __eq__(self, other: object) -> bool:
    """
    Checks equality between two trajectories using `np.allclose` for numerical arrays.
    Compares positions, rotations, timestamps, path lengths, velocities, and names.
    """
    if not isinstance(other, Trajectory):
        return NotImplemented

    if len(self) != len(other):
        return False

    if self.rotations is not None and other.rotations is not None:
        rot_equal = np.allclose(self.rotations.as_quat(), other.rotations.as_quat())
    elif self.rotations is None and other.rotations is None:
        rot_equal = True
    else:
        rot_equal = False

    return (
        np.allclose(self.positions.xyz, other.positions.xyz)
        and rot_equal
        and np.allclose(self.timestamps, other.timestamps)
        and np.allclose(self.path_lengths, other.path_lengths)
        and np.allclose(self._velocity_xyz, other._velocity_xyz)
        and self.name == other.name
    )

copy

copy() -> Trajectory

Returns a deep copy of the trajectory instance.

Source code in trajectopy\core\trajectory.py
def copy(self) -> "Trajectory":
    """Returns a deep copy of the trajectory instance."""
    return copy.deepcopy(self)

init_path_lengths

init_path_lengths()

Computes cumulative path lengths based on Euclidean distances between consecutive local coordinates.

Source code in trajectopy\core\trajectory.py
def init_path_lengths(self):
    """Computes cumulative path lengths based on Euclidean distances between consecutive local coordinates."""
    if len(self.positions) == 0:
        return np.array([])  # without positions, there is no local frame either
    return lengths_from_xyz(self.positions.to_local(inplace=False).xyz)

set_sorting

set_sorting(sorting: Sorting) -> None

Changes the sorting strategy and physically reorders all trajectory data.

After calling this method, all data arrays (positions, rotations, timestamps, path_lengths, velocities) will be reordered according to the new sorting.

Parameters:

  • sorting (Sorting) –

    The new sorting strategy (TIME or ARC_LENGTH).

Source code in trajectopy\core\trajectory.py
def set_sorting(self, sorting: Sorting) -> None:
    """Changes the sorting strategy and physically reorders all trajectory data.

    After calling this method, all data arrays (positions, rotations, timestamps,
    path_lengths, velocities) will be reordered according to the new sorting.

    Args:
        sorting (Sorting): The new sorting strategy (TIME or ARC_LENGTH).
    """
    if sorting == self._sorting:
        return

    self._sorting = sorting
    self._apply_sorting()

sort_index

sort_index(sorting: Sorting) -> ndarray

Returns the index that orders the current data by time or path length.

The sort is stable, so that data that is already in order (e.g. with equal path lengths of several laps) keeps its order and data stored alongside the trajectory, such as deviations, can be reordered alike.

Parameters:

  • sorting (Sorting) –

    Sorting to order by.

Returns:

  • ndarray –

    np.ndarray: Index into the current data.

Source code in trajectopy\core\trajectory.py
def sort_index(self, sorting: Sorting) -> np.ndarray:
    """Returns the index that orders the current data by time or path length.

    The sort is stable, so that data that is already in order (e.g. with equal path lengths of several laps)
    keeps its order and data stored alongside the trajectory, such as deviations, can be reordered alike.

    Args:
        sorting (Sorting): Sorting to order by.

    Returns:
        np.ndarray: Index into the current data.
    """
    key = self.timestamps if sorting == Sorting.TIME else self.path_lengths
    return np.argsort(key, kind="stable")

overlaps_with

overlaps_with(other: Trajectory) -> bool

Checks if the time span of this trajectory overlaps with another.

Parameters:

  • other (Trajectory) –

    The trajectory to compare against.

Returns:

  • bool ( bool ) –

    True if the time ranges overlap, False otherwise.

Source code in trajectopy\core\trajectory.py
def overlaps_with(self, other: "Trajectory") -> bool:
    """
    Checks if the time span of this trajectory overlaps with another.

    Args:
        other (Trajectory): The trajectory to compare against.

    Returns:
        bool: True if the time ranges overlap, False otherwise.
    """
    if len(self) == 0 or len(other) == 0:
        return False

    return self.time_start <= other.time_end and self.time_end >= other.time_start

crop

crop(
    index_start: float,
    index_end: float,
    inverse: bool = False,
    inplace: bool = True,
) -> Trajectory

Crops (or cuts) the trajectory based on a time window.

Parameters:

  • index_start (float) –

    Start index of the window.

  • index_end (float) –

    End index of the window.

  • inverse (bool, default: False ) –

    If True, removes data inside the window (cutting). If False, keeps data inside the window (cropping). Defaults to False.

  • inplace (bool, default: True ) –

    If True, modifies self. If False, returns a new instance. Defaults to True.

Returns:

  • Trajectory ( Trajectory ) –

    The modified or new trajectory instance.

Source code in trajectopy\core\trajectory.py
def crop(self, index_start: float, index_end: float, inverse: bool = False, inplace: bool = True) -> "Trajectory":
    """
    Crops (or cuts) the trajectory based on a time window.

    Args:
        index_start (float): Start index of the window.
        index_end (float): End index of the window.
        inverse (bool, optional): If True, removes data *inside* the window (cutting).
                                  If False, keeps data *inside* the window (cropping). Defaults to False.
        inplace (bool, optional): If True, modifies self. If False, returns a new instance. Defaults to True.

    Returns:
        Trajectory: The modified or new trajectory instance.
    """
    # filter to index_start and index_end
    if inverse:
        filt = [not index_start <= idx <= index_end for idx in self.index]
    else:
        filt = [index_start <= idx <= index_end for idx in self.index]

    return self.mask(mask=filt, inplace=inplace)

intersect

intersect(
    index: ndarray,
    max_gap_size: float = 10.0,
    inplace: bool = True,
) -> Trajectory

Filters the trajectory to overlap with a reference timestamp vector.

This method finds the common time span between self and the reference timestamps, crops self to that span, and then filters points that are either exact matches or exist within valid gaps defined by max_gap_size.

Parameters:

  • index (ndarray) –

    The reference indices to intersect with.

  • max_gap_size (float, default: 10.0 ) –

    The maximum allowed time gap (in seconds or meters) between reference indices to include trajectory points. Defaults to 10.0.

  • inplace (bool, default: True ) –

    If True, modifies self. Defaults to True.

Raises:

  • ValueError –

    If the index spans do not overlap.

Returns:

  • Trajectory ( Trajectory ) –

    The intersected trajectory.

Source code in trajectopy\core\trajectory.py
def intersect(self, index: np.ndarray, max_gap_size: float = 10.0, inplace: bool = True) -> "Trajectory":
    """
    Filters the trajectory to overlap with a reference timestamp vector.

    This method finds the common time span between self and the reference `timestamps`,
    crops self to that span, and then filters points that are either exact matches
    or exist within valid gaps defined by `max_gap_size`.

    Args:
        index (np.ndarray): The reference indices to intersect with.
        max_gap_size (float, optional): The maximum allowed time gap (in seconds or meters) between
                                        reference indices to include trajectory points. Defaults to 10.0.
        inplace (bool, optional): If True, modifies self. Defaults to True.

    Raises:
        ValueError: If the index spans do not overlap.

    Returns:
        Trajectory: The intersected trajectory.
    """
    traj_self = self if inplace else self.copy()
    index_span = common_span(index1=index, index2=traj_self.index)

    if index_span is None:
        raise ValueError("intersect_both: Indices do not overlap!")

    traj_self.crop(index_start=index_span[0], index_end=index_span[1])

    index_sorted = np.sort(index)
    filter_mask = np.ones(len(traj_self), dtype=bool)

    # find where gaps are too large
    gaps = np.diff(index_sorted) > max_gap_size
    gap_starts = index_sorted[:-1][gaps]
    gap_ends = index_sorted[1:][gaps]

    # the index (time or path length) is in ascending order, see _apply_sorting
    for g_start, g_end in zip(gap_starts, gap_ends):
        idx_start = np.searchsorted(traj_self.index, g_start, side="right")
        idx_end = np.searchsorted(traj_self.index, g_end, side="left")

        # keep one point after gap start and one point before gap end for interpolation
        if idx_end - 1 > idx_start:
            filter_mask[idx_start + 1 : idx_end - 1] = False

    filter_index = np.where(filter_mask)[0]
    traj_self.mask(np.array(filter_index, dtype=int))

    return traj_self

mask

mask(
    mask: list | ndarray, inplace: bool = True
) -> Trajectory

Applies a boolean mask or index array to filter all trajectory components.

Filtered components include: timestamps, positions, rotations, path lengths, and velocities.

Parameters:

  • mask (Union[list, ndarray]) –

    Boolean array or list of indices to keep.

  • inplace (bool, default: True ) –

    If True, modifies self. Defaults to True.

Returns:

  • Trajectory ( Trajectory ) –

    The masked trajectory.

Source code in trajectopy\core\trajectory.py
def mask(self, mask: list | np.ndarray, inplace: bool = True) -> "Trajectory":
    """
    Applies a boolean mask or index array to filter all trajectory components.

    Filtered components include: timestamps, positions, rotations, path lengths, and velocities.

    Args:
        mask (Union[list, np.ndarray]): Boolean array or list of indices to keep.
        inplace (bool, optional): If True, modifies self. Defaults to True.

    Returns:
        Trajectory: The masked trajectory.
    """
    traj_self = self if inplace else self.copy()

    traj_self.timestamps = traj_self.timestamps[mask]
    traj_self.positions.xyz = traj_self.positions.xyz[mask, :]

    if traj_self.rotations:
        quat_filtered = traj_self.rotations.as_quat()[mask, :]
        traj_self.rotations = Rotations.from_quat(quat_filtered) if len(quat_filtered) > 0 else None

    traj_self.path_lengths = traj_self.path_lengths[mask]

    if traj_self.velocity_xyz is not None:
        traj_self.velocity_xyz = traj_self.velocity_xyz[mask]

    return traj_self

transform

transform(
    transformation: ndarray, inplace: bool = True
) -> Trajectory

Applies a rigid body or similarity transformation to the trajectory poses.

Velocities are rotated and scaled alike, path lengths are scaled. A trajectory without orientations stays without orientations.

Parameters:

  • transformation (ndarray) –

    A 4x4 homogeneous transformation matrix.

  • inplace (bool, default: True ) –

    If True, modifies self. Defaults to True.

Returns:

  • Trajectory ( Trajectory ) –

    The transformed trajectory.

Source code in trajectopy\core\trajectory.py
def transform(self, transformation: np.ndarray, inplace: bool = True) -> "Trajectory":
    """
    Applies a rigid body or similarity transformation to the trajectory poses.

    Velocities are rotated and scaled alike, path lengths are scaled. A trajectory without
    orientations stays without orientations.

    Args:
        transformation (np.ndarray): A 4x4 homogeneous transformation matrix.
        inplace (bool, optional): If True, modifies self. Defaults to True.

    Returns:
        Trajectory: The transformed trajectory.
    """
    traj_self = self if inplace else self.copy()
    linear = transformation[:3, :3]

    traj_self.velocity_xyz = traj_self.velocity_xyz @ linear.T
    traj_self.path_lengths = traj_self.path_lengths * float(np.cbrt(abs(np.linalg.det(linear))))

    has_orientation = traj_self.has_orientation
    traj_self.se3 = [np.dot(transformation, p) for p in traj_self.se3]
    if not has_orientation:
        traj_self.rotations = None
    return traj_self

to_dataframe

to_dataframe(sort_by: str = '') -> DataFrame

Exports the trajectory to a Pandas DataFrame.

Columns usually include: time, path_length, pos_x, pos_y, pos_z, speed_x, speed_y, speed_z, and rotation columns (rot_x/y/z/w) if available.

Parameters:

  • sort_by (str, default: '' ) –

    Column name to sort by. If empty, uses self.sorting.

Returns:

  • DataFrame –

    pd.DataFrame: A dataframe containing the trajectory data.

Source code in trajectopy\core\trajectory.py
def to_dataframe(self, sort_by: str = "") -> pd.DataFrame:
    """
    Exports the trajectory to a Pandas DataFrame.

    Columns usually include: time, path_length, pos_x, pos_y, pos_z, speed_x, speed_y, speed_z,
    and rotation columns (rot_x/y/z/w) if available.

    Args:
        sort_by (str, optional): Column name to sort by. If empty, uses `self.sorting`.

    Returns:
        pd.DataFrame: A dataframe containing the trajectory data.
    """
    sort_by = sort_by or self.sorting
    if self.rotations:
        dataframe = pd.DataFrame(
            np.c_[
                self.timestamps, self.path_lengths, self.positions.xyz, self.rotations.as_quat(), self.velocity_xyz
            ],
            columns=[
                "time",
                "path_length",
                "pos_x",
                "pos_y",
                "pos_z",
                "rot_x",
                "rot_y",
                "rot_z",
                "rot_w",
                "speed_x",
                "speed_y",
                "speed_z",
            ],
        )
    else:
        dataframe = pd.DataFrame(
            np.c_[self.timestamps, self.path_lengths, self.positions.xyz, self.velocity_xyz],
            columns=["time", "path_length", "pos_x", "pos_y", "pos_z", "speed_x", "speed_y", "speed_z"],
        )

    return dataframe.sort_values(by=sort_by)

to_string

to_string() -> str

Serializes the trajectory to a CSV-formatted string with metadata headers.

Headers included: #epsg, #name, #nframe, #sorting, #fields.

Source code in trajectopy\core\trajectory.py
def to_string(self) -> str:
    """
    Serializes the trajectory to a CSV-formatted string with metadata headers.

    Headers included: #epsg, #name, #nframe, #sorting, #fields.
    """
    from trajectopy.io.trajectory_io import trajectory_to_string

    return trajectory_to_string(self)

to_file

to_file(filename: str, mode: str = 'w') -> None

Writes the trajectory to an ASCII file using the format defined in to_string.

Parameters:

  • filename (str) –

    The output file path.

  • mode (str, default: 'w' ) –

    File open mode. Defaults to "w".

Source code in trajectopy\core\trajectory.py
def to_file(self, filename: str, mode: str = "w") -> None:
    """
    Writes the trajectory to an ASCII file using the format defined in `to_string`.

    Args:
        filename (str): The output file path.
        mode (str, optional): File open mode. Defaults to "w".
    """
    from trajectopy.io.trajectory_io import write_trajectory

    write_trajectory(self, filename=filename, mode=mode)

to_kml

to_kml(
    filename: str,
    precision: float = 1e-06,
    color: str = "#ff0000",
    **options: Any,
) -> None

Exports the trajectory to a Google Earth KML file, as a time-stamped track that the time slider of Google Earth plays back.

Requires the trajectory to have a valid EPSG code so it can be converted to WGS84 (EPSG:4326).

Parameters:

  • filename (str) –

    The output filename (e.g., "track.kml").

  • precision (float, default: 1e-06 ) –

    Coordinate precision in degrees. Defaults to 1e-6 (about 0.1 m).

  • color (str, default: '#ff0000' ) –

    Color of the track and its points as "#RRGGBB" or "#RRGGBBAA". Defaults to red.

  • **options (Any, default: {} ) –

    Further options of :func:trajectopy.io.kml.write_kml, e.g. field="speed" (color by a field), heights="ellipsoidal" (draw at the trajectory's heights instead of on the ground), extrude=True or line_width.

Raises:

  • ValueError –

    If the trajectory does not have a known EPSG code or an option is invalid.

Source code in trajectopy\core\trajectory.py
def to_kml(self, filename: str, precision: float = 1e-6, color: str = "#ff0000", **options: Any) -> None:
    """
    Exports the trajectory to a Google Earth KML file, as a time-stamped track that the time slider of
    Google Earth plays back.

    Requires the trajectory to have a valid EPSG code so it can be converted to WGS84 (EPSG:4326).

    Args:
        filename (str): The output filename (e.g., "track.kml").
        precision (float, optional): Coordinate precision in degrees. Defaults to 1e-6 (about 0.1 m).
        color (str, optional): Color of the track and its points as "#RRGGBB" or "#RRGGBBAA".
            Defaults to red.
        **options: Further options of :func:`trajectopy.io.kml.write_kml`, e.g. ``field="speed"`` (color
            by a field), ``heights="ellipsoidal"`` (draw at the trajectory's heights instead of on the
            ground), ``extrude=True`` or ``line_width``.

    Raises:
        ValueError: If the trajectory does not have a known EPSG code or an option is invalid.
    """
    from trajectopy.io.kml import write_kml

    write_kml(self, filename=filename, precision=precision, color=color, **options)