From 1b4277b3d7990f9b81765e8102c63e1abb87baee Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 16 Jan 2025 16:11:27 -0500 Subject: [PATCH 1/5] fix time support issue --- pynapple/core/time_series.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pynapple/core/time_series.py b/pynapple/core/time_series.py index 734a0c4b..e22872b8 100644 --- a/pynapple/core/time_series.py +++ b/pynapple/core/time_series.py @@ -382,7 +382,7 @@ def bin_average(self, bin_size, ep=None, time_units="s"): t, d = _bin_average(time_array, data_array, starts, ends, bin_size) - return _initialize_tsd_output(self, d, time_index=t) + return _initialize_tsd_output(self, d, time_index=t, time_support=ep) def dropna(self, update_time_support=True): """Drop every row containing NaNs. By default, the time support is updated to start and end around the time points that are non NaNs. @@ -477,7 +477,7 @@ def convolve(self, array, ep=None, trim="both"): new_data_array = _convolve(time_array, data_array, starts, ends, array, trim) - return _initialize_tsd_output(self, new_data_array, time_index=time_array) + return _initialize_tsd_output(self, new_data_array, time_index=time_array, time_support=ep) def smooth(self, std, windowsize=None, time_units="s", size_factor=100, norm=True): """Smooth a time series with a gaussian kernel. @@ -634,7 +634,7 @@ def interpolate(self, ts, ep=None, left=None, right=None): start += len(t) - return _initialize_tsd_output(self, new_d, time_index=new_t) + return _initialize_tsd_output(self, new_d, time_index=new_t, time_support=ep) class TsdTensor(_BaseTsd): From cf8ed800fea35be479d5dc650a6c2fd359eca058 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 16 Jan 2025 16:20:31 -0500 Subject: [PATCH 2/5] added tests --- tests/test_time_series.py | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/test_time_series.py b/tests/test_time_series.py index 7a17aedf..8de6e9d0 100755 --- a/tests/test_time_series.py +++ b/tests/test_time_series.py @@ -649,6 +649,23 @@ def test_smooth_raise_error(self, tsd): ], ) class TestTsd: + + def test_bin_average_time_support(self, tsd): + ep = nap.IntervalSet(tsd.time_support.start[0]+1, tsd.time_support.end[0]-1) + out = tsd.bin_average(0.1, ep=ep) + assert np.all(out.time_support == ep) + + def test_convolve_time_support(self, tsd): + ep = nap.IntervalSet(tsd.time_support.start[0] + 1, tsd.time_support.end[0] - 1) + out = tsd.convolve(np.ones(10), ep=ep) + assert np.all(out.time_support == ep) + + def test_interpolate_time_support(self, tsd): + ep = nap.IntervalSet(tsd.time_support.start[0] + 1, tsd.time_support.end[0] - 1) + ts = nap.Ts(np.linspace(0, 10, 20)) + out = tsd.interpolate(ts, ep=ep) + assert np.all(out.time_support == ep) + def test_as_series(self, tsd): assert isinstance(tsd.as_series(), pd.Series) @@ -978,6 +995,23 @@ def test_interpolate_with_ep(self, tsd): ], ) class TestTsdFrame: + + def test_bin_average_time_support(self, tsdframe): + ep = nap.IntervalSet(tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1) + out = tsdframe.bin_average(0.1, ep=ep) + assert np.all(out.time_support == ep) + + def test_convolve_time_support(self, tsdframe): + ep = nap.IntervalSet(tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1) + out = tsdframe.convolve(np.ones(10), ep=ep) + assert np.all(out.time_support == ep) + + def test_interpolate_time_support(self, tsdframe): + ep = nap.IntervalSet(tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1) + ts = nap.Ts(np.linspace(0, 10, 20)) + out = tsdframe.interpolate(ts, ep=ep) + assert np.all(out.time_support == ep) + def test_as_dataframe(self, tsdframe): assert isinstance(tsdframe.as_dataframe(), pd.DataFrame) @@ -1589,6 +1623,22 @@ def test_count_dtype(self, dtype, expectation, ts): ) class TestTsdTensor: + def test_bin_average_time_support(self, tsdtensor): + ep = nap.IntervalSet(tsdtensor.time_support.start[0]+1, tsdtensor.time_support.end[0]-1) + out = tsdtensor.bin_average(0.1, ep=ep) + assert np.all(out.time_support == ep) + + def test_convolve_time_support(self, tsdtensor): + ep = nap.IntervalSet(tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1) + out = tsdtensor.convolve(np.ones(10), ep=ep) + assert np.all(out.time_support == ep) + + def test_interpolate_time_support(self, tsdtensor): + ep = nap.IntervalSet(tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1) + ts = nap.Ts(np.linspace(0, 10, 20)) + out = tsdtensor.interpolate(ts, ep=ep) + assert np.all(out.time_support == ep) + def test_return_ndarray(self, tsdtensor): np.testing.assert_array_equal(tsdtensor[0], tsdtensor.values[0]) From 798e1d5ec26184bd0a79c4cca4188c3014bd385b Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 16 Jan 2025 16:21:50 -0500 Subject: [PATCH 3/5] linted --- pynapple/core/time_series.py | 4 +++- tests/test_time_series.py | 26 +++++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/pynapple/core/time_series.py b/pynapple/core/time_series.py index e22872b8..213d100a 100644 --- a/pynapple/core/time_series.py +++ b/pynapple/core/time_series.py @@ -477,7 +477,9 @@ def convolve(self, array, ep=None, trim="both"): new_data_array = _convolve(time_array, data_array, starts, ends, array, trim) - return _initialize_tsd_output(self, new_data_array, time_index=time_array, time_support=ep) + return _initialize_tsd_output( + self, new_data_array, time_index=time_array, time_support=ep + ) def smooth(self, std, windowsize=None, time_units="s", size_factor=100, norm=True): """Smooth a time series with a gaussian kernel. diff --git a/tests/test_time_series.py b/tests/test_time_series.py index 8de6e9d0..9331003b 100755 --- a/tests/test_time_series.py +++ b/tests/test_time_series.py @@ -651,7 +651,7 @@ def test_smooth_raise_error(self, tsd): class TestTsd: def test_bin_average_time_support(self, tsd): - ep = nap.IntervalSet(tsd.time_support.start[0]+1, tsd.time_support.end[0]-1) + ep = nap.IntervalSet(tsd.time_support.start[0] + 1, tsd.time_support.end[0] - 1) out = tsd.bin_average(0.1, ep=ep) assert np.all(out.time_support == ep) @@ -997,17 +997,23 @@ def test_interpolate_with_ep(self, tsd): class TestTsdFrame: def test_bin_average_time_support(self, tsdframe): - ep = nap.IntervalSet(tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1) + ep = nap.IntervalSet( + tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1 + ) out = tsdframe.bin_average(0.1, ep=ep) assert np.all(out.time_support == ep) def test_convolve_time_support(self, tsdframe): - ep = nap.IntervalSet(tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1) + ep = nap.IntervalSet( + tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1 + ) out = tsdframe.convolve(np.ones(10), ep=ep) assert np.all(out.time_support == ep) def test_interpolate_time_support(self, tsdframe): - ep = nap.IntervalSet(tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1) + ep = nap.IntervalSet( + tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1 + ) ts = nap.Ts(np.linspace(0, 10, 20)) out = tsdframe.interpolate(ts, ep=ep) assert np.all(out.time_support == ep) @@ -1624,17 +1630,23 @@ def test_count_dtype(self, dtype, expectation, ts): class TestTsdTensor: def test_bin_average_time_support(self, tsdtensor): - ep = nap.IntervalSet(tsdtensor.time_support.start[0]+1, tsdtensor.time_support.end[0]-1) + ep = nap.IntervalSet( + tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1 + ) out = tsdtensor.bin_average(0.1, ep=ep) assert np.all(out.time_support == ep) def test_convolve_time_support(self, tsdtensor): - ep = nap.IntervalSet(tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1) + ep = nap.IntervalSet( + tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1 + ) out = tsdtensor.convolve(np.ones(10), ep=ep) assert np.all(out.time_support == ep) def test_interpolate_time_support(self, tsdtensor): - ep = nap.IntervalSet(tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1) + ep = nap.IntervalSet( + tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1 + ) ts = nap.Ts(np.linspace(0, 10, 20)) out = tsdtensor.interpolate(ts, ep=ep) assert np.all(out.time_support == ep) From 61ae0c8f82549d8fea354bd28234147fd19ba967 Mon Sep 17 00:00:00 2001 From: BalzaniEdoardo Date: Thu, 16 Jan 2025 16:39:41 -0500 Subject: [PATCH 4/5] improved tests --- tests/test_time_series.py | 60 +++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/tests/test_time_series.py b/tests/test_time_series.py index 9331003b..b1828f40 100755 --- a/tests/test_time_series.py +++ b/tests/test_time_series.py @@ -650,18 +650,30 @@ def test_smooth_raise_error(self, tsd): ) class TestTsd: - def test_bin_average_time_support(self, tsd): - ep = nap.IntervalSet(tsd.time_support.start[0] + 1, tsd.time_support.end[0] - 1) + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_bin_average_time_support(self, tsd, delta_ep): + ep = nap.IntervalSet( + tsd.time_support.start[0] + delta_ep[0], + tsd.time_support.end[0] + delta_ep[1], + ) out = tsd.bin_average(0.1, ep=ep) assert np.all(out.time_support == ep) - def test_convolve_time_support(self, tsd): - ep = nap.IntervalSet(tsd.time_support.start[0] + 1, tsd.time_support.end[0] - 1) + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_convolve_time_support(self, tsd, delta_ep): + ep = nap.IntervalSet( + tsd.time_support.start[0] + delta_ep[0], + tsd.time_support.end[0] + delta_ep[1], + ) out = tsd.convolve(np.ones(10), ep=ep) assert np.all(out.time_support == ep) - def test_interpolate_time_support(self, tsd): - ep = nap.IntervalSet(tsd.time_support.start[0] + 1, tsd.time_support.end[0] - 1) + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_interpolate_time_support(self, tsd, delta_ep): + ep = nap.IntervalSet( + tsd.time_support.start[0] + delta_ep[0], + tsd.time_support.end[0] + delta_ep[1], + ) ts = nap.Ts(np.linspace(0, 10, 20)) out = tsd.interpolate(ts, ep=ep) assert np.all(out.time_support == ep) @@ -996,23 +1008,29 @@ def test_interpolate_with_ep(self, tsd): ) class TestTsdFrame: - def test_bin_average_time_support(self, tsdframe): + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_bin_average_time_support(self, tsdframe, delta_ep): ep = nap.IntervalSet( - tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1 + tsdframe.time_support.start[0] + delta_ep[0], + tsdframe.time_support.end[0] + delta_ep[1], ) out = tsdframe.bin_average(0.1, ep=ep) assert np.all(out.time_support == ep) - def test_convolve_time_support(self, tsdframe): + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_convolve_time_support(self, tsdframe, delta_ep): ep = nap.IntervalSet( - tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1 + tsdframe.time_support.start[0] + delta_ep[0], + tsdframe.time_support.end[0] + delta_ep[1], ) out = tsdframe.convolve(np.ones(10), ep=ep) assert np.all(out.time_support == ep) - def test_interpolate_time_support(self, tsdframe): + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_interpolate_time_support(self, tsdframe, delta_ep): ep = nap.IntervalSet( - tsdframe.time_support.start[0] + 1, tsdframe.time_support.end[0] - 1 + tsdframe.time_support.start[0] + delta_ep[0], + tsdframe.time_support.end[0] + delta_ep[1], ) ts = nap.Ts(np.linspace(0, 10, 20)) out = tsdframe.interpolate(ts, ep=ep) @@ -1629,23 +1647,29 @@ def test_count_dtype(self, dtype, expectation, ts): ) class TestTsdTensor: - def test_bin_average_time_support(self, tsdtensor): + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_bin_average_time_support(self, delta_ep, tsdtensor): ep = nap.IntervalSet( - tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1 + tsdtensor.time_support.start[0] + delta_ep[0], + tsdtensor.time_support.end[0] + delta_ep[1], ) out = tsdtensor.bin_average(0.1, ep=ep) assert np.all(out.time_support == ep) - def test_convolve_time_support(self, tsdtensor): + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_convolve_time_support(self, tsdtensor, delta_ep): ep = nap.IntervalSet( - tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1 + tsdtensor.time_support.start[0] + delta_ep[0], + tsdtensor.time_support.end[0] + delta_ep[1], ) out = tsdtensor.convolve(np.ones(10), ep=ep) assert np.all(out.time_support == ep) - def test_interpolate_time_support(self, tsdtensor): + @pytest.mark.parametrize("delta_ep", [(1, -1), (-1, -1), (1, 1)]) + def test_interpolate_time_support(self, tsdtensor, delta_ep): ep = nap.IntervalSet( - tsdtensor.time_support.start[0] + 1, tsdtensor.time_support.end[0] - 1 + tsdtensor.time_support.start[0] + delta_ep[0], + tsdtensor.time_support.end[0] + delta_ep[1], ) ts = nap.Ts(np.linspace(0, 10, 20)) out = tsdtensor.interpolate(ts, ep=ep) From 925cb43280964c9dc080eb30b30721a169459ec4 Mon Sep 17 00:00:00 2001 From: Guillaume Viejo Date: Fri, 17 Jan 2025 06:00:09 -0500 Subject: [PATCH 5/5] Bumping v0.8.1 --- README.md | 2 +- doc/releases.md | 4 ++++ pynapple/__init__.py | 2 +- pyproject.toml | 2 +- setup.py | 4 ++-- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 98443375..bd6618f7 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ pynapple is a light-weight python library for neurophysiological data analysis. New release :fire: ------------------ -### pynapple >= 0.8 +### pynapple >= 0.8.1 The objects `IntervalSet`, `TsdFrame` and `TsGroup` inherits a new metadata class. It is now possible to add labels for each interval of an `IntervalSet`, each column of a `TsdFrame` and each unit of a `TsGroup`. diff --git a/doc/releases.md b/doc/releases.md index 44f19117..2494aa0c 100644 --- a/doc/releases.md +++ b/doc/releases.md @@ -18,6 +18,10 @@ of the Flatiron institute. ## Releases +### 0.8.1 (2025-01-17) + +- Bugfix : time support was not updated for `bin_average` and `interpolate` with new `_initialize_tsd_output` method + ### 0.8.0 (2025-01-15) - New private class: `_MetadataMixin` (core/metadata_class.py). Can be inherited by `IntervalSet`, `TsdFrame` and `TsGroup`. diff --git a/pynapple/__init__.py b/pynapple/__init__.py index 9b532a40..cb104193 100644 --- a/pynapple/__init__.py +++ b/pynapple/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.8.0" +__version__ = "0.8.1" from .core import ( IntervalSet, Ts, diff --git a/pyproject.toml b/pyproject.toml index 788c78a2..42a8c6f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pynapple" -version = "0.8.0" +version = "0.8.1" description = "PYthon Neural Analysis Package Pour Laboratoires d’Excellence" readme = "README.md" authors = [{ name = "Guillaume Viejo", email = "guillaume.viejo@gmail.com" }] diff --git a/setup.py b/setup.py index f3b279e9..2414d912 100644 --- a/setup.py +++ b/setup.py @@ -59,8 +59,8 @@ test_suite='tests', tests_require=test_requirements, url='https://github.com/pynapple-org/pynapple', - version='v0.8.0', + version='v0.8.1', zip_safe=False, long_description_content_type='text/markdown', - download_url='https://github.com/pynapple-org/pynapple/archive/refs/tags/v0.8.0.tar.gz' + download_url='https://github.com/pynapple-org/pynapple/archive/refs/tags/v0.8.1.tar.gz' )