Replacing displacement vectors for greater clarity#
This post introduces recent improvements to how movement computes displacement vectors, making the definitions more explicit, flexible, and intuitive for users.
Background#
Computing kinematic properties is a core functionality since early versions of movement, when they where first introduced by Chang Huan Lo in #106.
For a library dedicated to analysing motion-tracking data, quantifying how far a tracked point moves between consecutive frames is fundamental. This measure underpins subsequent computations, such as the total distance travelled along a path. That’s why we introduced the compute_displacement function early on, and why it features in our compute and visualise kinematics example.
Its original implementation, however, produced results that were difficult to interpret. For a given individual and keypoint at timestep t, displacement was defined as the vector pointing from the previous position at t-1 to the current position at t. This definition is somewhat counter-intuitive: it identifies the last spatial translation used by the keypoint to reach its current position. It indicates where the point came from rather than where it is going.
For this reason, during the Hackday at Open Software Week 2025—and as my first contribution to movement—I volunteered to develop a more intuitive interface for displacement vectors, under the supervision of Sofía Miñano.
These improvements were introduced in #657 through a collaborative effort. The update provides a simpler, well-tested, and better-documented implementation that makes displacement computations easier to understand and use.

What’s new?#
kinematics has two new sister functions:
compute_forward_displacement, computing the vector defined at timetthat goes from the position in the current frame to the position in the next frame, att+1.compute_backward_displacement, computing the vector defined at timetthat goes from the position in the current frame to the position in the previous frame, att-1.
These functions replace the previous, more ambiguous compute_displacement, which has now been deprecated.
The new API makes the directionality of displacement explicit, giving users greater flexibility. Depending on the context, one can now choose between forward- or backward-oriented vectors instead of relying on a single implicit definition.
If you need a drop-in replacement for the old behaviour, you can use:
import movement.kinematics as kin
# Instead of:
displacement = kin.compute_displacement(ds.position)
# Use:
displacement = -kin.compute_backward_displacement(ds.position)
Related changes
We slightly modified the behaviour of vector conversion from Cartesian to polar coordinates. For simplicity and interpretability, cart2pol now always sets the angle phi to 0 when the vector’s norm rho is 0, rather than following the C standard for arctan2. This change should not affect existing workflows, as a zero-length vector has an undefined direction—meaning it could point in any direction, and assigning phi = 0 is a safe, neutral choice.
Reflections#
I would like to extend my sincere gratitude to the Neuroinformatics Unit for fostering an exceptional open environment that has even inspired me to enhance my own projects. Their efforts have motivated me to make BraiAn more accessible to inexperienced researchers, to improve its interoperability and to develop automated pipelines for software verification.
I am firmly convinced that bridging the gap between experimental laboratories is crucial for enabling reproducible and comparable results across research groups. I have long believed that the development and adoption of shared standards and widely accepted platforms can facilitate this goal. The Neuroinformatics Unit has not only reinforced my conviction but also demonstrated, through their remarkable work, that this vision can be turned into a practical reality.