Skip to content

Vectors3D

Represents a batch of 3D vectors.

Parameters

FieldTypeDescription
datanp.ndarray | list | tupleArray-like data of shape (N, 3), converted to a contiguous float32 array.

Raises

ExceptionCondition
TypeErrordata can't be converted to a float32 array (e.g. non-numeric elements)
ValueErrordata's rank isn't 2, its last axis isn't length 3, or it contains a non-finite value (NaN/Inf)

Attributes

AttributeTypeDescription
shape_specClassVar[tuple[int | None, ...]]Class-level shape spec, (None, 3)None means the batch size is variable.
datanp.ndarrayThe wrapped batch, shape (N, 3). Reading it returns a copy, so mutating the result doesn't affect the Vectors3D; assigning a new value re-validates it the same way as construction.
shapetuple[int, ...](N, 3).
ndimintAlways 2.
dtypenp.dtypeAlways float32.
sizeint3 * N.

Methods

MethodDescription
to_numpy(copy=True)Returns the batch as np.ndarray. Pass copy=False to get a reference to the internal array instead — faster for large data, but mutating it mutates the Vectors3D too.
copy()Returns a new Vectors3D with an independent copy of the data.
Vectors3D.coerce(value)Returns value unchanged if it's already a Vectors3D; otherwise wraps a shape-(N, 3) np.ndarray/list/tuple into one. Raises TypeError for any other input.

Operators

OperationBehavior
v1 == v2True only if other is exactly a Vectors3D (not a subclass, not another datatype) with element-equal data. False for anything else.
len(v)Batch size N. 0 for an empty batch (shape (0, 3)) — that's a valid, constructible batch.
np.asarray(v)Works directly — NumPy functions (e.g. np.reshape, np.sum) accept a Vectors3D in place of an np.ndarray. Always returns a copy; use to_numpy(copy=False) for a zero-copy view.
hash(v)Not supported — a Vectors3D can't be used as a dict key or set member.

Visualization

datatypes.visualize(vectors, entity_path=..., label=...) logs the batch as N 3D arrows (rr.Arrows3D), each drawn from the world origin. Passing label as a list[str] of length N attaches one text label per arrow.

Example

python
"""Demonstrates the Telekinesis Vectors3D datatype."""

import time

import numpy as np
from loguru import logger
import rerun as rr

from telekinesis import datatypes

def vectors3d_example():
    """Demonstrate creation, access, update, NumPy interop, serialization, and empty batches."""

    # ======================= Create ============================================
    vectors = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
    vectors3d = datatypes.Vectors3D(vectors)

    logger.info(f"Created Vectors3D: {vectors3d}")

    # ======================= Inspect ===========================================
    data = vectors3d.data
    shape = vectors3d.shape
    size = vectors3d.size
    dtype = vectors3d.dtype
    ndim = vectors3d.ndim
    numpy_array = vectors3d.to_numpy()
    vectors3d_copy = vectors3d.copy()

    logger.info(f"shape={shape}, size={size}, ndim={ndim}, dtype={dtype}")
    logger.info(f"Vectors3D data: {data}")
    logger.info(f"NumPy array: {numpy_array}")
    logger.info(f"Copied Vectors3D: {vectors3d_copy}")

    # ======================= Visualize =========================================
    rr.init("vectors3d_example", spawn=True)
    datatypes.visualize(vectors3d, entity_path="/Vectors3D", label=["Vector 1", "Vector 2"])

    # ======================= Update ============================================
    new_data = [[7.0, 8.0, 9.0], [10.0, 11.0, 12.0]]
    vectors3d.data = new_data

    logger.info(f"Updated Vectors3D: {vectors3d}")
    datatypes.visualize(
        vectors3d,
        entity_path="/Vectors3D/updated",
        label=["Updated Vector 1", "Updated Vector 2"],
    )

    # ======================= NumPy Interop =====================================
    sum_result = vectors3d + np.array([1.0, 1.0, 1.0])

    logger.info(f"Sum of Vectors3D with numpy array: {sum_result}")

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(vectors3d)
    serialization_ms = (time.perf_counter() - start) * 1000

    start = time.perf_counter()
    deserialized = datatypes.deserialize(serialized)["param_0"]
    deserialization_ms = (time.perf_counter() - start) * 1000

    logger.info(f"Deserialized Vectors3D: {deserialized}")
    logger.info(f"Round-trip successful: {deserialized.data == new_data}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")

    # ======================= Empty Batch =======================================
    empty = datatypes.Vectors3D(np.empty((0, 3), dtype=np.float32))

    logger.info(f"Empty Vectors3D: {empty}")
    logger.info(f"Empty Vectors3D shape: {empty.shape}")


if __name__ == "__main__":
    vectors3d_example()

See also Vector3D for a single 3D vector.