From a8f15bde880a9a7b5264bdd0e1cba81606001383 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Tue, 26 Dec 2023 19:56:36 +0100 Subject: [PATCH 01/17] change index shift to avoid error when synchrofacts occur in the last bin --- elephant/statistics.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/elephant/statistics.py b/elephant/statistics.py index 868b4b06d..c60c393b2 100644 --- a/elephant/statistics.py +++ b/elephant/statistics.py @@ -1548,13 +1548,8 @@ def _epoch_no_spread(self): if self.sampling_rate: # ensure that spikes are not on the bin edges bin_shift = .5 / self.sampling_rate - left_edges -= bin_shift + left_edges += bin_shift - # Ensure that an epoch does not start before the minimum t_start. - # Note: all spike trains share the same t_start and t_stop. - if left_edges[0] < self.t_start: - left_edges[0] = self.t_start - durations[0] -= bin_shift else: warnings.warn('No sampling rate specified. ' 'Note that using the complexity epoch to get ' From 3995a83aeb976f5549ce6daabf233fdf38e0e9ea Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Mon, 5 Feb 2024 11:40:15 +0100 Subject: [PATCH 02/17] Undo changes, this is the wrong place for such a fix, since the error only appears in synchrotool and binnedspiketrains are used in many other places --- elephant/statistics.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/elephant/statistics.py b/elephant/statistics.py index c60c393b2..7affdc4be 100644 --- a/elephant/statistics.py +++ b/elephant/statistics.py @@ -1548,7 +1548,13 @@ def _epoch_no_spread(self): if self.sampling_rate: # ensure that spikes are not on the bin edges bin_shift = .5 / self.sampling_rate - left_edges += bin_shift + left_edges -= bin_shift + + # Ensure that an epoch does not start before the minimum t_start. + # Note: all spike trains share the same t_start and t_stop. + if left_edges[0] < self.t_start: + left_edges[0] = self.t_start + durations[0] -= bin_shift else: warnings.warn('No sampling rate specified. ' From 3613ac391001feaaed3da25ad26c514ee2176740 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Mon, 5 Feb 2024 11:42:41 +0100 Subject: [PATCH 03/17] Fix last bin error from Jonas and Sven Co-authored by: skrausse Co-authored by: jo460464 --- doc/authors.rst | 2 ++ elephant/spike_train_synchrony.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/doc/authors.rst b/doc/authors.rst index 4af092105..31be9f1b9 100644 --- a/doc/authors.rst +++ b/doc/authors.rst @@ -51,6 +51,8 @@ contribution, and may not be the current affiliation of a contributor. * Florian Porrmann [13] * Sarah Pilz [13] * Oliver Kloß [1] +* Jonas Oberste-Frielinghaus [1] +* Sven Krausse [1] 1. Institute of Neuroscience and Medicine (INM-6) and Institute for Advanced Simulation (IAS-6) and JARA-Institute Brain Structure-Function Relationships (INM-10), Jülich Research Centre, Jülich, Germany 2. Unité de Neurosciences, Information et Complexité, CNRS UPR 3293, Gif-sur-Yvette, France diff --git a/elephant/spike_train_synchrony.py b/elephant/spike_train_synchrony.py index bf6e181e6..9469e3150 100644 --- a/elephant/spike_train_synchrony.py +++ b/elephant/spike_train_synchrony.py @@ -397,10 +397,12 @@ def annotate_synchrofacts(self): ``self.epoch.array_annotations`` *in-place*. """ epoch_complexities = self.epoch.array_annotations['complexity'] + bin_shift = .5 / self.sampling_rate right_edges = ( self.epoch.times.magnitude.flatten() + self.epoch.durations.rescale( self.epoch.times.units).magnitude.flatten() + + bin_shift.rescale(self.epoch.times.units).magnitude ) for idx, st in enumerate(self.input_spiketrains): From 74dc07f25e484f725edb30885c57e1b95df0de73 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Wed, 3 Apr 2024 15:25:53 +0200 Subject: [PATCH 04/17] fix erroneous indentation --- elephant/statistics.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/elephant/statistics.py b/elephant/statistics.py index 7affdc4be..ed3abdc6e 100644 --- a/elephant/statistics.py +++ b/elephant/statistics.py @@ -1550,11 +1550,11 @@ def _epoch_no_spread(self): bin_shift = .5 / self.sampling_rate left_edges -= bin_shift - # Ensure that an epoch does not start before the minimum t_start. - # Note: all spike trains share the same t_start and t_stop. - if left_edges[0] < self.t_start: - left_edges[0] = self.t_start - durations[0] -= bin_shift + # Ensure that an epoch does not start before the minimum t_start. + # Note: all spike trains share the same t_start and t_stop. + if left_edges[0] < self.t_start: + left_edges[0] = self.t_start + durations[0] -= bin_shift else: warnings.warn('No sampling rate specified. ' From f7c91b097c6cfd3fcf0dddf690d109dd369b3a36 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 11:04:14 +0200 Subject: [PATCH 05/17] simplify binning error test --- elephant/test/test_spike_train_synchrony.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/elephant/test/test_spike_train_synchrony.py b/elephant/test/test_spike_train_synchrony.py index 58be525eb..07aa532d9 100644 --- a/elephant/test/test_spike_train_synchrony.py +++ b/elephant/test/test_spike_train_synchrony.py @@ -390,16 +390,16 @@ def test_binning_for_input_with_rounding_errors(self): sampling_rate = 30000 / pq.s - spiketrains = [neo.SpikeTrain(np.arange(1000) * pq.s / 30000, + spiketrains = [neo.SpikeTrain(np.arange(10) * pq.s / 30000, t_stop=.1 * pq.s), - neo.SpikeTrain(np.arange(2000, step=2) * pq.s / 30000, + neo.SpikeTrain(np.arange(20, step=2) * pq.s / 30000, t_stop=.1 * pq.s)] - first_annotations = np.ones(1000) + first_annotations = np.ones(10) first_annotations[::2] = 2 - second_annotations = np.ones(1000) - second_annotations[:500] = 2 + second_annotations = np.ones(10) + second_annotations[:5] = 2 correct_annotations = np.array([first_annotations, second_annotations]) From d7846f469d7f873c29832d51c11c69e89a7f96ec Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 11:25:03 +0200 Subject: [PATCH 06/17] add test for synchrofact in last bin where indexing error used to occur --- elephant/test/test_spike_train_synchrony.py | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/elephant/test/test_spike_train_synchrony.py b/elephant/test/test_spike_train_synchrony.py index 07aa532d9..dee9ae1d4 100644 --- a/elephant/test/test_spike_train_synchrony.py +++ b/elephant/test/test_spike_train_synchrony.py @@ -408,6 +408,28 @@ def test_binning_for_input_with_rounding_errors(self): spread=0, mode='delete', in_place=True, deletion_threshold=2) + def test_binning_indexing_last_bin_synchrofact(self): + + # a test with inputs divided by 30000 which leads to rounding errors + # these errors have to be accounted for by proper binning; + # check if we still get the correct result + # If there is a synchrofact in the last bin there was an indexing + # error due to the rounding error correction + + sampling_rate = 30000 / pq.s + + st = neo.SpikeTrain(np.arange(10) * pq.s / 30000, t_stop=.1 * pq.s) + + spiketrains = [st, st] + + annotations = 2*np.ones(10) + + correct_annotations = np.array([annotations, annotations]) + + self._test_template(spiketrains, correct_annotations, sampling_rate, + spread=0, mode='delete', in_place=True, + deletion_threshold=2) + def test_correct_transfer_of_spiketrain_attributes(self): # for delete=True the spiketrains in the block are changed, From 72936690467b8eae934963621e42bae48b2a7f63 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 12:06:41 +0200 Subject: [PATCH 07/17] Alternative method to avoid indexing error in last bin --- elephant/spike_train_synchrony.py | 2 -- elephant/statistics.py | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/elephant/spike_train_synchrony.py b/elephant/spike_train_synchrony.py index 08bcdd96a..8eefc03da 100644 --- a/elephant/spike_train_synchrony.py +++ b/elephant/spike_train_synchrony.py @@ -393,12 +393,10 @@ def annotate_synchrofacts(self): ``self.epoch.array_annotations`` *in-place*. """ epoch_complexities = self.epoch.array_annotations['complexity'] - bin_shift = .5 / self.sampling_rate right_edges = ( self.epoch.times.magnitude.flatten() + self.epoch.durations.rescale( self.epoch.times.units).magnitude.flatten() - + bin_shift.rescale(self.epoch.times.units).magnitude ) for idx, st in enumerate(self.input_spiketrains): diff --git a/elephant/statistics.py b/elephant/statistics.py index ed3abdc6e..258d194cc 100644 --- a/elephant/statistics.py +++ b/elephant/statistics.py @@ -1445,6 +1445,11 @@ def __init__(self, spiketrains, if bin_size is None and sampling_rate is not None: self.bin_size = 1 / self.sampling_rate + # Extend t_stop to avoid indexing problems + self.t_stop += self.bin_size + for st in spiketrains: + st.t_stop = self.t_stop + if spread == 0: self.time_histogram, self.complexity_histogram = \ self._histogram_no_spread() From ee383b8262f2146e7b92465e696cf589f701ba6e Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 12:07:30 +0200 Subject: [PATCH 08/17] fix new error for metadata update with spiketrainlist --- elephant/spike_train_synchrony.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/elephant/spike_train_synchrony.py b/elephant/spike_train_synchrony.py index 8eefc03da..1ce6bc205 100644 --- a/elephant/spike_train_synchrony.py +++ b/elephant/spike_train_synchrony.py @@ -356,7 +356,12 @@ def delete_synchrofacts(self, threshold, in_place=False, mode='delete'): # replace link to spiketrain in segment new_index = self._get_spiketrain_index( segment.spiketrains, st) - segment.spiketrains[new_index] = new_st + + # explicitly re-define the spiketrains + sts = list(segment.spiketrains) + sts[new_index] = new_st + segment.spiketrains = sts + except ValueError: # st is not in this segment even though it points to it warnings.warn(f"The SpikeTrain at index {idx} of the " From c638628bc20528eb998f02ccc514cee341e040ff Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 12:29:19 +0200 Subject: [PATCH 09/17] make t_stop extension only when necessary, include note to docstring --- elephant/statistics.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/elephant/statistics.py b/elephant/statistics.py index 258d194cc..90caf57d2 100644 --- a/elephant/statistics.py +++ b/elephant/statistics.py @@ -1357,6 +1357,11 @@ class Complexity(object): bin edge into the following bin. This can be adjusted using the tolerance parameter and turned off by setting `tolerance=None`. + Due to the rounding error correction an indexing error would occur if + spikes were in the last bin. To avoid the t_stop of the original spike + trains is modified to add one more bin in the cases where a spike is found + at the last time bin. + See also -------- elephant.conversion.BinnedSpikeTrain @@ -1445,10 +1450,16 @@ def __init__(self, spiketrains, if bin_size is None and sampling_rate is not None: self.bin_size = 1 / self.sampling_rate - # Extend t_stop to avoid indexing problems - self.t_stop += self.bin_size - for st in spiketrains: - st.t_stop = self.t_stop + # Check if spikes happen in the last bin + for st in self.input_spiketrains: + # Extend t_stop to avoid indexing problems + if np.isclose(self.t_stop.magnitude, st.times[-1].magnitude): + warnings.warn('Spike found in last bin, extra bin added ', + 'to avoid indexing errors') + self.t_stop += self.bin_size + for st in self.input_spiketrains: + st.t_stop = self.t_stop + break if spread == 0: self.time_histogram, self.complexity_histogram = \ From 2ff001504d3d626c6110b0b474658ff5250956ff Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 12:40:02 +0200 Subject: [PATCH 10/17] remove warning --- elephant/statistics.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/elephant/statistics.py b/elephant/statistics.py index 90caf57d2..d65835d58 100644 --- a/elephant/statistics.py +++ b/elephant/statistics.py @@ -1454,8 +1454,6 @@ def __init__(self, spiketrains, for st in self.input_spiketrains: # Extend t_stop to avoid indexing problems if np.isclose(self.t_stop.magnitude, st.times[-1].magnitude): - warnings.warn('Spike found in last bin, extra bin added ', - 'to avoid indexing errors') self.t_stop += self.bin_size for st in self.input_spiketrains: st.t_stop = self.t_stop From 51c02e79fe5b3c3c723c5e6b66427c5d734529e4 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 14:35:55 +0200 Subject: [PATCH 11/17] undo spiketrainlist problem --- elephant/spike_train_synchrony.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/elephant/spike_train_synchrony.py b/elephant/spike_train_synchrony.py index 1ce6bc205..8eefc03da 100644 --- a/elephant/spike_train_synchrony.py +++ b/elephant/spike_train_synchrony.py @@ -356,12 +356,7 @@ def delete_synchrofacts(self, threshold, in_place=False, mode='delete'): # replace link to spiketrain in segment new_index = self._get_spiketrain_index( segment.spiketrains, st) - - # explicitly re-define the spiketrains - sts = list(segment.spiketrains) - sts[new_index] = new_st - segment.spiketrains = sts - + segment.spiketrains[new_index] = new_st except ValueError: # st is not in this segment even though it points to it warnings.warn(f"The SpikeTrain at index {idx} of the " From 3ec7b214dc0df96373fefc550d9d11b9ab531631 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 14:36:56 +0200 Subject: [PATCH 12/17] newer neo is required for synchrotool indexing not to fail or have a memory leak --- requirements/environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/environment.yml b/requirements/environment.yml index 9f6196b6e..412fa72c5 100644 --- a/requirements/environment.yml +++ b/requirements/environment.yml @@ -13,6 +13,6 @@ dependencies: - statsmodels - jinja2 - pip: - - neo>=0.10.0 + - neo>=0.13.0 - viziphant # neo, viziphant can be removed once it is integrated into requirements-tutorials.txt From 728c698032e8f389581525bd17d98af1d1fb3bc4 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 15:08:07 +0200 Subject: [PATCH 13/17] ensure t_stop of original spiketrains is conserved --- elephant/test/test_spike_train_synchrony.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/elephant/test/test_spike_train_synchrony.py b/elephant/test/test_spike_train_synchrony.py index dee9ae1d4..77753dcd8 100644 --- a/elephant/test/test_spike_train_synchrony.py +++ b/elephant/test/test_spike_train_synchrony.py @@ -193,6 +193,8 @@ def _test_template(self, spiketrains, correct_complexities, sampling_rate, spread, deletion_threshold=2, mode='delete', in_place=False, binary=True): + intial_t_stop = spiketrains[0].t_stop.magnitude + synchrofact_obj = Synchrotool( spiketrains, sampling_rate=sampling_rate, @@ -233,6 +235,8 @@ def _test_template(self, spiketrains, correct_complexities, sampling_rate, cleaned_spike_times): assert_array_almost_equal(cleaned_st, correct_st) + assert_array_almost_equal(spiketrains[0].t_stop.magnitude, intial_t_stop) + def test_no_synchrofacts(self): # nothing to find here From 3dc224f0052aaecf9a76990b0af6c55c5ced0011 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 4 Apr 2024 17:24:15 +0200 Subject: [PATCH 14/17] fix PEP8 issue --- elephant/test/test_spike_train_synchrony.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/elephant/test/test_spike_train_synchrony.py b/elephant/test/test_spike_train_synchrony.py index 77753dcd8..2f564ff7a 100644 --- a/elephant/test/test_spike_train_synchrony.py +++ b/elephant/test/test_spike_train_synchrony.py @@ -235,7 +235,8 @@ def _test_template(self, spiketrains, correct_complexities, sampling_rate, cleaned_spike_times): assert_array_almost_equal(cleaned_st, correct_st) - assert_array_almost_equal(spiketrains[0].t_stop.magnitude, intial_t_stop) + assert_array_almost_equal(spiketrains[0].t_stop.magnitude, + intial_t_stop) def test_no_synchrofacts(self): From c2be5c5e9b743546e95a1feb51f300f10c4bb0b7 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 25 Apr 2024 15:13:09 +0200 Subject: [PATCH 15/17] update neo requirements also in txt --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 929268871..b65469375 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,4 +1,4 @@ -neo>=0.10.0 +neo>=0.13.0 numpy>=1.19.5 quantities>=0.14.1 scipy>=1.10.0 From cc58286ffaa6c96d2c8d9236158fabebf31210a7 Mon Sep 17 00:00:00 2001 From: Aitor Morales-Gregorio <43403140+morales-gregorio@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:13:30 +0200 Subject: [PATCH 16/17] Update elephant/statistics.py Co-authored-by: Moritz Kern <92092328+Moritz-Alexander-Kern@users.noreply.github.com> --- elephant/statistics.py | 1 - 1 file changed, 1 deletion(-) diff --git a/elephant/statistics.py b/elephant/statistics.py index d65835d58..e0f3ca8e1 100644 --- a/elephant/statistics.py +++ b/elephant/statistics.py @@ -1569,7 +1569,6 @@ def _epoch_no_spread(self): if left_edges[0] < self.t_start: left_edges[0] = self.t_start durations[0] -= bin_shift - else: warnings.warn('No sampling rate specified. ' 'Note that using the complexity epoch to get ' From 3c25002aaec02412c799f79a6c990daba9ce9d98 Mon Sep 17 00:00:00 2001 From: morales-gregorio Date: Thu, 25 Apr 2024 15:17:40 +0200 Subject: [PATCH 17/17] update author affiliations --- doc/authors.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/authors.rst b/doc/authors.rst index 93aab77b7..b0f444e76 100644 --- a/doc/authors.rst +++ b/doc/authors.rst @@ -37,7 +37,7 @@ contribution, and may not be the current affiliation of a contributor. * Alessandra Stella [1] * Peter Bouss [1] * Alexander van Meegen [1] -* Aitor Morales-Gregorio [1] +* Aitor Morales-Gregorio [1, 14] * Cristiano Köhler [1] * Paulina Dąbrowska [1] * Jan Lewen [1] @@ -51,7 +51,7 @@ contribution, and may not be the current affiliation of a contributor. * Florian Porrmann [13] * Sarah Pilz [13] * Oliver Kloß [1] -* Jonas Oberste-Frielinghaus [1] +* Jonas Oberste-Frielinghaus [1, 14] * Sven Krausse [1] * Felician Richter [12]