def merge(self, other): ''' Merge the another :class:`Epoch` into this one. The :class:`Epoch` objects are concatenated horizontally (column-wise), :func:`np.hstack`). If the attributes of the two :class:`Epoch` are not compatible, and Exception is raised. ''' othertimes = other.times.rescale(self.times.units) otherdurations = other.durations.rescale(self.durations.units) times = np.hstack([self.times, othertimes]) * self.times.units durations = np.hstack([self.durations, otherdurations ]) * self.durations.units labels = np.hstack([self.labels, other.labels]) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) return Epoch(times=times, durations=durations, labels=labels, **kwargs)
def test_merge_annotations__func__dict(self): ann1 = {'val0': 'val0', 'val1': 1, 'val2': 2.2, 'val3': 'test1', 'val4': [.4], 'val5': {0: 0, 1: {0: 0}}, 'val6': np.array([0, 1, 2])} ann2 = {'val2': 2.2, 'val3': 'test2', 'val4': [4, 4.4], 'val5': {1: {1: 1}, 2: 2}, 'val6': np.array([4, 5, 6]), 'val7': True} ann1c = ann1.copy() ann2c = ann2.copy() targ = {'val0': 'val0', 'val1': 1, 'val2': 2.2, 'val3': 'test1;test2', 'val4': [.4, 4, 4.4], 'val5': {0: 0, 1: {0: 0, 1: 1}, 2: 2}, 'val7': True} res = merge_annotations(ann1, ann2) val6t = np.array([0, 1, 2, 4, 5, 6]) val6r = res.pop('val6') val61 = ann1.pop('val6') val61c = ann1c.pop('val6') val62 = ann2.pop('val6') val62c = ann2c.pop('val6') self.assertEqual(ann1, ann1c) self.assertEqual(ann2, ann2c) self.assertEqual(res, targ) assert_arrays_equal(val6r, val6t) self.assertRaises(AssertionError, assert_arrays_equal, val61, val6t) assert_arrays_equal(val61, val61c) assert_arrays_equal(val62, val62c)
def test_merge_annotations__dict(self): value1 = {'val1': 1, 'val2': 2.2, 'val3': 'test1'} value2 = {'val2': 2.2, 'val3': 'test2', 'val4': [4, 4.4], 'val5': True} targ = {'val1': 1, 'val2': 2.2, 'val3': 'test1;test2', 'val4': [4, 4.4], 'val5': True} res = merge_annotations(value1, value2) self.assertEqual(targ, res)
def merge(self, other): ''' Merge the another :class:`Event` into this one. The :class:`Event` objects are concatenated horizontally (column-wise), :func:`np.hstack`). If the attributes of the two :class:`Event` are not compatible, and Exception is raised. ''' othertimes = other.times.rescale(self.times.units) times = np.hstack([self.times, othertimes]) * self.times.units labels = np.hstack([self.labels, other.labels]) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge({}, {})".format(attr_self, attr_other) print('Event: merge annotations') merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) kwargs['array_annotations'] = self._merge_array_annotations(other) evt = Event(times=times, labels=labels, **kwargs) return evt
def merge(self, other): ''' Merge the another :class:`Epoch` into this one. The :class:`Epoch` objects are concatenated horizontally (column-wise), :func:`np.hstack`). If the attributes of the two :class:`Epoch` are not compatible, and Exception is raised. ''' othertimes = other.times.rescale(self.times.units) times = np.hstack([self.times, othertimes]) * self.times.units kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) kwargs['array_annotations'] = self._merge_array_annotations(other) labels = kwargs['array_annotations']['labels'] durations = kwargs['array_annotations']['durations'] return Epoch(times=times, durations=durations, labels=labels, **kwargs)
def merge(self, other): ''' Merge the another :class:`AnalogSignal` into this one. The :class:`AnalogSignal` objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two :class:`AnalogSignal` are not compatible, and Exception is raised. ''' assert self.sampling_rate == other.sampling_rate assert self.t_start == other.t_start if other.units != self.units: other = other.rescale(self.units) stack = np.hstack(map(np.array, (self, other))) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) return AnalogSignal(stack, units=self.units, dtype=self.dtype, copy=False, t_start=self.t_start, sampling_rate=self.sampling_rate, **kwargs)
def merge(self, other): ''' Merge another signal into this one. The signal objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two signals are not compatible, an Exception is raised. Required attributes of the signal are used. ''' if not np.array_equal(self.times, other.times): raise MergeError( "Cannot merge these two signals as the sample times differ.") if self.segment != other.segment: raise MergeError( "Cannot merge these two signals as they belong to different segments." ) if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): if self.lazy_shape[0] != other.lazy_shape[0]: raise MergeError( "Cannot merge signals of different length.") merged_lazy_shape = (self.lazy_shape[0], self.lazy_shape[1] + other.lazy_shape[1]) else: raise MergeError( "Cannot merge a lazy object with a real object.") if other.units != self.units: other = other.rescale(self.units) stack = np.hstack((self.magnitude, other.magnitude)) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge({}, {})".format(attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) signal = self.__class__(self.times, stack, units=self.units, dtype=self.dtype, copy=False, **kwargs) signal.segment = self.segment signal.array_annotate(**self._merge_array_annotations(other)) if hasattr(self, "lazy_shape"): signal.lazy_shape = merged_lazy_shape return signal
def merge(self, other): ''' Merge another :class:`AnalogSignal` into this one. The :class:`AnalogSignal` objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two :class:`AnalogSignal` are not compatible, an Exception is raised. ''' if self.sampling_rate != other.sampling_rate: raise MergeError("Cannot merge, different sampling rates") if self.t_start != other.t_start: raise MergeError("Cannot merge, different t_start") if self.segment != other.segment: raise MergeError("Cannot merge these two signals as they belong to different segments.") if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): if self.lazy_shape[0] != other.lazy_shape[0]: raise MergeError("Cannot merge signals of different length.") merged_lazy_shape = (self.lazy_shape[0], self.lazy_shape[1] + other.lazy_shape[1]) else: raise MergeError("Cannot merge a lazy object with a real object.") if other.units != self.units: other = other.rescale(self.units) stack = np.hstack(map(np.array, (self, other))) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) signal = AnalogSignal(stack, units=self.units, dtype=self.dtype, copy=False, t_start=self.t_start, sampling_rate=self.sampling_rate, **kwargs) signal.segment = self.segment # merge channel_index (move to ChannelIndex.merge()?) if self.channel_index and other.channel_index: signal.channel_index = ChannelIndex( index=np.arange(signal.shape[1]), channel_ids=np.hstack([self.channel_index.channel_ids, other.channel_index.channel_ids]), channel_names=np.hstack([self.channel_index.channel_names, other.channel_index.channel_names])) else: signal.channel_index = ChannelIndex(index=np.arange(signal.shape[1])) if hasattr(self, "lazy_shape"): signal.lazy_shape = merged_lazy_shape return signal
def merge(self, other): ''' Merge another :class:`IrregularlySampledSignal` with this one, and return the merged signal. The :class:`IrregularlySampledSignal` objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two :class:`IrregularlySampledSignal` are not compatible, a :class:`MergeError` is raised. ''' if not np.array_equal(self.times, other.times): raise MergeError( "Cannot merge these two signals as the sample times differ.") if self.segment != other.segment: raise MergeError( "Cannot merge these two signals as they belong to different segments." ) if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): if self.lazy_shape[0] != other.lazy_shape[0]: raise MergeError( "Cannot merge signals of different length.") merged_lazy_shape = (self.lazy_shape[0], self.lazy_shape[1] + other.lazy_shape[1]) else: raise MergeError( "Cannot merge a lazy object with a real object.") if other.units != self.units: other = other.rescale(self.units) stack = np.hstack(map(np.array, (self, other))) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) signal = IrregularlySampledSignal(self.times, stack, units=self.units, dtype=self.dtype, copy=False, **kwargs) signal.segment = self.segment if hasattr(self, "lazy_shape"): signal.lazy_shape = merged_lazy_shape return signal
def merge(self, other): ''' Merge another :class:`IrregularlySampledSignal` with this one, and return the merged signal. The :class:`IrregularlySampledSignal` objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two :class:`IrregularlySampledSignal` are not compatible, a :class:`MergeError` is raised. ''' if not np.array_equal(self.times, other.times): raise MergeError("Cannot merge these two signals as the sample times differ.") if self.segment != other.segment: raise MergeError("Cannot merge these two signals as they belong to different segments.") if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): if self.lazy_shape[0] != other.lazy_shape[0]: raise MergeError("Cannot merge signals of different length.") merged_lazy_shape = (self.lazy_shape[0], self.lazy_shape[1] + other.lazy_shape[1]) else: raise MergeError("Cannot merge a lazy object with a real object.") if other.units != self.units: other = other.rescale(self.units) stack = np.hstack(map(np.array, (self, other))) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) signal = IrregularlySampledSignal(self.times, stack, units=self.units, dtype=self.dtype, copy=False, **kwargs) signal.segment = self.segment if hasattr(self, "lazy_shape"): signal.lazy_shape = merged_lazy_shape return signal
def merge(self, other): ''' Merge the another :class:`AnalogSignalArray` into this one. The :class:`AnalogSignalArray` objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two :class:`AnalogSignalArray` are not compatible, and Exception is raised. ''' assert self.sampling_rate == other.sampling_rate assert self.t_start == other.t_start other.units = self.units stack = np.hstack(map(np.array, (self, other))) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) if self.channel_index is None: channel_index = other.channel_index elif other.channel_index is None: channel_index = self.channel_index else: channel_index = np.append(self.channel_index, other.channel_index) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) return AnalogSignalArray(stack, units=self.units, dtype=self.dtype, copy=False, t_start=self.t_start, sampling_rate=self.sampling_rate, channel_index=channel_index, **kwargs)
def merge(self, other): ''' Merge another :class:`SpikeTrain` into this one. The times of the :class:`SpikeTrain` objects combined in one array and sorted. If the attributes of the two :class:`SpikeTrain` are not compatible, an Exception is raised. ''' if self.sampling_rate != other.sampling_rate: raise MergeError("Cannot merge, different sampling rates") if self.t_start != other.t_start: raise MergeError("Cannot merge, different t_start") if self.t_stop != other.t_stop: raise MemoryError("Cannot merge, different t_stop") if self.left_sweep != other.left_sweep: raise MemoryError("Cannot merge, different left_sweep") if self.segment != other.segment: raise MergeError("Cannot merge these two signals as they belong to" " different segments.") if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): merged_lazy_shape = (self.lazy_shape[0] + other.lazy_shape[0]) else: raise MergeError("Cannot merge a lazy object with a real" " object.") if other.units != self.units: other = other.rescale(self.units) wfs = [self.waveforms is not None, other.waveforms is not None] if any(wfs) and not all(wfs): raise MergeError("Cannot merge signal with waveform and signal " "without waveform.") stack = np.concatenate((np.asarray(self), np.asarray(other))) sorting = np.argsort(stack) stack = stack[sorting] kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) train = SpikeTrain(stack, units=self.units, dtype=self.dtype, copy=False, t_start=self.t_start, t_stop=self.t_stop, sampling_rate=self.sampling_rate, left_sweep=self.left_sweep, **kwargs) if all(wfs): wfs_stack = np.vstack((self.waveforms, other.waveforms)) wfs_stack = wfs_stack[sorting] train.waveforms = wfs_stack train.segment = self.segment if train.segment is not None: self.segment.spiketrains.append(train) if hasattr(self, "lazy_shape"): train.lazy_shape = merged_lazy_shape return train
def merge(self, other): ''' Merge another signal into this one. The signal objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two signal are not compatible, an Exception is raised. Required attributes of the signal are used. ''' for attr in self._necessary_attrs: if 'signal' != attr[0]: if getattr(self, attr[0], None) != getattr(other, attr[0], None): raise MergeError("Cannot merge these two signals as the %s differ." % attr[0]) if self.segment != other.segment: raise MergeError( "Cannot merge these two signals as they belong to different segments.") if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): if self.lazy_shape[0] != other.lazy_shape[0]: raise MergeError("Cannot merge signals of different length.") merged_lazy_shape = (self.lazy_shape[0], self.lazy_shape[1] + other.lazy_shape[1]) else: raise MergeError("Cannot merge a lazy object with a real object.") if other.units != self.units: other = other.rescale(self.units) stack = np.hstack((self.magnitude, other.magnitude)) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge(%s, %s)" % (attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) kwargs['array_annotations'] = self._merge_array_annotations(other) signal = self.__class__(stack, units=self.units, dtype=self.dtype, copy=False, t_start=self.t_start, sampling_rate=self.sampling_rate, **kwargs) signal.segment = self.segment if hasattr(self, "lazy_shape"): signal.lazy_shape = merged_lazy_shape # merge channel_index (move to ChannelIndex.merge()?) if self.channel_index and other.channel_index: signal.channel_index = ChannelIndex(index=np.arange(signal.shape[1]), channel_ids=np.hstack( [self.channel_index.channel_ids, other.channel_index.channel_ids]), channel_names=np.hstack( [self.channel_index.channel_names, other.channel_index.channel_names])) else: signal.channel_index = ChannelIndex(index=np.arange(signal.shape[1])) return signal
def merge(self, other): ''' Merge another signal into this one. The signal objects are concatenated horizontally (column-wise, :func:`np.hstack`). If the attributes of the two signal are not compatible, an Exception is raised. Required attributes of the signal are used. ''' for attr in self._necessary_attrs: if 'signal' != attr[0]: if getattr(self, attr[0], None) != getattr( other, attr[0], None): raise MergeError( "Cannot merge these two signals as the %s differ." % attr[0]) if self.segment != other.segment: raise MergeError( "Cannot merge these two signals as they belong to different segments." ) if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): if self.lazy_shape[0] != other.lazy_shape[0]: raise MergeError( "Cannot merge signals of different length.") merged_lazy_shape = (self.lazy_shape[0], self.lazy_shape[1] + other.lazy_shape[1]) else: raise MergeError( "Cannot merge a lazy object with a real object.") if other.units != self.units: other = other.rescale(self.units) stack = np.hstack((self.magnitude, other.magnitude)) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge({}, {})".format(attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) kwargs['array_annotations'] = self._merge_array_annotations(other) signal = self.__class__(stack, units=self.units, dtype=self.dtype, copy=False, t_start=self.t_start, sampling_rate=self.sampling_rate, **kwargs) signal.segment = self.segment if hasattr(self, "lazy_shape"): signal.lazy_shape = merged_lazy_shape # merge channel_index (move to ChannelIndex.merge()?) if self.channel_index and other.channel_index: signal.channel_index = ChannelIndex( index=np.arange(signal.shape[1]), channel_ids=np.hstack([ self.channel_index.channel_ids, other.channel_index.channel_ids ]), channel_names=np.hstack([ self.channel_index.channel_names, other.channel_index.channel_names ])) else: signal.channel_index = ChannelIndex( index=np.arange(signal.shape[1])) return signal
def concatenate(self, other, allow_overlap=False): ''' Combine this and another signal along the time axis. The signal objects are concatenated vertically (row-wise, :func:`np.vstack`). Patching can be used to combine signals across segments. Note: Only array annotations common to both signals are attached to the concatenated signal. If the attributes of the two signal are not compatible, an Exception is raised. Required attributes of the signal are used. Parameters ---------- other : neo.BaseSignal The object that is merged into this one. allow_overlap : bool If false, overlapping samples between the two signals are not permitted and an ValueError is raised. If true, no check for overlapping samples is performed and all samples are combined. Returns ------- signal : neo.IrregularlySampledSignal Signal containing all non-overlapping samples of both source signals. Raises ------ MergeError If `other` object has incompatible attributes. ''' for attr in self._necessary_attrs: if not (attr[0] in ['signal', 'times', 't_start', 't_stop', 'times']): if getattr(self, attr[0], None) != getattr( other, attr[0], None): raise MergeError( "Cannot concatenate these two signals as the %s differ." % attr[0]) if hasattr(self, "lazy_shape"): if hasattr(other, "lazy_shape"): if self.lazy_shape[-1] != other.lazy_shape[-1]: raise MergeError( "Cannot concatenate signals as they contain" " different numbers of traces.") merged_lazy_shape = (self.lazy_shape[0] + other.lazy_shape[0], self.lazy_shape[-1]) else: raise MergeError( "Cannot concatenate a lazy object with a real object.") if other.units != self.units: other = other.rescale(self.units) new_times = np.hstack((self.times, other.times)) sorting = np.argsort(new_times) new_samples = np.vstack((self.magnitude, other.magnitude)) kwargs = {} for name in ("name", "description", "file_origin"): attr_self = getattr(self, name) attr_other = getattr(other, name) if attr_self == attr_other: kwargs[name] = attr_self else: kwargs[name] = "merge({}, {})".format(attr_self, attr_other) merged_annotations = merge_annotations(self.annotations, other.annotations) kwargs.update(merged_annotations) kwargs['array_annotations'] = intersect_annotations( self.array_annotations, other.array_annotations) if not allow_overlap: if max(self.t_start, other.t_start) <= min(self.t_stop, other.t_stop): raise ValueError( 'Can not combine signals that overlap in time. Allow for ' 'overlapping samples using the "no_overlap" parameter.') t_start = min(self.t_start, other.t_start) t_stop = max(self.t_start, other.t_start) signal = IrregularlySampledSignal(signal=new_samples[sorting], times=new_times[sorting], units=self.units, dtype=self.dtype, copy=False, t_start=t_start, t_stop=t_stop, **kwargs) signal.segment = None signal.channel_index = None if hasattr(self, "lazy_shape"): signal.lazy_shape = merged_lazy_shape return signal
def merge(self, *others): ''' Merge other :class:`SpikeTrain` objects into this one. The times of the :class:`SpikeTrain` objects combined in one array and sorted. If the attributes of the :class:`SpikeTrain` objects are not compatible, an Exception is raised. ''' for other in others: if isinstance(other, neo.io.proxyobjects.SpikeTrainProxy): raise MergeError("Cannot merge, SpikeTrainProxy objects cannot be merged" "into regular SpikeTrain objects, please load them first.") elif not isinstance(other, SpikeTrain): raise MergeError("Cannot merge, only SpikeTrain" "can be merged into a SpikeTrain.") if self.sampling_rate != other.sampling_rate: raise MergeError("Cannot merge, different sampling rates") if self.t_start != other.t_start: raise MergeError("Cannot merge, different t_start") if self.t_stop != other.t_stop: raise MergeError("Cannot merge, different t_stop") if self.left_sweep != other.left_sweep: raise MergeError("Cannot merge, different left_sweep") if self.segment != other.segment: raise MergeError("Cannot merge these signals as they belong to" " different segments.") all_spiketrains = [self] all_spiketrains.extend([st.rescale(self.units) for st in others]) wfs = [st.waveforms is not None for st in all_spiketrains] if any(wfs) and not all(wfs): raise MergeError("Cannot merge signal with waveform and signal " "without waveform.") stack = np.concatenate([np.asarray(st) for st in all_spiketrains]) sorting = np.argsort(stack) stack = stack[sorting] kwargs = {} kwargs['array_annotations'] = self._merge_array_annotations(others, sorting=sorting) for name in ("name", "description", "file_origin"): attr = getattr(self, name) # check if self is already a merged spiketrain # if it is, get rid of the bracket at the end to append more attributes if attr is not None: if attr.startswith('merge(') and attr.endswith(')'): attr = attr[:-1] for other in others: attr_other = getattr(other, name) # both attributes are None --> nothing to do if attr is None and attr_other is None: continue # one of the attributes is None --> convert to string in order to merge them elif attr is None or attr_other is None: attr = str(attr) attr_other = str(attr_other) # check if the other spiketrain is already a merged spiketrain # if it is, append all of its merged attributes that aren't already in attr if attr_other.startswith('merge(') and attr_other.endswith(')'): for subattr in attr_other[6:-1].split('; '): if subattr not in attr: attr += '; ' + subattr if not attr.startswith('merge('): attr = 'merge(' + attr # if the other attribute is not in the list --> append # if attr doesn't already start with merge add merge( in the beginning elif attr_other not in attr: attr += '; ' + attr_other if not attr.startswith('merge('): attr = 'merge(' + attr # close the bracket of merge(...) if necessary if attr is not None: if attr.startswith('merge('): attr += ')' # write attr into kwargs dict kwargs[name] = attr merged_annotations = merge_annotations(*(st.annotations for st in all_spiketrains)) kwargs.update(merged_annotations) train = SpikeTrain(stack, units=self.units, dtype=self.dtype, copy=False, t_start=self.t_start, t_stop=self.t_stop, sampling_rate=self.sampling_rate, left_sweep=self.left_sweep, **kwargs) if all(wfs): wfs_stack = np.vstack([st.waveforms.rescale(self.waveforms.units) for st in all_spiketrains]) wfs_stack = wfs_stack[sorting] * self.waveforms.units train.waveforms = wfs_stack train.segment = self.segment if train.segment is not None: self.segment.spiketrains.append(train) return train