CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pytransform3d

3D transformations for Python with comprehensive rotation representations, coordinate conversions, and visualization tools

Pending
Overview
Eval results
Files

transform-manager.mddocs/

Transform Manager

Graph-based system for managing complex transformation chains with automatic path finding between coordinate frames. Supports static and time-varying transformations with efficient computation and visualization capabilities.

Capabilities

TransformManager Class

Core class for managing static transformation graphs between coordinate frames.

class TransformManager:
    def __init__(self, strict_check=True, check=True):
        """
        Initialize transformation manager.
        
        Parameters:
        - strict_check: bool - Enable strict validation
        - check: bool - Enable transformation checks
        """

    def add_transform(self, from_frame, to_frame, A2B):
        """
        Add transformation between frames.
        
        Parameters:
        - from_frame: str - Source frame name
        - to_frame: str - Target frame name  
        - A2B: array, shape (4, 4) - Transformation matrix
        """

    def get_transform(self, from_frame, to_frame):
        """
        Get transformation between any two frames.
        
        Parameters:
        - from_frame: str - Source frame name
        - to_frame: str - Target frame name
        
        Returns:
        - A2B: array, shape (4, 4) - Transformation matrix
        """

    def plot_frames_in(self, frame, ax=None, s=1.0, ax_s=1, **kwargs):
        """
        Plot all frames in specified reference frame.
        
        Parameters:
        - frame: str - Reference frame name
        - ax: Axes3D, optional - Matplotlib 3D axis
        - s: float - Scaling factor for frame visualization
        - ax_s: float - Axis scaling factor
        """

    def plot_connections_in_frame(self, frame, ax=None, s=1.0, ax_s=1, **kwargs):
        """Plot frame connections as lines."""

    def check_consistency(self):
        """Check consistency of all transformations in graph."""

    def whitelist_frames(self, frames):
        """Restrict graph to specified frames."""

    def remove_frame(self, frame):
        """Remove frame and its connections from graph."""

    def connected_components(self):
        """Find connected components in transformation graph."""

    @property
    def nodes(self):
        """Get all frame names in the graph."""

    @property 
    def transforms(self):
        """Get all transformations as dictionary."""

TemporalTransformManager Class

Extended manager for time-varying transformations with temporal interpolation.

class TemporalTransformManager(TransformManager):
    def __init__(self, strict_check=True, check=True):
        """Initialize temporal transformation manager."""

    def add_transform(self, from_frame, to_frame, transform, static=True):
        """
        Add time-varying transformation.
        
        Parameters:
        - from_frame: str - Source frame name
        - to_frame: str - Target frame name
        - transform: TimeVaryingTransform or array - Transform object or static matrix
        - static: bool - Whether transform is static
        """

    def get_transform(self, from_frame, to_frame, time=None):
        """
        Get transformation at specific time.
        
        Parameters:
        - from_frame: str - Source frame name
        - to_frame: str - Target frame name
        - time: float, optional - Time for interpolation
        
        Returns:
        - A2B: array, shape (4, 4) - Transformation at specified time
        """

Time-Varying Transform Classes

Base classes for defining time-dependent transformations.

class TimeVaryingTransform:
    """Abstract base class for time-varying transformations."""
    
    def as_matrix(self, time):
        """
        Get transformation matrix at specific time.
        
        Parameters:
        - time: float - Time value
        
        Returns:
        - A2B: array, shape (4, 4) - Transformation matrix
        """

class StaticTransform(TimeVaryingTransform):
    def __init__(self, A2B):
        """
        Static transformation that doesn't change over time.
        
        Parameters:
        - A2B: array, shape (4, 4) - Static transformation matrix
        """

class NumpyTimeseriesTransform(TimeVaryingTransform):
    def __init__(self, times, transforms, interpolation_method="slerp"):
        """
        Time-varying transformation from numpy array timeseries.
        
        Parameters:
        - times: array, shape (n,) - Time stamps
        - transforms: array, shape (n, 4, 4) - Transformation matrices
        - interpolation_method: str - Interpolation method ("slerp" or "linear")
        """

TransformGraphBase Class

Base class providing core graph functionality for transformation management.

class TransformGraphBase:
    """Base class for transformation graphs with path finding algorithms."""
    
    def shortest_path(self, from_frame, to_frame):
        """Find shortest path between frames in graph."""
        
    def has_frame(self, frame):
        """Check if frame exists in graph."""
        
    def get_frames(self):
        """Get all frame names."""

Usage Examples

Basic Transform Management

import numpy as np
import pytransform3d.transformations as pt
from pytransform3d.transform_manager import TransformManager

# Create transform manager
tm = TransformManager()

# Add transformations between frames
base_to_link1 = pt.transform_from(p=[1, 0, 0])
tm.add_transform("base", "link1", base_to_link1)

link1_to_link2 = pt.transform_from(p=[0, 1, 0])
tm.add_transform("link1", "link2", link1_to_link2)

link2_to_end = pt.transform_from(p=[0, 0, 1])
tm.add_transform("link2", "end_effector", link2_to_end)

# Get transformation between any two frames
base_to_end = tm.get_transform("base", "end_effector")
print(f"Base to end effector:\n{base_to_end}")

# Get transformation in reverse direction
end_to_base = tm.get_transform("end_effector", "base")
print(f"End effector to base:\n{end_to_base}")

Kinematic Chain Visualization

import matplotlib.pyplot as plt
from pytransform3d.transform_manager import TransformManager
from pytransform3d.plot_utils import make_3d_axis

# Create kinematic chain
tm = TransformManager()

# Add joints in a simple arm
tm.add_transform("base", "shoulder", pt.transform_from(p=[0, 0, 0.1]))
tm.add_transform("shoulder", "elbow", pt.transform_from(p=[0.3, 0, 0]))
tm.add_transform("elbow", "wrist", pt.transform_from(p=[0.25, 0, 0]))
tm.add_transform("wrist", "hand", pt.transform_from(p=[0.1, 0, 0]))

# Plot all frames
ax = make_3d_axis(ax_s=1)
tm.plot_frames_in("base", ax=ax, s=0.1)
tm.plot_connections_in_frame("base", ax=ax)
plt.show()

Time-Varying Transformations

import numpy as np
from pytransform3d.transform_manager import TemporalTransformManager, NumpyTimeseriesTransform
import pytransform3d.transformations as pt

# Create temporal transform manager
ttm = TemporalTransformManager()

# Define time-varying transformation (rotating joint)
times = np.linspace(0, 2*np.pi, 100)
transforms = []
for t in times:
    R = pr.matrix_from_euler([0, 0, t], "xyz", extrinsic=True)
    T = pt.transform_from(R=R, p=[0, 0, 0])
    transforms.append(T)

transforms = np.array(transforms)
rotating_joint = NumpyTimeseriesTransform(times, transforms)

# Add static and time-varying transforms
ttm.add_transform("base", "rotating_link", rotating_joint, static=False)
ttm.add_transform("rotating_link", "end", pt.transform_from(p=[1, 0, 0]), static=True)

# Get transformation at specific times
T_at_0 = ttm.get_transform("base", "end", time=0)
T_at_pi = ttm.get_transform("base", "end", time=np.pi)

print(f"Transform at t=0:\n{T_at_0[:3, 3]}")  # translation part
print(f"Transform at t=π:\n{T_at_pi[:3, 3]}")  # translation part

Complex Robot Structure

from pytransform3d.transform_manager import TransformManager
import pytransform3d.transformations as pt
import pytransform3d.rotations as pr

# Create complex robot structure
tm = TransformManager()

# Base platform
tm.add_transform("world", "base_platform", pt.transform_from(p=[0, 0, 0.05]))

# Left arm
R_left = pr.matrix_from_euler([0, 0, np.pi/4], "xyz", extrinsic=True)
tm.add_transform("base_platform", "left_shoulder", pt.transform_from(R=R_left, p=[-0.2, 0.3, 0.4]))
tm.add_transform("left_shoulder", "left_elbow", pt.transform_from(p=[0.3, 0, 0]))
tm.add_transform("left_elbow", "left_hand", pt.transform_from(p=[0.25, 0, 0]))

# Right arm
R_right = pr.matrix_from_euler([0, 0, -np.pi/4], "xyz", extrinsic=True)
tm.add_transform("base_platform", "right_shoulder", pt.transform_from(R=R_right, p=[0.2, 0.3, 0.4]))
tm.add_transform("right_shoulder", "right_elbow", pt.transform_from(p=[0.3, 0, 0]))
tm.add_transform("right_elbow", "right_hand", pt.transform_from(p=[0.25, 0, 0]))

# Head
tm.add_transform("base_platform", "neck", pt.transform_from(p=[0, 0, 0.6]))
tm.add_transform("neck", "head", pt.transform_from(p=[0, 0, 0.1]))

# Eyes
tm.add_transform("head", "left_eye", pt.transform_from(p=[-0.03, 0.05, 0.02]))
tm.add_transform("head", "right_eye", pt.transform_from(p=[0.03, 0.05, 0.02]))

# Get transformation between hands
left_to_right = tm.get_transform("left_hand", "right_hand")
print(f"Left hand to right hand distance: {np.linalg.norm(left_to_right[:3, 3]):.3f}m")

# Check graph properties
print(f"Total frames: {len(tm.nodes)}")
print(f"Frames: {list(tm.nodes)}")

Graph Analysis

from pytransform3d.transform_manager import TransformManager

# Create disconnected graph
tm = TransformManager()

# First component
tm.add_transform("A", "B", np.eye(4))
tm.add_transform("B", "C", np.eye(4))

# Second component (disconnected)
tm.add_transform("X", "Y", np.eye(4))
tm.add_transform("Y", "Z", np.eye(4))

# Find connected components
components = tm.connected_components()
print(f"Connected components: {components}")

# Check consistency
try:
    tm.check_consistency()
    print("Graph is consistent")
except Exception as e:
    print(f"Graph inconsistency: {e}")

# Try to get transform between disconnected components
try:
    T = tm.get_transform("A", "X")  # Will fail - no path
except KeyError:
    print("No path between disconnected components")

Install with Tessl CLI

npx tessl i tessl/pypi-pytransform3d

docs

batch-operations.md

batch-rotations.md

camera.md

coordinates.md

editor.md

index.md

plot-utils.md

rotations.md

trajectories.md

transform-manager.md

transformations.md

uncertainty.md

urdf.md

visualization.md

tile.json