Skip to content

Commit

Permalink
Account for unidirectional spiketrain->segment links in synchrofact d…
Browse files Browse the repository at this point in the history
…eletion (NeuralEnsemble#398)

* Fix a bug in synchrofact deletion

when passing the actual segment.spiketrains list
to the Synchrotool and performing in-place deletion
the spiketrain was overwritten before its index was determined
resulting in an error

* Fix spiketrain replacement being skipped

if the spiketrain is not part of a segment and/or block
the `continue` skipped the replacement in the input list

* Handle unidirectional segment uplinks
  • Loading branch information
Kleinjohann committed Feb 1, 2021
1 parent 1ba500a commit f20f071
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 23 deletions.
55 changes: 32 additions & 23 deletions elephant/spike_train_synchrony.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"""
from __future__ import division, print_function, unicode_literals

import warnings
from collections import namedtuple
from copy import deepcopy

Expand Down Expand Up @@ -341,33 +342,41 @@ def delete_synchrofacts(self, threshold, in_place=False, mode='delete'):
if mode == 'extract':
mask = np.invert(mask)
new_st = st[mask]
spiketrain_list[idx] = new_st
if in_place:
if in_place and st.segment is not None:
segment = st.segment
if segment is None:
continue

# replace link to spiketrain in segment
new_index = self._get_spiketrain_index(
segment.spiketrains, st)
segment.spiketrains[new_index] = new_st
try:
# replace link to spiketrain in segment
new_index = self._get_spiketrain_index(
segment.spiketrains, st)
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 "
"input list spiketrains has a "
"unidirectional uplink to a segment in "
"whose segment.spiketrains list it does not "
"appear. Only the spiketrains in the input "
"list will be replaced. You can suppress "
"this warning by setting "
"spiketrain.segment=None for the input "
"spiketrains.")

block = segment.block
if block is None:
continue

# replace link to spiketrain in groups
for group in block.groups:
try:
idx = self._get_spiketrain_index(
group.spiketrains,
st)
except ValueError:
# st is not in this group, move to next group
continue

# st found in group, replace with new_st
group.spiketrains[idx] = new_st
if block is not None:
# replace link to spiketrain in groups
for group in block.groups:
try:
idx = self._get_spiketrain_index(
group.spiketrains,
st)
except ValueError:
# st is not in this group, move to next group
continue

# st found in group, replace with new_st
group.spiketrains[idx] = new_st
spiketrain_list[idx] = new_st

return spiketrain_list

Expand Down
53 changes: 53 additions & 0 deletions elephant/test/test_spike_train_synchrony.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,59 @@ def test_spread_0(self):
spread=0, mode='delete', in_place=True,
deletion_threshold=2)

def test_spiketrains_findable(self):

# same test as `test_spread_0` with the addition of
# a neo structure: we must not overwrite the spiketrain
# list of the segment before determining the index

sampling_rate = 1 / pq.s

segment = neo.Segment()

segment.spiketrains = [neo.SpikeTrain([1, 5, 9, 11, 16, 19] * pq.s,
t_stop=20*pq.s),
neo.SpikeTrain([1, 4, 8, 12, 16, 18] * pq.s,
t_stop=20*pq.s)]

segment.create_relationship()

correct_annotations = np.array([[2, 1, 1, 1, 2, 1],
[2, 1, 1, 1, 2, 1]])

self._test_template(segment.spiketrains, correct_annotations,
sampling_rate, spread=0, mode='delete',
in_place=True, deletion_threshold=2)

def test_unidirectional_uplinks(self):

# same test as `test_spiketrains_findable` but the spiketrains
# are rescaled first
# the rescaled spiketrains have a unidirectional uplink to segment
# check that this does not cause an error
# check that a UserWarning is issued in this case

sampling_rate = 1 / pq.s

segment = neo.Segment()

segment.spiketrains = [neo.SpikeTrain([1, 5, 9, 11, 16, 19] * pq.s,
t_stop=20*pq.s),
neo.SpikeTrain([1, 4, 8, 12, 16, 18] * pq.s,
t_stop=20*pq.s)]

segment.create_relationship()

spiketrains = [st.rescale(pq.s) for st in segment.spiketrains]

correct_annotations = np.array([[2, 1, 1, 1, 2, 1],
[2, 1, 1, 1, 2, 1]])

with self.assertWarns(UserWarning):
self._test_template(spiketrains, correct_annotations,
sampling_rate, spread=0, mode='delete',
in_place=True, deletion_threshold=2)

def test_spread_1(self):

# test synchrofact search taking into account adjacent bins
Expand Down

0 comments on commit f20f071

Please sign in to comment.