Skip to content

v0.17.0

Latest

Choose a tag to compare

@niksirbi niksirbi released this 08 Jun 16:30
45d29ab

Important

This release contains several breaking changes. Please read the notes below carefully before updating.

To update movement to the latest version, see the update guide.

What's Changed

⚡️ Highlight 1: New path analysis functions

Movement-Path

Thanks to @isha822, @vybhav72954, and @Haris-bin-shakeel for contributing three new path analysis functions! The movement.kinematics.path sub-module now provides a comprehensive suite of trajectory metrics:

Note

By path we refer to the spatial trajectory of an individual over the time span of the data.
While these metrics can be computed based on any set of keypoints, they are most meaningful when applied to a single keypoint representing the individual's overall position (e.g., centroid).

  1. compute_path_straightness() computes the straightness index of a path — the ratio of the Euclidean ("beeline") distance between start and end positions to the total path length. Values range from 0 (returned to start) to 1 (perfectly straight).

  2. compute_directional_change() computes the rate of heading change per time step — the absolute turning angle divided by the time interval.

  3. compute_path_deviation() computes the perpendicular distance of each position from the straight line connecting the first and last valid positions. Zero means the position lies exactly on the straight line; larger values indicate greater lateral excursion.

from movement.kinematics import (
    compute_path_straightness,
    compute_directional_change,
    compute_path_deviation,
)

# Compute the path traced by each individual's centroid
centroid = ds.position.mean(dim="keypoint")

si = compute_path_straightness(centroid)

dc = compute_directional_change(centroid)

deviation = compute_path_deviation(centroid)
max_deviation = deviation.max(dim="time") 

Additionally, compute_turning_angle has been moved from movement.kinematics.orientation to movement.kinematics.path, alongside the other path metrics. It remains importable from movement.kinematics as before.

Warning

The start and stop keyword arguments have been removed from compute_path_length(). Use xarray's .sel() for time-windowing instead:

# Before
compute_path_length(position, start=0, stop=100)

# After
compute_path_length(position.sel(time=slice(0, 100)))

⚡️ Highlight 2: Dimension names renamed from plural to singular

  • Rename xarray dimensions from plural to singular by @niksirbi in #973

The xarray dimension names "keypoints" and "individuals" have been renamed to "keypoint" and "individual", following standard pandas/xarray conventions where dimensions represent variable names, not collections.

Warning

This is a breaking change. Any code that references these dimension names directly must be updated.

Migrating your code:

# Before (v0.16.0 and earlier)
ds.position.sel(keypoints="snout")
ds.position.sel(individuals="mouse1")
ds.sizes["keypoints"]

# After (v0.17.0)
ds.position.sel(keypoint="snout")
ds.position.sel(individual="mouse1")
ds.sizes["keypoint"]

The dim parameter of movement.kinematics.compute_pairwise_distances() has also been updated:

# Before
compute_pairwise_distances(data, dim="keypoints", pairs="all")

# After
compute_pairwise_distances(data, dim="keypoint", pairs="all")

Migrating netCDF files saved with previous versions:

If you have netCDF files saved with movement < 0.17.0, you can update them using the rename_legacy_dimensions() utility (available temporarily to help with the transition):

import xarray as xr
from movement.io.load import rename_legacy_dimensions

ds = xr.open_dataset("old_dataset.nc")
ds = rename_legacy_dimensions(ds)
ds.to_netcdf("new_dataset.nc")

🔌 Interoperability

  • Add get_supported_source_software() to expose supported formats by @niksirbi in #968

This helps developers of tools that depend on movement programmatically discover which tracking software formats are supported.

This paves the way for supporting more tracking software in the future.

🐛 Bug fixes

🗑️ Removed functions

  • Remove deprecated funcs and document deprecation lifecycle by @niksirbi in #967

The following deprecated functions have been removed:

🤝 Improving the contributor experience

  • Migrate dev and docs from optional dependencies to PEP 735 dependency groups by @lochhh in #956
  • Fix invalid --all-groups flag in contributing docs by @niksirbi in #979
  • Add pre-commit hook to prevent hardcoded movement website references in docs by @lochhh in #1010
  • Update bbox nan fixture by @anna-teruel in #1020

📚 Documentation

  • Update and clarify the project's long-term vision by @niksirbi in #1019
  • Show ABlog postcard in blog post sidebar by @niksirbi in #990

🧹 Housekeeping

  • Use custom typehints_formatter to handle PEP 695 TypeAliasType by @lochhh in #969
  • Pin sphinx-autodoc-typehints>=3.10.4 by @lochhh in #1016
  • Use GitHub App token in contributors workflow by @niksirbi in #971
  • Contributors-Readme-Action: Update contributors list by @github-actions[bot] in #970
  • Bump conda-incubator/setup-miniconda from 3.3.0 to 4.0.1 by @dependabot[bot] in #972
  • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #974
  • Contributors-Readme-Action: Update contributors list by @neuroinformatics-unit-bot[bot] in #1015
  • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #1018

New Contributors

Full Changelog: v0.16.0...v0.17.0