Skip to content
Closed
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ Redistribution and use in source and binary forms, with or without modification,

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the names of the copyright holders nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission.
* Neither the names of the copyright holders nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 changes: 17 additions & 0 deletions neo/core/epoch.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,20 @@ def merge(self, other):
other.annotations)
kwargs.update(merged_annotations)
return Epoch(times=times, durations=durations, labels=labels, **kwargs)

def _copy_data_complement(self, other):
'''
Copy the metadata from another :class:`Epoch`.
'''
for attr in ("labels", "durations", "name", "file_origin",
"description", "annotations"):
setattr(self, attr, getattr(other, attr, None))

def duplicate_with_new_data(self, signal):
'''
Create a new :class:`Epoch` with the same metadata
but different data (times, durations)
'''
new = self.__class__(times=signal)
new._copy_data_complement(self)
return new
17 changes: 17 additions & 0 deletions neo/core/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,20 @@ def merge(self, other):
other.annotations)
kwargs.update(merged_annotations)
return Event(times=times, labels=labels, **kwargs)

def _copy_data_complement(self, other):
'''
Copy the metadata from another :class:`Event`.
'''
for attr in ("labels", "name", "file_origin", "description",
"annotations"):
setattr(self, attr, getattr(other, attr, None))

def duplicate_with_new_data(self, signal):
'''
Create a new :class:`Event` with the same metadata
but different data
'''
new = self.__class__(times=signal)
new._copy_data_complement(self)
return new
55 changes: 55 additions & 0 deletions neo/core/spiketrain.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,25 @@ def _check_time_in_range(value, t_start, t_stop, view=False):
raise ValueError("The last spike (%s) is after t_stop (%s)" %
(value, t_stop))

def _check_waveform_dimensions(spiketrain):
'''
Verify that waveform is compliant with the waveform definition as
quantity array 3D (spike, channel_index, time)
'''

if not spiketrain.size:
return

waveforms = spiketrain.waveforms

if not (waveforms and waveforms.size):
return

if waveforms.shape[0] != len(spiketrain):
raise ValueError("Spiketrain length (%s) does not match to number of "
"waveforms present (%s)" % (len(spiketrain),
waveforms.shape[0]))


def _new_spiketrain(cls, signal, t_stop, units=None, dtype=None,
copy=True, sampling_rate=1.0 * pq.Hz,
Expand Down Expand Up @@ -435,6 +454,42 @@ def __setslice__(self, i, j, value):
_check_time_in_range(value, self.t_start, self.t_stop)
super(SpikeTrain, self).__setslice__(i, j, value)

def _copy_data_complement(self, other):
'''
Copy the metadata from another :class:`SpikeTrain`.
'''
for attr in ("t_start", "t_stop", "waveforms", "left_sweep",
"sampling_rate", "name", "file_origin", "description",
"annotations"):
setattr(self, attr, getattr(other, attr, None))

def duplicate_with_new_data(self, signal, t_start=None, t_stop=None,
waveforms=None):
'''
Create a new :class:`SpikeTrain` with the same metadata
but different data (times, t_start, t_stop)
'''
# using previous t_start and t_stop if no values are provided
if t_start is None:
t_start = self.t_start
if t_stop is None:
t_stop = self.t_stop
if waveforms is None:
waveforms = self.waveforms

new_st = self.__class__(signal, t_stop,waveforms=waveforms,
units=self.units)
new_st._copy_data_complement(self)

# overwriting t_start and t_stop with new values
new_st.t_start = t_start
new_st.t_stop = t_stop

# consistency check
_check_time_in_range(new_st, new_st.t_start, new_st.t_stop, view=True)
_check_waveform_dimensions(new_st)
return new_st

def time_slice(self, t_start, t_stop):
'''
Creates a new :class:`SpikeTrain` corresponding to the time slice of
Expand Down
20 changes: 19 additions & 1 deletion neo/test/coretest/test_epoch.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
from neo.core.epoch import Epoch
from neo.core import Segment
from neo.test.tools import (assert_neo_object_is_compliant,
assert_arrays_equal, assert_same_sub_schema)
assert_arrays_equal, assert_arrays_almost_equal,
assert_same_sub_schema)
from neo.test.generate_datasets import (get_fake_value, get_fake_values,
fake_neo, TEST_ANNOTATIONS)

Expand Down Expand Up @@ -228,6 +229,23 @@ def test__pretty(self):

self.assertEqual(prepr, targ)

class TestDuplicateWithNewData(unittest.TestCase):
def setUp(self):
self.data = np.array([0.1, 0.5, 1.2, 3.3, 6.4, 7])
self.durations = np.array([0.2, 0.4, 1.1, 2.4, 0.2, 2.0])
self.quant = pq.ms
self.epoch = Epoch(self.data*self.quant,
durations=self.durations*self.quant)

def test_duplicate_with_new_data(self):
signal1 = self.epoch
new_data = np.sort(np.random.uniform(0, 100, (self.epoch))) * pq.ms
signal1b = signal1.duplicate_with_new_data(new_data)
assert_arrays_almost_equal(np.asarray(signal1b),
np.asarray(new_data), 1e-12)
assert_arrays_almost_equal(np.asarray(signal1b.durations),
np.asarray(signal1.durations), 1e-12)


if __name__ == "__main__":
unittest.main()
16 changes: 15 additions & 1 deletion neo/test/coretest/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
from neo.core.event import Event
from neo.core import Segment
from neo.test.tools import (assert_neo_object_is_compliant,
assert_arrays_equal, assert_same_sub_schema)
assert_arrays_equal,
assert_arrays_almost_equal,
assert_same_sub_schema)
from neo.test.generate_datasets import (get_fake_value, get_fake_values,
fake_neo, TEST_ANNOTATIONS)

Expand Down Expand Up @@ -217,6 +219,18 @@ def test__pretty(self):

self.assertEqual(prepr, targ)

class TestDuplicateWithNewData(unittest.TestCase):
def setUp(self):
self.data = np.array([0.1, 0.5, 1.2, 3.3, 6.4, 7])
self.dataquant = self.data*pq.ms
self.event = Event(self.dataquant)

def test_duplicate_with_new_data(self):
signal1 = self.event
new_data = np.sort(np.random.uniform(0, 100, (self.event))) * pq.ms
signal1b = signal1.duplicate_with_new_data(new_data)
assert_arrays_almost_equal(np.asarray(signal1b),
np.asarray(new_data), 1e-12)

if __name__ == "__main__":
unittest.main()
36 changes: 35 additions & 1 deletion neo/test/coretest/test_spiketrain.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
from neo.core.spiketrain import (check_has_dimensions_time, SpikeTrain,
_check_time_in_range, _new_spiketrain)
from neo.core import Segment, Unit
from neo.test.tools import assert_arrays_equal, assert_neo_object_is_compliant
from neo.test.tools import (assert_arrays_equal,
assert_arrays_almost_equal,
assert_neo_object_is_compliant)
from neo.test.generate_datasets import (get_fake_value, get_fake_values,
fake_neo, TEST_ANNOTATIONS)

Expand Down Expand Up @@ -1135,6 +1137,38 @@ def test_time_slice_none_both(self):
self.assertEqual(self.train1.t_start, result.t_start)
self.assertEqual(self.train1.t_stop, result.t_stop)

class TestDuplicateWithNewData(unittest.TestCase):
def setUp(self):
self.waveforms = np.array([[[0., 1.],
[0.1, 1.1]],
[[2., 3.],
[2.1, 3.1]],
[[4., 5.],
[4.1, 5.1]],
[[6., 7.],
[6.1, 7.1]],
[[8., 9.],
[8.1, 9.1]],
[[10., 11.],
[10.1, 11.1]]]) * pq.mV
self.data = np.array([0.1, 0.5, 1.2, 3.3, 6.4, 7])
self.dataquant = self.data*pq.ms
self.train = SpikeTrain(self.dataquant, t_stop=10.0*pq.ms,
waveforms=self.waveforms)

def test_duplicate_with_new_data(self):
signal1 = self.train
new_data = np.sort(np.random.uniform(0, 100, (self.train))) * pq.ms
new_t_start = -10*pq.s
new_t_stop = 10*pq.s
signal1b = signal1.duplicate_with_new_data(new_data,
t_start=new_t_start,
t_stop=new_t_stop)
assert_arrays_almost_equal(np.asarray(signal1b),
np.asarray(new_data), 1e-12)
self.assertEqual(signal1b.t_start, new_t_start)
self.assertEqual(signal1b.t_stop, new_t_stop)
self.assertEqual(signal1b.sampling_rate, signal1.sampling_rate)

class TestAttributesAnnotations(unittest.TestCase):
def test_set_universally_recommended_attributes(self):
Expand Down