From 1f25348d02365624a889f860e85e44b7b1b76adf Mon Sep 17 00:00:00 2001 From: Swagat Mishra Date: Fri, 13 Mar 2026 10:46:03 +0530 Subject: [PATCH 1/3] Pin netCDF4 <1.7.3 to avoid HDF5 incompatibility (fixes #687) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c8cb184bd..3ce349f28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ dependencies = [ "numpy>=2.0.0", "pandas", "h5py", - "netCDF4<1.7.3", + "netCDF4>=1.7.2,<1.7.3", "tables>=3.10.1", "attrs", "pooch", From f53fb3071a80548b86d1998a1c43e8ac44f6322d Mon Sep 17 00:00:00 2001 From: Swagat Mishra Date: Wed, 18 Mar 2026 01:49:50 +0530 Subject: [PATCH 2/3] Handle null vectors explicitly in convert_to_unit for Cartesian coordinates --- movement/utils/vector.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/movement/utils/vector.py b/movement/utils/vector.py index ca7430df1..bd8024bb1 100644 --- a/movement/utils/vector.py +++ b/movement/utils/vector.py @@ -82,7 +82,10 @@ def convert_to_unit(data: xr.DataArray) -> xr.DataArray: """ if "space" in data.dims: validate_dims_coords(data, {"space": ["x", "y"]}) - return data / compute_norm(data) + norm = compute_norm(data) + unit = data / norm + unit = xr.where(norm == 0, np.nan, unit) + return unit elif "space_pol" in data.dims: validate_dims_coords(data, {"space_pol": ["rho", "phi"]}) # Set both rho and phi values to NaN at null vectors (where rho = 0) From 9248a3312a1c0197cc3cadbad61271272a1e3237 Mon Sep 17 00:00:00 2001 From: Swagat Mishra Date: Wed, 18 Mar 2026 02:34:24 +0530 Subject: [PATCH 3/3] Improve xarray compatibility in vector utilities (fixes #899) --- movement/utils/vector.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/movement/utils/vector.py b/movement/utils/vector.py index bd8024bb1..ec6d92758 100644 --- a/movement/utils/vector.py +++ b/movement/utils/vector.py @@ -147,8 +147,7 @@ def cart2pol(data: xr.DataArray) -> xr.DataArray: # Make all zeros in phi positive zeros # - where rho == 0, set phi to 0 # - where rho != 0, keep the phi value from atan2 - phi = xr.where(np.isclose(rho.values, 0.0, atol=1e-9), 0.0, phi) - + phi = xr.where(np.isclose(rho, 0.0, atol=1e-9), 0.0, phi) # Replace space dim with space_pol dims = list(data.dims) dims[dims.index("space")] = "space_pol" @@ -301,11 +300,12 @@ def compute_signed_angle_2d( cross *= -1.0 dot = u_x * v_x + u_y * v_y - angles = np.arctan2(cross, dot) - assert isinstance(angles, xr.DataArray) + angles = xr.apply_ufunc(np.arctan2, cross, dot) + # arctan2 returns values in [-pi, pi]. - # We need to map -pi angles to pi, to stay in the (-pi, pi] range - angles.values[angles <= -np.pi] = np.pi + # Map -pi to pi to stay in the (-pi, pi] range + angles = xr.where(angles <= -np.pi, np.pi, angles) + angles.name = "signed_angle" return angles