compute_turning_angle#

movement.kinematics.compute_turning_angle(data, in_degrees=False, min_step_length=0.0)[source]#

Compute the turning angles between consecutive steps in a trajectory.

The turning angle at time t is the signed angle between two consecutive backward displacement vectors at times t-1 and t. The returned angles are in radians, spanning the range \((-\pi, \pi]\), unless in_degrees is set to True.

Parameters:
  • data (DataArray) – The input position data. Must contain time and space dimensions. The space dimension must contain exactly the coordinates ["x", "y"] (2D spatial data only).

  • in_degrees (bool) – If True, return turning angles in degrees. Default is False (radians).

  • min_step_length (float) – The minimum step length to consider for computing the turning angle. Any turning angle involving an incoming or outgoing step shorter than or equal to this value is set to NaN. The default 0.0 only masks steps with exactly zero length, which means steps with near-zero lengths may still produce spurious angles. See Note 2 below.

Returns:

Turning angles with the same shape as the input data, but with the space dimension dropped.

Return type:

DataArray

Notes

  1. Time dimension length: This function uses a shift operation to preserve the original time dimension length. The first two time steps are always NaN: the first because no previous step exists, and the second because a turning angle requires two steps (three positions). In other words, the turning angle at time step t is computed as the angle between the steps from t-2 to t-1 and from t-1 to t.

  2. Positional jitter and small steps: Tracking data often contains positional jitter, meaning a stationary animal may appear to make microscopic movements. With default parameters (min_step_length=0.0), these tiny, noisy movements will produce spurious, meaningless turning angles. It is highly recommended to set min_step_length to an appropriate threshold based on the tracking resolution and the animal’s size in the scene. The value should be in the same units as the input position data (e.g. pixels, mm, etc.). Pre-smoothing the trajectory can also help reduce positional jitter.

  3. NaN propagation: NaN positions in the input propagate to NaN turning angles. A single missing position affects up to two turning angles (the incoming and outgoing steps). Use movement.filtering.interpolate_over_time() to fill positional gaps before computing turning angles if continuity is important.

See also

movement.kinematics.compute_backward_displacement

The underlying function used to compute the displacement vectors.

movement.utils.vector.compute_signed_angle_2d

The underlying function used to compute the signed angle between two consecutive displacement vectors.

Examples

>>> from movement.kinematics import compute_turning_angle

Compute turning angles from the centroid trajectory of a poses dataset ds:

>>> centroid = ds.position.mean(dim="keypoints")
>>> angles = compute_turning_angle(centroid)

Compute in degrees, with a minimum step length of 3 pixels to filter out pose estimation jitter:

>>> angles = compute_turning_angle(
...     centroid, in_degrees=True, min_step_length=3
... )