Skip to content

extract epoch based signal#525

Closed
lungsi wants to merge 2 commits intoNeuralEnsemble:masterfrom
myHBPwork:epochextract
Closed

extract epoch based signal#525
lungsi wants to merge 2 commits intoNeuralEnsemble:masterfrom
myHBPwork:epochextract

Conversation

@lungsi
Copy link

@lungsi lungsi commented Apr 19, 2018

Added two methods within the class BaseSignal these are: (staticmethod) _rescale_epoch_time and extract_for_epoch. Therefore when a neo object signal is created (which in turn is an instance of the child class of BaseSignal) it has the method extract_for_epoch. Passing the epochs (created neo.Epoch) into this method will return a list of extracted signals (specific to the epochs).

>>> 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)>

@pep8speaks
Copy link

pep8speaks commented Apr 19, 2018

Hello @lungsi! Thanks for updating the PR.

Line 13:69: W291 trailing whitespace
Line 40:78: W291 trailing whitespace
Line 42:73: W291 trailing whitespace
Line 61:68: W291 trailing whitespace
Line 63:58: W291 trailing whitespace
Line 86:61: W291 trailing whitespace
Line 311:1: W293 blank line contains whitespace
Line 364:28: E225 missing whitespace around operator

Comment last updated on April 19, 2018 at 11:49 Hours UTC

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.02%) to 48.87% when pulling b2f075c on lungsi:epochextract into db9357c on NeuralEnsemble:master.

@coveralls
Copy link

coveralls commented Apr 19, 2018

Coverage Status

Coverage decreased (-0.02%) to 48.87% when pulling 7ee2f82 on lungsi:epochextract into db9357c on NeuralEnsemble:master.

def extract_for_epoch(self, epoch):
"""
Checks self (which is the instance, neo.AnalogSignal or neo.SpikeTrain) for
specified neo.Epoch and returns signals for respetive epochs within neo.Epoch
Copy link
Member

Choose a reason for hiding this comment

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

typo: this should be 'respective'

@JuliaSprenger
Copy link
Member

JuliaSprenger commented Apr 19, 2018

Hi Lungsi!
Thanks for your contribution.
The utility function you are proposing is indeed part of a collection of functions we are missing for quite some time. However, I am not sure if this type of utility functions should be a method of the BaseSignal class or should go into a separate neo_utility function collection.
@apdavison @samuelgarcia I think we discussed this already once, based on the neo_utils collection here (https://web.gin.g-node.org/INT/multielectrode_grasp/src/master/code/neo_utils.py), which we planned to include at some point. What is your current opinion on the topic?

If this is going to stay a BaseSignal method, I would suggest to include the code of the _rescale_epoch_time directly in the extract_for_epoch, since it does not make sense to have an epoch specific function in the BaseSignal class.

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.

@apdavison
Copy link
Member

I believe this is an implementation of #387 ?

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"?

@apdavison apdavison added this to the 0.7.0 milestone Apr 21, 2018
@samuelgarcia
Copy link
Contributor

samuelgarcia commented Apr 23, 2018

Dear all.
I made some coments about slicing here #526

I have implemented proxy objects here #461.
This is not merged yet, but it is almost ready (except some side effect errors and pep87).

For doing this I would prefer to write external function as proposed by @JuliaSprenger and map them to method as proposed by @apdavison.

So with proxy objects the external function could be hacked easily to work with standard/proxy objects.

My proposal is AnalogSignal.extract_for_epoch should call external neo.io.utils_slice.slice_sig_by_epoch (or whatever)

External function will also help for global slicing at segment/block level.

EDIT: I am totally repeating what @JuliaSprenger and @apdavison said before sorry.

@apdavison apdavison modified the milestones: 0.7.0, 0.8.0 Nov 15, 2018
@apdavison apdavison self-assigned this Jul 23, 2019
@apdavison apdavison modified the milestones: 0.8.0, 0.9.0 Sep 26, 2019
@apdavison
Copy link
Member

I'm postponing this to the next milestone due to lack of time to work on it.

@apdavison apdavison modified the milestones: 0.9.0, 0.10.0 Sep 24, 2020
@apdavison
Copy link
Member

closing now as this PR is very old, but we will revisit the idea

@apdavison apdavison closed this Mar 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants