def test_spike_objects(self): dimension = 40 offset = sp.zeros((dimension, 1)) offset[0] = 4 cluster1 = self.rand.randn(dimension, 10) cluster2 = self.rand.randn(dimension, 100) + offset cluster3 = self.rand.randn(dimension, 500) - offset clusterList1 = [cluster1[:, i] for i in xrange(sp.size(cluster1, 1))] clusterList2 = [cluster2[:, i] for i in xrange(sp.size(cluster2, 1))] clusterList3 = [cluster3[:, i] for i in xrange(sp.size(cluster3, 1))] mean1 = sp.zeros(dimension) mean2 = offset.flatten() mean3 = -mean2 total, pair = qa.overlap_fp_fn( { 1: clusterList1, 2: clusterList2, 3: clusterList3 }, means={ 1: mean1, 2: mean2, 3: mean3 }, covariances={ 1: sp.eye(dimension), 2: sp.eye(dimension), 3: sp.eye(dimension) }) # Replacing some arrays with Spike objects mean2 = neo.Spike(waveform=mean2.reshape(-1, 4) / 1000.0 * pq.mV) mean3 = neo.Spike(waveform=mean3.reshape(-1, 4) / 1e6 * pq.V) newClusterList = [] for s in clusterList1: newClusterList.append( neo.Spike(waveform=s.reshape(-1, 4) / 1000.0 * pq.mV)) total_s, pair_s = qa.overlap_fp_fn( { 1: newClusterList, 2: clusterList2, 3: clusterList3 }, means={ 1: mean1, 2: mean2, 3: mean3 }, covariances='white') # Results should be identical for arrays and Spike objects for i in total.keys(): self.assertAlmostEqual(total[i][0], total_s[i][0]) self.assertAlmostEqual(total[i][1], total_s[i][1]) for j in pair[i].keys(): self.assertAlmostEqual(pair[i][j][0], pair_s[i][j][0]) self.assertAlmostEqual(pair[i][j][1], pair_s[i][j][1])
def test_spikes(self): trains = {} trains[0] = [ neo.Spike(0 * pq.ms, waveform=[[-1, -2], [1, 2]] * pq.mV), neo.Spike(0 * pq.ms, waveform=[[-1, -2], [1, 2]] * pq.mV) ] trains[1] = trains[0] means = {} means[0] = neo.Spike(0 * pq.ms, waveform=[[-1, -1], [1, 1]] * pq.mV) exp = qa.variance_explained(trains, means) self.assertAlmostEqual(exp[1][0], 1) self.assertAlmostEqual(exp[1][0], 1) self.assertAlmostEqual(exp[0][0], 1) self.assertAlmostEqual(exp[0][1], 0.75)
def spike_train_to_spikes(spike_train, include_waveforms=True): """ Return a list of spikes for a spike train. Note that while the created spikes have references to the same segment and unit as the spike train, the relationships in the other direction are not automatically created (the spikes are not attached to the unit or segment). Other properties like annotations are not copied or referenced in the created spikes. :param spike_train: A spike train from which the :class:`neo.core.Spike` objects are constructed. :type spike_train: :class:`neo.core.SpikeTrain` :param bool include_waveforms: Determines if the ``waveforms`` property is converted to the spike waveforms. If ``waveforms`` is None, this parameter has no effect. :returns: A list of :class:`neo.core.Spike` objects, one for every spike in ``spike_train``. :rtype: list """ waves = None if include_waveforms: waves = spike_train.waveforms spikes = [] for i, t in enumerate(spike_train): s = neo.Spike(t, sampling_rate=spike_train.sampling_rate, left_sweep=spike_train.left_sweep) if waves is not None: s.waveform = waves[i, :, :] s.unit = spike_train.unit s.segment = spike_train.segment spikes.append(s) return spikes
def variance_explained(spikes, means=None, noise=None): """ Returns the fraction of variance in each channel that is explained by the means. Values below 0 or above 1 for large data sizes indicate that some assumptions were incorrect (e.g. about channel noise) and the results should not be trusted. :param dict spikes: Dictionary, indexed by unit, of :class:`neo.core.SpikeTrain` objects (where the ``waveforms`` member includes the spike waveforms) or lists of :class:`neo.core.Spike` objects. :param dict means: Dictionary, indexed by unit, of lists of spike waveforms as :class:`neo.core.Spike` objects or numpy arrays. Means for units that are not in this dictionary will be estimated using the spikes. Default: None - means will be estimated from given spikes. :type noise: Quantity 1D :param noise: The known noise levels (as variance) per channel of the original data. This should be estimated from the signal periods that do not contain spikes, otherwise the explained variance could be overestimated. If None, the estimate of explained variance is done without regard for noise. Default: None :return dict: A dictionary of arrays, both indexed by unit. If ``noise`` is ``None``, the dictionary contains the fraction of explained variance per channel without taking noise into account. If ``noise`` is given, it contains the fraction of variance per channel explained by the means and given noise level together. """ ret = {} if means is None: means = {} for u, spks in spikes.iteritems(): train = spks if not isinstance(train, neo.SpikeTrain): train = spikes_to_spike_train(spks) if u in means and means[u].waveform.shape[0] == train.waveforms.shape[ 1]: spike = means[u] else: spike = neo.Spike(0) spike.waveform = sp.mean(train.waveforms, axis=0) orig = sp.mean(sp.var(train.waveforms, axis=1), axis=0) waves = train.waveforms - spike.waveform new = sp.mean(sp.var(waves, axis=1), axis=0) if noise is not None: ret[u] = sp.asarray(1 - (new - noise) / orig) else: ret[u] = sp.asarray(1 - new / orig) return ret
def create_hierarchy(cls, many_to_many): b = neo.Block() for ns in range(cls.SEGMENTS): b.segments.append(neo.Segment()) channels = [] if many_to_many: channels = [ neo.RecordingChannel(name='Shared %d' % i, index=i + cls.CHANNELS) for i in range(cls.CHANNELS / 2) ] for ng in range(cls.CHANNEL_GROUPS): rcg = neo.RecordingChannelGroup() for nu in range(cls.UNITS): unit = neo.Unit() for ns in range(cls.SEGMENTS): spike = neo.Spike(0 * pq.s) unit.spikes.append(spike) b.segments[ns].spikes.append(spike) st = neo.SpikeTrain([] * pq.s, 0 * pq.s) unit.spiketrains.append(st) b.segments[ns].spiketrains.append(st) rcg.units.append(unit) if not many_to_many: for nc in range(cls.CHANNELS): rc = neo.RecordingChannel(name='Single %d' % nc, index=nc) rc.recordingchannelgroups.append(rcg) rcg.recordingchannels.append(rc) else: for nc in range(cls.CHANNELS): if nc % 2 == 0: rc = neo.RecordingChannel(name='Single %d' % (nc / 2), index=nc / 2) else: rc = channels[nc / 2] rc.recordingchannelgroups.append(rcg) rcg.recordingchannels.append(rc) rcg.channel_indexes = sp.array( [c.index for c in rcg.recordingchannels]) rcg.channel_names = sp.array( [c.name for c in rcg.recordingchannels]) b.recordingchannelgroups.append(rcg) try: neo.io.tools.create_many_to_one_relationship(b) except AttributeError: b.create_many_to_one_relationship() return b
def test_trains(self): trains = {} trains[0] = neo.SpikeTrain( sp.zeros(2) * pq.ms, 0 * pq.ms, waveforms=[[[-1, -2], [1, 2]], [[-1, -2], [1, 2]]] * pq.mV) trains[1] = trains[0] means = {} means[1] = neo.Spike(0 * pq.ms, waveform=[[-1, -1], [1, 1]] * pq.mV) exp = qa.variance_explained(trains, means) self.assertAlmostEqual(exp[0][0], 1) self.assertAlmostEqual(exp[0][0], 1) self.assertAlmostEqual(exp[1][0], 1) self.assertAlmostEqual(exp[1][1], 0.75)
def test_remove_spiketrain(self): unit = neo.Unit() segment = neo.Segment() s = neo.Spike(0 * pq.s) unit.spikes.append(s) segment.spikes.append(s) s.unit = unit s.segment = segment st = neo.SpikeTrain([] * pq.s, 0 * pq.s) unit.spiketrains.append(st) segment.spiketrains.append(st) st.unit = unit st.segment = segment tools.remove_from_hierarchy(st) self.assertTrue(s in unit.spikes) self.assertTrue(s in segment.spikes) self.assertFalse(st in unit.spiketrains) self.assertFalse(st in segment.spiketrains)
def extract_spikes(train, signals, length, align_time): """ Extract spikes with waveforms from analog signals using a spike train. Spikes that are too close to the beginning or end of the shortest signal to be fully extracted are ignored. :type train: :class:`neo.core.SpikeTrain` :param train: The spike times. :param sequence signals: A sequence of :class:`neo.core.AnalogSignal` objects from which the spikes are extracted. The waveforms of the returned spikes are extracted from these signals in the same order they are given. :type length: Quantity scalar :param length: The length of the waveform to extract as time scalar. :type align_time: Quantity scalar :param align_time: The alignment time of the spike times as time scalar. This is the time delta from the start of the extracted waveform to the exact time of the spike. :returns: A list of :class:`neo.core.Spike` objects, one for each time point in ``train``. All returned spikes include their ``waveform`` property. :rtype: list """ if not signals: raise ValueError('No signals to extract spikes from') ref = signals[0] for s in signals[1:]: if ref.sampling_rate != s.sampling_rate: raise ValueError( 'All signals for spike extraction need the same sampling rate') wave_unit = signals[0].units srate = signals[0].sampling_rate end = min(s.shape[0] for s in signals) aligned_train = train - align_time cut_samples = int((length * srate).simplified) st = sp.asarray((aligned_train * srate).simplified) # Find extraction epochs st_ok = (st >= 0) * (st < end - cut_samples) epochs = sp.vstack((st[st_ok], st[st_ok] + cut_samples)).T.astype(sp.int64) nspikes = epochs.shape[0] if not nspikes: return [] # Create data data = sp.vstack([sp.asarray(s.rescale(wave_unit)) for s in signals]) nc = len(signals) spikes = [] for s in xrange(nspikes): waveform = sp.zeros((cut_samples, nc)) for c in xrange(nc): waveform[:, c] = \ data[c, epochs[s, 0]:epochs[s, 1]] spikes.append(neo.Spike(train[st_ok][s], waveform=waveform * wave_unit, sampling_rate=srate)) return spikes
import ipdb ss = session.create(location="http://predata.g-node.org", username="******", password="******") blk = neo.Block(name='testBlock1') for ind1 in range(3): seg = neo.Segment(name='testSegment' + str(ind1), index=ind1) seg.block = blk for ind2 in range(3): sp = neo.SpikeTrain(name='SpikeTrain' + str(ind2), times=np.random.rand(10) * qu.s, t_stop=1.2) sp.segment = seg seg.spiketrains.append(sp) for ind2 in range(3): sp = neo.Spike(name='Spike' + str(ind2), time=np.random.rand() * qu.s) sp.segment = seg seg.spikes.append(sp) for ind2 in range(3): irr = neo.IrregularlySampledSignal(name='IrregularlySampled' + str(ind2), times=np.random.rand(10) * qu.s, signal=np.random.rand(10) * qu.mV) irr.segment = seg seg.irregularlysampledsignals.append(irr) for ind2 in range(3): an = neo.AnalogSignal(name='AnalogSignal' + str(ind2), signal=np.random.rand(10) * qu.mV, sampling_rate=10 * qu.Hz) an.segment = seg seg.analogsignals.append(an)