Releases: neuroinformatics-unit/movement
v0.12.0
What's Changed
⚡️ Work begins on coordinate system transforms
@animeshsasan has kicked off our efforts in this area.
He has added a new function for computing homography-based transforms between sets of points on a plane. This is the first step towards supporting multi-session alignment in a common coordinate system, with further work planned for upcoming releases (see issue #565).
- Add function to estimate perspective transform between two planes by @animeshsasan in #696
🧹 Housekeeping
- Add workflow to check conda installation weekly by @niksirbi in #701
- Fix errors in conda install check workflow by @niksirbi in #703
- Remove setup-miniconda action from test workflow by @niksirbi in #705
- Add OSSS 2026 banner by @adamltyson in #707
Full Changelog: v0.11.1...v0.12.0
v0.11.1
This release patches some minor issues with our website and welcomes one new contributor to the project.
The actual package functionality is not affected.
What's Changed
- Move displacement blog image to its proper place by @niksirbi in #697
- suppressed hash value of SHA from pooch by @LakshmiSowmya04 in #695
- More specific project description in pyproject.toml by @niksirbi in #698
- Fix issues with multi-version docs by @niksirbi in #700
New Contributors
- @LakshmiSowmya04 made their first contribution in #695
Full Changelog: v0.11.0...v0.11.1
v0.11.0
Summary
movement v0.11.0 redefines displacement vectors, simplifies installation via pip and uv, and introduces multi-version documentation. It also brings support for 3D DeepLabCut files and welcomes many new contributors 🎉.
What’s changed
↗️ Refined displacement vectors
@carlocastoldi has overhauled how movement computes displacement vectors, making the definitions more explicit, flexible, and intuitive for users. You can read all about these changes in our latest blog post, written by Carlo.
- improve resulting displacement vectors by @carlocastoldi in #657
- Add blog post about displacement's API changes by @carlocastoldi in #688
⚡️ Simplified installation via pip and uv
We’ve streamlined the dependency setup so that movement can now be installed directly with pip or uv—no extra steps required.
Early adopters can try:
uv pip install movementSee our updated installation guide for full details.
📚 Multi-version documentation
Thanks to @animeshsasan, the documentation now includes a version switcher! This means that, going forward, you will be able to browse docs for multiple versions of movement, making it much easier to follow along with future updates and interface changes.
- Changes for multi-version docs by @animeshsasan in #668
📂 Improved handling of DeepLabCut files
Through a collaboration between @Akseli-Ilmanen and @lochhh, movement can now load and save DeepLabCut files with 3D coordinates (x, y, z).
In addition, @CeliaLrt clarified the documentation to make explicit that movement currently requires all keypoints to be shared across individuals.
- Support loading and saving 3D DeepLabCut poses by @lochhh in #686
- Add documentation to specify Movement require identical keypoints (#150) by @CeliaLrt in #658
🧹 Housekeeping
- Update links to SLEAP docs by @niksirbi in #681
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #682
- Update links to animovement by @niksirbi in #684
- Pin netcdf<1.7.3 to fix failing integration tests by @niksirbi in #685
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #692
- Contributors-Readme-Action: Update contributors list by @github-actions[bot] in #690
- Bump actions/download-artifact from 5 to 6 by @dependabot[bot] in #691
🧑💻 New Contributors
- @carlocastoldi made their first contribution in #657
- @CeliaLrt made their first contribution in #658
- @animeshsasan made their first contribution in #66
- @Akseli-Ilmanen made their first contribution by co-authoring #686
Full Changelog: v0.10.0...v0.11.0
v0.10.0
What's Changed
✨ Highlight ✨ movement meets FreeMoCap
A new example demonstrating how to read 3D data from FreeMoCap recordings as movement poses datasets. Thanks to @maxstaras for collecting the data and writing this example! 🚀
- Adding FreeMoCap example by @maxstaras in #633
New feature: export a bounding boxes dataset as a VIA-tracks .csv file
- Export bboxes dataset as VIA tracks .csv file by @sfmig in #580
- Update example to show usage of
to_via_tracks_filefrom PR 580 by @sfmig in #680
Documentation
- Add missing contributors by @niksirbi in #665
- Mention typical timing of community calls on website and README by @niksirbi in #672
Housekeeping
- Pin napari-video >= 0.2.13 by @niksirbi in #662
- Contributors-Readme-Action: Update contributors list by @github-actions[bot] in #671
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #673
- Bump actions/download-artifact from 4 to 5 by @dependabot[bot] in #674
New Contributors
- @maxstaras made their first contribution in #633
Full Changelog: v0.9.0...v0.10.0
v0.9.0
What's Changed
New feature: compute kinetic energy
- feat: compute_kinetic_energy for per-individual KE decomposition (#228) by @vtushar06 in #623
The compute_kinetic_energy function is the newest addition to the movement.kinematics module. It can be used to derive the total kinetic energy per individual, or decompose it into "translational" (centre-of-mass motion) and "internal" components (motion of keypoints relative to individual's centre-of-mass). Thanks to @vtushar06 for driving this forward.
Improvements to documentation
Spearheaded by @lochhh.
- Replace external links to movement docs with explicit targets by @lochhh in #642
- Aggregate API docs for flat modules by @lochhh in #648
- Add gallery of examples in API documentation by @lochhh in #644
Housekeeping
- Contributors-Readme-Action: Update contributors list by @github-actions[bot] in #650
- Bump akhilmhdh/contributors-readme-action from 2.3.10 to 2.3.11 by @dependabot[bot] in #651
- Add downloads badge by @adamltyson in #652
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #653
Full Changelog: v0.8.2...v0.9.0
v0.8.2
v0.8.1
v0.8.0
✨ Highlight ✨ visualise bounding boxes
Thanks to the persistent efforts of @DPWebster, bounding boxes can now be displayed in our GUI as a napari Shapes layer 🎉 (for now this only apples to bounding boxes datasets). See the updated user guide for more info.
- Visualize bounding boxes as Napari shapes layer by @DPWebster in #590
movement now has a logo
- Add
movementlogo and favicon to the website by @niksirbi in #614 - Update logo, favicon, and overview images by @niksirbi in #632
Miscellaneous
- fix: update default individual name from 'individual_0' to 'id_0' acr… by @vtushar06 in #618
- Accommodate sample datasets that are ZIP archives by @niksirbi in #619
Housekeeping
- Fetch full commit history in
build-sphinx-docsby @niksirbi in #621 - Restrict deploy_sphinx_docs to
mainbranch on manual workflow dispatch by @lochhh in #624 - Contributors-Readme-Action: Update contributors list by @github-actions in #627
- Apply monospace formatting for
movementin CONTRIBUTING.md by @niksirbi in #626 - [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in #629
New Contributors
- @vtushar06 made their first contribution in #618
- @DPWebster made their first contribution in #590
Full Changelog: v0.7.1...v0.8.0
v0.7.1
✨ Highlight ✨ netCDF is the file format 🗃️ of choice for saving movement datasets 💾
Saving to netCDF is the recommended way to preserve the complete state of your analysis, including all variables, coordinates, and attributes. Below is an example of how you may integrate netCDF into you movement-powered workflows:
from movement.io import load_poses
from movement.filtering import rolling_filter
from movement.kinematics import compute_speed
ds = load_poses.from_file(
"path/to/my_data.h5", source_software="DeepLabCut", fps=30
)
# Apply a rolling median filter to smooth the position data
ds["position_smooth"] = rolling_filter(
ds["position"], window=5, statistic="median"
)
# Compute speed based on the smoothed position data
ds["speed"] = compute_speed(ds["position_smooth"])
# Save the dataset to a netCDF file
# This includes the original position and confidence data,
# the smoothed position, and the computed speed
ds.to_netcdf("my_data_processed.nc")To later load the dataset back from disk:
import xarray as xr
ds = xr.open_dataset("my_data_processed.nc")Miscellaneous
- Completely remove deprecated median_filter function by @niksirbi in #611
- Add log_to_attrs decorator to scale function by @niksirbi in #604
Warning
The deprecated movement.filtering.median_filter() function has been completely removed. Use movement.filtering.median_filter() instead, with statistic="median".
Housekeeping
- Change path to match GIN repo current status by @sfmig in #603
- Add note for Apple silicon users with macOS <=13 by @niksirbi in #605
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in #607
- chore: run codespell throughout fixing a typo by @yarikoptic in #608
- Remove announcement banner for Open Software Week by @niksirbi in #610
- Remove "easily" from some longer examples by @adamltyson in #612
New Contributors
- @yarikoptic made their first contribution in #608
Full Changelog: v0.7.0...v0.7.1
v0.7.0
🎉 Highlight: support for the NWB file format 🧠
movement poses datasets can now be loaded from and saved to NeuroData Without Borders (NWB) files. The pose tracks are formatted according to the ndx-pose extension.
This was a global team effort started long ago by @edeno, continued by me, and finally wrapped up by @lochhh.
Many thanks go to @luiztauffer for providing advice and crash-testing.
Example usage:
import pynwb
import xarray as xr
from movement.io import load_poses, save_poses
# Load pose tracks from open NWBFile objects:
with pynwb.NWBHDF5IO("path/to/file.nwb", mode="r") as io:
nwb_file = io.read()
ds = load_poses.from_nwb_file(nwb_file)
# Or, directly load pose tracks from NWB files on disk.
# Here merge data from 2 files into a multi-individual dataset:
ds_singles = [load_poses.from_nwb_file(f) for f in ["id1.nwb", "id2.nwb"]]
ds_multi = xr.merge(ds_singles)
# Create NWBFile objects for each individual and save them to disk
nwb_files = save_poses.to_nwb_file(ds)
for file in nwb_files:
with NWBHDF5IO(f"{file.identifier}.nwb", "w") as io:
io.write(file)As always, let us know if you encounter any hurdles with this.
What's Changed
- Fix remaining napari future warning by @sfmig in #594
- Temporarily suppress napari warnings by @lochhh in #592
- Replace numpy legacy random generation by @lochhh in #597
- Update the contributing guide by @niksirbi in #598
- Refactor
reports.pyby @lochhh in #557 - Ignore SWC URL in linkcheck by @lochhh in #601
- Add I/O support for the ndx-pose NWB extension: take 2 by @niksirbi in #360
Full Changelog: v0.6.1...v0.7.0

