diff --git a/syncopy/datatype/discrete_data.py b/syncopy/datatype/discrete_data.py index a8fef9c09..9c8e4b53b 100644 --- a/syncopy/datatype/discrete_data.py +++ b/syncopy/datatype/discrete_data.py @@ -115,7 +115,7 @@ def sample(self): """Indices of all recorded samples""" if self.data is None: return None - return np.unique(self.data[:, self.dimord.index("sample")]) + return self.data[:, self.dimord.index("sample")] @property def samplerate(self): @@ -156,6 +156,9 @@ def trialid(self, trlid): print("SyNCoPy core - trialid: Cannot assign `trialid` without data. " + "Please assing data first") return + if (self.data.shape[0] == 0) and (trlid.shape[0] == 0): + self._trialid = np.array(trlid, dtype=int) + return scount = np.nanmax(self.data[:, self.dimord.index("sample")]) try: array_parser(trlid, varname="trialid", dims=(self.data.shape[0],), @@ -174,7 +177,7 @@ def trialtime(self): # Helper function that grabs a single trial def _get_trial(self, trialno): - return self._data[self.trialid == trialno, :] + return self._data[self._trialslice[trialno], :] # Helper function that spawns a `FauxTrial` object given actual trial information def _preview_trial(self, trialno): diff --git a/syncopy/datatype/methods/definetrial.py b/syncopy/datatype/methods/definetrial.py index a2a23c27d..5ba449294 100644 --- a/syncopy/datatype/methods/definetrial.py +++ b/syncopy/datatype/methods/definetrial.py @@ -335,20 +335,13 @@ def definetrial(obj, trialdefinition=None, pre=None, post=None, start=None, # Compute trial-IDs by matching data samples with provided trial-bounds samples = tgt.data[:, tgt.dimord.index("sample")] - if np.size(samples) > 0: - starts = tgt.sampleinfo[:, 0] - ends = tgt.sampleinfo[:, 1] - startids = np.searchsorted(starts, samples, side="right") - endids = np.searchsorted(ends, samples, side="left") - mask = startids == endids - startids -= 1 - # Samples not belonging into any trial get a trial-ID of -1 - startids[mask] = int(startids.min() <= 0) * (-1) - tgt.trialid = startids - # no data - empty object, can happen due to a selection - else: - tgt.trialid = None - tgt._trialdefinition = None + idx = np.searchsorted(samples, tgt.sampleinfo.ravel()) + idx = idx.reshape(tgt.sampleinfo.shape) + + tgt._trialslice = [slice(st,end) for st,end in idx] + tgt.trialid = np.full((samples.shape), -1, dtype=int) + for itrl, itrl_slice in enumerate(tgt._trialslice): + tgt.trialid[itrl_slice] = itrl # Write log entry if ref == tgt: diff --git a/syncopy/tests/test_discretedata.py b/syncopy/tests/test_discretedata.py index 9a668f464..9a32eee6b 100644 --- a/syncopy/tests/test_discretedata.py +++ b/syncopy/tests/test_discretedata.py @@ -506,69 +506,6 @@ def test_ed_trialsetting(self): with pytest.raises(SPYValueError): ang_dummy.definetrial(evt_dummy, pre=pre, post=post, trigger=1) - # test data-selection via class method - def test_ed_dataselection(self): - - # Create testing objects (regular and swapped dimords) - dummy = EventData(data=np.hstack([self.data, self.data]), - dimord=self.customDimord, - trialdefinition=self.trl, - samplerate=2.0) - ymmud = EventData(data=np.hstack([self.data[:, ::-1], self.data[:, ::-1]]), - trialdefinition=self.trl, - samplerate=2.0, - dimord=dummy.dimord[::-1]) - - # selections are chosen so that result is not empty - trialSelections = [ - "all", # enforce below selections in all trials of `dummy` - [3, 1] # minimally unordered - ] - - eventidSelections = [ - [0, 0, 1], # preserve repetition, don't convert to slice - range(0, 2), # narrow range - ] - - latencySelections = [ - [0.5, 2.5], # regular range - [0.7, 2.] # reduce range - ] - - timeSelections = list(zip(["latency"] * len(latencySelections), latencySelections)) - - trialSels = [random.choice(trialSelections)] - eventidSels = [random.choice(eventidSelections)] - timeSels = [random.choice(timeSelections)] - - for obj in [dummy, ymmud]: - eventidIdx = obj.dimord.index("eventid") - for trialSel in trialSels: - for eventidSel in eventidSels: - for timeSel in timeSels: - kwdict = {} - kwdict["trials"] = trialSel - kwdict["eventid"] = eventidSel - kwdict[timeSel[0]] = timeSel[1] - cfg = StructDict(kwdict) - # data selection via class-method + `Selector` instance for indexing - selected = obj.selectdata(**kwdict) - obj.selectdata(**kwdict, inplace=True) - selector = obj.selection - tk = 0 - for trialno in selector.trial_ids: - if selector.time[tk]: - assert np.array_equal(obj.trials[trialno][selector.time[tk], :], - selected.trials[tk]) - tk += 1 - assert np.array_equal(selected.eventid, - obj.eventid[np.unique(selected.data[:, eventidIdx]).astype(np.intp)]) - cfg.data = obj - # data selection via package function and `cfg`: ensure equality - out = selectdata(cfg) - assert np.array_equal(out.eventid, selected.eventid) - assert np.array_equal(out.data, selected.data) - def test_ed_parallel(self, testcluster): # repeat selected test w/parallel processing engine client = dd.Client(testcluster)