Library / SDK
dfki-ric/pytransform3d avatar
dfki-ric/pytransform3d

pytransform3d: rotations, translations and the conventions between them

3D transformations for Python.

707 stars80 forksPythonNOASSERTION

At a glance

What is it?
pytransform3d is a Python library for 3D transformations that offers operations and conversions for the common rotation and translation representations, a TransformManager for chains of frames, and optional extras for URDF files, a Qt editor and Open3D visualisation. Its documentation makes transformation conventions explicit, which is the part that saves you the most time.
Who is it for?
pytransform3d suits a robotics, graphics or human-pose project that keeps tripping over rotation representations, since the conversions and the explicit convention documentation are the reason to use it rather than a few hand-written matrix helpers.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One library for every rotation representation you meet

pytransform3d is described as a Python library for transformations in three dimensions, and the list of what it offers is the clearest statement of its purpose. It gives operations like concatenation and inversion for most common representations of rotation, also called orientation, and translation, also called position. It gives conversions between those representations. It provides clear documentation of transformation conventions. It is tightly coupled with matplotlib to quickly visualize or animate transformations. Beyond the core there are four optional pieces, each with its own extra dependency: the TransformManager, which manages complex chains of transformations and can export to a graph visualization as PNG, which additionally requires pydot; the TransformEditor, which allows modifying transformations graphically and additionally requires PyQt4 or PyQt5; the UrdfTransformManager, which loads transformations from URDF files and additionally requires lxml; and a matplotlib-like interface to the Open3D visualizer for displaying and animating geometries and transformations, which additionally requires Open3D. The audience is robotics, graphics and human pose work, and the README lists specifying motions of a robot, learning robot movements from human demonstration, sensor fusion for human pose estimation and collision detection for robots as example domains.

The TransformManager is a graph of named frames

The example in the README shows the shape of the API better than any description. You build transformations between named frames and add them to a TransformManager, then ask the manager for the transform between any two frames:

python
tm = TransformManager()
tm.add_transform("end-effector", "robot", ee2robot)
tm.add_transform("camera", "robot", cam2robot)
tm.add_transform("object", "camera", object2cam)

ee2object = tm.get_transform("end-effector", "object")

The frames are named strings and the edges carry the transform from the second frame to the first, so end-effector to robot, camera to robot, object to camera. Asking for end-effector to object then traverses the chain, and the manager resolves the composition. That is the feature that removes the fiddly mental arithmetic of inverting transforms and multiplying them in the right order, and it is the reason the library is more than a set of conversion functions. The same manager also draws the frames, through plot_frames_in, which is why the example follows the transform query with a plot and axis limits before showing the figure.

Building a transform from a position and a quaternion

The example also shows how representations enter the picture, which is the practical reason the library has so many conversion functions. Each of the three transforms is built differently. The end-effector to robot transform uses transform_from_pq with a position array and a random quaternion produced by pr.random_quaternion from a seeded numpy generator. The camera to robot transform uses transform_from_pq with the identity quaternion, pr.q_id, and a fixed position. The object to camera transform uses transform_from, which takes a rotation matrix and a translation separately, and the rotation is built from intrinsic Euler angles with pr.active_matrix_from_intrinsic_euler_xyz. So the same library takes an orientation as a quaternion in one place and as Euler angles in another, and the naming of the active function tells you the convention being used. The plotting calls that follow, set_xlim, set_ylim and set_zlim, are plain matplotlib axes methods, which is the point of the tight matplotlib coupling: the visualization is not a separate abstraction, it is the axes object you already have.

Installing it, and the extra that pulls in Open3D

Installation from PyPI is a single command:

bash
pip install 'pytransform3d[all]'

Or through conda:

bash
conda install -c conda-forge pytransform3d

The bracket notation matters here. The all extra, as the setup file spells it out, pulls in pydot, trimesh, pycollada and open3d, and the base install is numpy, scipy, matplotlib and lxml. If you do not need the graph export, the graphical editor and the Open3D visualisation, installing without the extra keeps open3d, a heavy dependency, out of your environment. The requirements file in the repository lists numpy, scipy, matplotlib, lxml, trimesh, pycollada, pydot and open3d together, which is the union of the base install and the all extra. The package also exposes doc and test extras, with doc covering numpydoc, sphinx, sphinx-gallery, pydata-sphinx-theme and sphinxcontrib.video, and test covering pytest and pytest-cov.

Building the docs and running the tests

The README covers the developer workflow in two short sections. The documentation source lives in the doc directory, and to build it you run:

bash
cd doc
make html

The built HTML then sits at doc/build/html/index.html, and the dependencies for that build are installed with the editable install in the main folder of the repository:

bash
pip install -e '.[doc]'

Tests are run with pytest from the root directory of the project, and a coverage report is located at htmlcov/index.html. The note is that you have to install pytest to run the tests and pytest-cov to obtain the code coverage report, so the base install does not give you a working test command. The repository layout supports a full research workflow rather than just a library: there is a doc directory, an examples directory with subfolders for animations, apps, plots and visualizations, a paper directory, a test directory, a CITATION.cff file and a manifest.xml for conda, plus a .coveragerc at the root. The examples README and the paper directory are what turn this from a code drop into something you can cite.

The licence the metadata disagrees about

Here is a discrepancy worth resolving before you depend on the package. GitHub classifies the licence of this repository as Other, a custom licence the platform cannot map to a known identifier, and the README points to the LICENSE file. The setup file in the same repository declares license='BSD-3-Clause' and carries a classifier for the OSI Approved BSD License. The package also has a DOI badge for a JOSS paper and a release DOI badge pointing at Zenodo, which is the citable archiving arrangement a research project uses. The mismatch between a platform classification of Other and a BSD-3-Clause declaration in the packaging metadata is the kind of thing that comes from a licence file that was changed after the metadata was written, or from a custom addition on top of the BSD text. Read the LICENSE file to see which it is, and do not treat the BSD identifier in the setup metadata as the answer. The contributing guide and issue tracker are where such a question can also be raised.

What pytransform3d is not, and the JAX alternative

Two boundaries are visible. The first is about performance and differentiability. The README says that if you need similar features in JAX, on GPU, vectorized and differentiable, you should have a look at the experimental library jaxtransform3d. That sentence is the clearest statement of the trade-off in the project: pytransform3d is a NumPy and SciPy implementation, so it operates on CPU arrays with dense linear algebra, and the JAX variant exists because you cannot backpropagate through a NumPy array. If your project is training a model on transformation parameters, the experimental library is the relevant one. The second boundary is scope. The library does rotations and translations in three dimensions, and it does not do scene graphs, physics, collision queries or asset pipelines. The collision detection mentioned in the domain list is an application of the transformations rather than a feature of the library. A 3D graphics engine is the alternative for people who need those, and the difference in approach is that an engine owns the whole pipeline while this library owns the mathematics and hands the axes to matplotlib.

Editorial conclusion

pytransform3d suits a robotics, graphics or human-pose project that keeps tripping over rotation representations, since the conversions and the explicit convention documentation are the reason to use it rather than a few hand-written matrix helpers. It is the wrong tool if your work is on a GPU and needs to be differentiable or vectorised, since the README points to the experimental jaxtransform3d library for that case, and it is the wrong tool if you want a single rotation type with no conversions at all. Verify first which licence terms apply, because GitHub classifies the repository as Other while setup.py declares BSD-3-Clause and a BSD License classifier, so read the LICENSE file rather than trusting either, and note that the newest release is 3.17.0 from 2026-10-06 with the last push on 2026-10-09.

Frequently asked questions

How do I install pytransform3d?

From PyPI with pip install 'pytransform3d[all]', or from conda-forge with conda install -c conda-forge pytransform3d. The all extra pulls in pydot, trimesh, pycollada and open3d, while the base install needs only numpy, scipy, matplotlib and lxml.

What is the TransformManager for?

It manages chains of transformations between named frames. You add transforms with add_transform and then ask for any pair with get_transform, for example tm.get_transform("end-effector", "object"), and the manager composes the chain. It can also plot the frames and export the chain as a PNG graph when pydot is installed.

How do I load a robot model from a URDF file?

The UrdfTransformManager loads transformations from URDF files and additionally requires lxml. The README's gallery shows a Nao robot with a URDF from Bullet3, and the examples in the documentation cover this workflow.

Can I use pytransform3d with JAX on a GPU?

Not directly. The README says that if you need similar features in JAX, on GPU, vectorized and differentiable, you should have a look at the experimental library jaxtransform3d, since pytransform3d is built on NumPy and SciPy.

How do I run the tests and get a coverage report?

Run pytest from the root directory of the project. The coverage report is then located at htmlcov/index.html, and you need pytest installed to run the tests plus pytest-cov to obtain the coverage report.

Official sources

  1. dfki-ric/pytransform3d on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dfki-ric-pytransform3d.svg)](https://hysenlabs.com/projects/dfki-ric-pytransform3d)

Was this useful?