Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions neo/core/basesignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,65 @@ def merge(self, other):
signal.channel_index = ChannelIndex(index=np.arange(signal.shape[1]))

return signal

@staticmethod
def _rescale_epoch_times(a_signal, times_of_an_epoch):
"""
Checks epoch.times.units against signal.times.units

Arguments:
a_signal
times_of_an_epoch; epc.times or epc.durations of the created epoch, epc.

Returns:
same times_of_an_epoch if units are the same
or
rescaled (to signal.times.units) times_of_an_epoch if units are different.
"""
if times_of_an_epoch.units is not a_signal.times.units:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be "!=" rather than "is not"?

return times_of_an_epoch.rescale(a_signal.times.units)
else:
return times_of_an_epoch

def extract_for_epoch(self, epoch):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe cut_by_epoch or slice_by_epoch is more telling?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not particular preference, I used the verb extract because it returns the cut/sliced signal.

Copy link
Author

@lungsi lungsi Apr 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Julia,
Thanks for the comments.
The point regarding the function performing a utility is a good one. I started out thinking that way but since there were no current utility.py script/source fille so I took the current approach which is to make signal have the method where one just had to pass the epoch. If there's going to be a script containing the utility methods I thinks its ok to have it there.

With regards to why I have _rescale_epoch_time and extract_for_epoch, not just one is because it avoids code duplication and also one has only 1-reason to change/edit either methods.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer slice_by_epoch to match time_slice

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @JuliaSprenger on moving _rescale_epoch_time inside the function where it is used. This does not imply code duplication, since you can define a function inside a function.

Alternatively, it could be moved out of the BaseSignal definition into a utility function, as checking two Neo objects have the same units must surely be a common need.

"""
Checks self (which is the instance, neo.AnalogSignal or neo.SpikeTrain) for
specified neo.Epoch and returns signals for respective epochs within neo.Epoch

Arguments:
epoch; a created neo.Epoch

Returns:
signal from start of an epoch to stop (start+duration).
This is done for respective epoch. Therefore if there are three epochs within
the epoch neo object (in the argument) then it returns a list of three signals.
But if there's only one epoch it returns just the signal (not a list).

Usage:
>>> import neo
>>> import quantities as pq
>>> import numpy as np
>>> sigarr = neo.AnalogSignal([[1], [2], [3], [4], [5], [6]], units='mV',
sampling_rate=1*pq.Hz)
>>> epc = neo.Epoch(times=np.array([0, 3000])*pq.ms, durations=[1000, 2000]*pq.ms,
labels=np.array(['btn0', 'btn1'], dtype='S'))
>>> epochsignals = sigarr.extract_for_epoch(epc)
>>> epochsignals
[<AnalogSignal(array([[1]]) * mV, [0.0 s, 1.0 s], sampling rate: 1.0 Hz)>,
<AnalogSignal(array([], shape=(0, 1), dtype=int64) * mV, [3.0 s, 3.0 s],
sampling rate: 1.0 Hz)>]
>>> len(epochsignals)
2
>>> epochsignals[0]
<AnalogSignal(array([[1]]) * mV, [0.0 s, 1.0 s], sampling rate: 1.0 Hz)>

"""
extractions = []
for epc in epoch:
t_start = self._rescale_epoch_times(self, epc.times)
t_stop = self._rescale_epoch_times(self, epc.durations)
extractions.append(self.time_slice(t_start, t_stop))
if len(extractions)==1:
return extractions[0]
else:
return extractions