-
Notifications
You must be signed in to change notification settings - Fork 95
[Fix] instantaneous rate with list[neo.SpikeTrain] #649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 9 commits
1757196
b21bfe1
685ebbb
f898526
fbcbd4a
21ba059
4ff1dc7
024d595
6b47e0e
3a96ee3
b15b77d
0df030d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -482,15 +482,15 @@ def test_cv2_raise_error(self): | |
| self.assertRaises(ValueError, statistics.cv2, np.array([seq, seq])) | ||
|
|
||
|
|
||
| class InstantaneousRateTest(unittest.TestCase): | ||
| class InstantaneousRateTestCase(unittest.TestCase): | ||
|
|
||
| @classmethod | ||
| def setUpClass(cls) -> None: | ||
| """ | ||
| Run once before tests: | ||
| """ | ||
|
|
||
| block = _create_trials_block(n_trials=36) | ||
| block = _create_trials_block(n_trials=36, n_spiketrains=5) | ||
| cls.block = block | ||
| cls.trial_object = TrialsFromBlock(block, | ||
| description='trials are segments') | ||
|
|
@@ -988,8 +988,44 @@ def test_instantaneous_rate_trials_pool_trials(self): | |
| pool_spike_trains=False, | ||
| pool_trials=True) | ||
| self.assertIsInstance(rate, neo.core.AnalogSignal) | ||
| self.assertEqual(rate.shape[1], self.trial_object.n_spiketrains_trial_by_trial[0]) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test checks for consistency between the dimensions of the computed rate and the data in the Trials objects. However, an additional test against the integer values would protect against errors in implementing the object attributes. These hard expected values are supposed to be known when designing the test data in line 493. |
||
|
|
||
| def test_instantaneous_rate_list_pool_spike_trains(self): | ||
| def test_instantaneous_rate_trials_pool_spiketrains(self): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A suggestion to improve understanding of these unit tests, where the dimensions of the outputs change depending on the pooling, is to include a comment block at the beginning to explicitly state the input dimensions --> expected output dimensions. It would be easier to assess the behavior of the object and what is being tested in each test case. |
||
| kernel = kernels.GaussianKernel(sigma=500 * pq.ms) | ||
|
|
||
| rate = statistics.instantaneous_rate(self.trial_object, | ||
| sampling_period=0.1 * pq.ms, | ||
| kernel=kernel, | ||
| pool_spike_trains=True, | ||
| pool_trials=False) | ||
| self.assertIsInstance(rate, list) | ||
| self.assertEqual(len(rate), self.trial_object.n_trials) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above, where the test does not compare directly to the expected values, but retrieves them dynamically from the objects. |
||
| self.assertEqual(rate[0].shape[1], 1) | ||
|
|
||
| def test_instantaneous_rate_trials_pool_spiketrains_pool_trials(self): | ||
| kernel = kernels.GaussianKernel(sigma=500 * pq.ms) | ||
|
|
||
| rate = statistics.instantaneous_rate(self.trial_object, | ||
| sampling_period=0.1 * pq.ms, | ||
| kernel=kernel, | ||
| pool_spike_trains=True, | ||
| pool_trials=True) | ||
| self.assertIsInstance(rate, neo.AnalogSignal) | ||
| self.assertEqual(rate.shape[1], 1) | ||
|
|
||
| def test_instantaneous_rate_trials_pool_spiketrains_false_pool_trials_false(self): | ||
| kernel = kernels.GaussianKernel(sigma=500 * pq.ms) | ||
|
|
||
| rate = statistics.instantaneous_rate(self.trial_object, | ||
| sampling_period=0.1 * pq.ms, | ||
| kernel=kernel, | ||
| pool_spike_trains=False, | ||
| pool_trials=False) | ||
| self.assertIsInstance(rate, list) | ||
| self.assertEqual(len(rate), self.trial_object.n_trials) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above, where the test does not compare directly to the expected values, but retrieves them dynamically from the objects. |
||
| self.assertEqual(rate[0].shape[1], self.trial_object.n_spiketrains_trial_by_trial[0]) | ||
|
|
||
| def test_instantaneous_rate_spiketrainlist_pool_spike_trains(self): | ||
| kernel = kernels.GaussianKernel(sigma=500 * pq.ms) | ||
|
|
||
| rate = statistics.instantaneous_rate( | ||
|
|
@@ -999,7 +1035,19 @@ def test_instantaneous_rate_list_pool_spike_trains(self): | |
| pool_spike_trains=True, | ||
| pool_trials=False) | ||
| self.assertIsInstance(rate, neo.core.AnalogSignal) | ||
| self.assertEqual(rate.magnitude.shape[1], 1) | ||
| self.assertEqual(rate.shape[1], 1) | ||
|
|
||
| def test_instantaneous_rate_list_pool_spike_trains(self): | ||
| kernel = kernels.GaussianKernel(sigma=500 * pq.ms) | ||
|
|
||
| rate = statistics.instantaneous_rate( | ||
| list(self.trial_object.get_spiketrains_from_trial_as_list(0)), | ||
| sampling_period=0.1 * pq.ms, | ||
| kernel=kernel, | ||
| pool_spike_trains=True, | ||
| pool_trials=False) | ||
| self.assertIsInstance(rate, neo.core.AnalogSignal) | ||
| self.assertEqual(rate.shape[1], 1) | ||
|
|
||
| def test_instantaneous_rate_list_of_spike_trains(self): | ||
| kernel = kernels.GaussianKernel(sigma=500 * pq.ms) | ||
|
|
@@ -1010,7 +1058,7 @@ def test_instantaneous_rate_list_of_spike_trains(self): | |
| pool_spike_trains=False, | ||
| pool_trials=False) | ||
| self.assertIsInstance(rate, neo.core.AnalogSignal) | ||
| self.assertEqual(rate.magnitude.shape[1], 2) | ||
| self.assertEqual(rate.magnitude.shape[1], self.trial_object.n_spiketrains_trial_by_trial[0]) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above, where the test does not compare directly to the expected values, but retrieves them dynamically from the objects. The integer in the old test could be updated, and the new one just added as an additional check. |
||
|
|
||
|
|
||
| class TimeHistogramTestCase(unittest.TestCase): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |
| check_neo_consistency | ||
| check_same_units | ||
| round_binning_errors | ||
| is_list_neo_spiketrains | ||
| """ | ||
|
|
||
| from __future__ import division, print_function, unicode_literals | ||
|
|
@@ -21,7 +22,8 @@ | |
| import quantities as pq | ||
|
|
||
| from elephant.trials import Trials | ||
|
|
||
| import collections.abc | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It also avoids always loading additional objects with attribute statements each time |
||
| import neo | ||
|
|
||
| __all__ = [ | ||
| "deprecated_alias", | ||
|
|
@@ -31,6 +33,7 @@ | |
| "check_neo_consistency", | ||
| "check_same_units", | ||
| "round_binning_errors", | ||
| "is_list_neo_spiketrains", | ||
| ] | ||
|
|
||
|
|
||
|
|
@@ -446,3 +449,32 @@ def wrapper(*args, **kwargs): | |
| return method(*new_args, **new_kwargs) | ||
|
|
||
| return wrapper | ||
|
|
||
|
|
||
| def is_list_neo_spiketrains(obj: object) -> bool: | ||
Moritz-Alexander-Kern marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
| Check if input is an iterable containing only neo.SpikeTrain objects. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Corrections:
|
||
|
|
||
| Parameters | ||
| ---------- | ||
| obj : object | ||
| The object to check. Can be a neo.spiketrainlist, list, tuple or any other iterable. | ||
Moritz-Alexander-Kern marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Returns | ||
| ------- | ||
| bool | ||
| True if obj is an iterable containing only neo.SpikeTrain objects. | ||
Moritz-Alexander-Kern marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Raises | ||
Moritz-Alexander-Kern marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ------ | ||
| TypeError | ||
| If obj is not an iterable, or if any element is not a neo.SpikeTrain. | ||
|
|
||
| """ | ||
|
|
||
| if not isinstance(obj, collections.abc.Iterable): | ||
| raise TypeError("Input must be an iterable (list, tuple, etc.)") | ||
Moritz-Alexander-Kern marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if not all(isinstance(st, neo.SpikeTrain) for st in obj): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be replaced by a direct AND statements are evaluated lazyly from left to right. Whenever an non-Iterable is passed, the expression will be False and evaluation stops. |
||
| raise TypeError("All elements must be neo.SpikeTrain objects") | ||
|
|
||
| return True | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other PRs explicitly add links to the documentation of the referred classes using Sphinx's :class: statements, which facilitates navigating through the documentation.