Skip to content

Commit

Permalink
Add amplitude discriminator parameter for extrema type (peak or trough)
Browse files Browse the repository at this point in the history
The new `type` parameter allows the default types (peaks for amplitude windows with positive bounds; troughs for negative bounds) to be overridden. It also permits amplitude windows spanning zero (negative lower bound and positive upper bound), for which the type cannot be inferred.
  • Loading branch information
jpgill86 committed Dec 22, 2020
1 parent faa1a5d commit c95a55f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 20 deletions.
44 changes: 30 additions & 14 deletions docs/metadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -484,16 +484,24 @@ provides bandpass filtering.
Amplitude Discriminators
------------------------

Spikes with peaks that fall within amplitude windows given by
Spikes with peaks (or troughs) that fall within amplitude windows given by
``amplitude_discriminators`` can be automatically detected by *neurotic* on the
basis of amplitude alone. Note that amplitude discriminators are only applied
if fast loading is off (``lazy=False``).
basis of amplitude. Note that amplitude discriminators are only applied if fast
loading is off (``lazy=False``).

Detected spikes are indicated on the signals with markers, and spike trains are
displayed in a raster plot. Optionally, a color may be specified for an
amplitude discriminator using a single letter color code (e.g., ``'b'`` for
blue or ``'k'`` for black) or a hexadecimal color code (e.g., ``'1b9e77'``).

The algorithm can detect either peaks or troughs in the signal. When both the
lower and upper bounds for amplitude windows are positive, the default behavior
is to detect peaks. When both are negative, the default is to detect troughs.
These defaults can be overridden using `type: trough` or `type: peak`,
respectively. This is useful when, for example, detecting subthreshold
excitatory postsynaptic potentials. If the signs of the bounds differ, explicit
specification of the type is required.

In addition to restricting spike detection for a given unit to an amplitude
window, detection can also be limited in time to overlap with epochs with a
given label.
Expand Down Expand Up @@ -522,17 +530,25 @@ for each amplitude discriminator.
epoch: Unit 2 activity
color: 'e6ab02'
Here two units are detected on the same channel with different amplitude
windows. Any peaks between 50 and 150 microvolts on the "Extracellular" channel
will be tagged as a spike belonging to "Unit 1". The discriminator for "Unit 2"
provides the optional ``epoch`` parameter. This restricts detection of "Unit 2"
to spikes within the amplitude window that occur at the same time as epochs
labeled "Unit 2 activity". These epochs can be created by the epoch encoder
(reload required to rerun spike detection at launch-time), specified in the
read-only ``annotations_file``, or even be contained in the ``data_file`` if
the format supports epochs.

Amplitude windows are permitted to be negative.
- name: Unit 3
channel: Intracellular
units: mV
amplitude: [-10, 60]
type: peak
Here two units are detected on the "Extracellular" channel with different
amplitude windows, and a third unit is detected on the "Intracellular" channel.
On the "Extracellular" channel, any peaks between 50 and 150 microvolts will be
tagged as a spike belonging to "Unit 1". The discriminator for "Unit 2" detects
smaller peaks, between 20 and 50 microvolts, and it provides the optional
``epoch`` parameter. This restricts detection of "Unit 2" to spikes within the
amplitude window that occur at the same time as epochs labeled "Unit 2
activity". These epochs can be created by the epoch encoder (reload required to
rerun spike detection at launch-time), specified in the read-only
``annotations_file``, or even be contained in the ``data_file`` if the format
supports epochs. Finally, peaks between -10 and +60 millivolts will be detected
on the "Intracellular" channel; because the signs of these bounds differ, the
type (peak or trough) must be explicitly given.

.. _config-metadata-tridesclous:

Expand Down
24 changes: 18 additions & 6 deletions neurotic/datasets/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,21 +604,32 @@ def _detect_spikes(sig, discriminator, epochs):

min_threshold = min(discriminator['amplitude'])
max_threshold = max(discriminator['amplitude'])
if min_threshold >= 0 and max_threshold > 0:
spike_type = discriminator.get('type', None)
if spike_type == 'peak':
sign = 'above'
elif min_threshold < 0 and max_threshold <= 0:
elif spike_type == 'trough':
sign = 'below'
elif spike_type is None:
# infer type from thresholds
if min_threshold >= 0 and max_threshold > 0:
spike_type = 'peak'
sign = 'above'
elif min_threshold < 0 and max_threshold <= 0:
spike_type = 'trough'
sign = 'below'
else:
raise ValueError('automatic spike type inference for amplitude discriminator is possible only with two nonnegative thresholds (type=peak) or two nonpositive thresholds (type=trough); otherwise, type must be given explicitly: {}'.format(discriminator))
else:
raise ValueError('amplitude discriminator must have two nonnegative thresholds or two nonpositive thresholds: {}'.format(discriminator))
raise ValueError('amplitude discriminator type must be "peak", "trough", or unspecified: {}'.format(discriminator))

spikes_crossing_min = _elephant_tools.peak_detection(sig, pq.Quantity(min_threshold, discriminator['units']), sign, 'raw')
spikes_crossing_max = _elephant_tools.peak_detection(sig, pq.Quantity(max_threshold, discriminator['units']), sign, 'raw')
if sign == 'above':
if spike_type == 'peak':
spikes_between_min_and_max = np.setdiff1d(spikes_crossing_min, spikes_crossing_max)
elif sign == 'below':
elif spike_type == 'trough':
spikes_between_min_and_max = np.setdiff1d(spikes_crossing_max, spikes_crossing_min)
else:
raise ValueError('sign should be "above" or "below": {}'.format(sign))
raise ValueError('type should be "peak" or "trough": {}'.format(spike_type))

st = neo.SpikeTrain(
name = discriminator['name'],
Expand All @@ -630,6 +641,7 @@ def _detect_spikes(sig, discriminator, epochs):
st.annotate(
channels=[discriminator['channel']],
amplitude=pq.Quantity(discriminator['amplitude'], discriminator['units']),
type=spike_type,
)

if 'epoch' in discriminator:
Expand Down

0 comments on commit c95a55f

Please sign in to comment.