pynapple.process.perievent#

Functions to realign time series relative to a reference time.

Functions

compute_event_triggered_average(data, ...[, ...])

Bin the event timestamps and compute the Event-Triggered Average (ETA).

compute_perievent(data, events, window[, ...])

Perievent alignment, handles both discrete and continuous data.

compute_spike_triggered_average(data, ...[, ...])

Alias for compute_event_triggered_average() with spikes as the events argument.

pynapple.process.perievent.compute_event_triggered_average(data, events, binsize, window=0, time_unit='s', epochs=None)[source]#

Bin the event timestamps and compute the Event-Triggered Average (ETA).

Notes

If C is the event count matrix and feature is a Tsd, then the function computes the Hankel matrix H from window=(-t1,+t2) by offseting the Tsd. The ETA is then defined as the dot product between H and C divided by the number of events.

Parameters:
  • data (Tsd, TsdFrame, or TsdTensor) – The continuous timeseries to use as the feature (must be regularly sampled).

  • events (Ts, Tsd, TsdFrame, TsdTensor, or TsGroup) – The events (or spike trains) to align to. If a TsGroup, each unit’s spikes are binned and used as a separate event count vector. If not a Ts, we simply take the timestamps of the object.

  • binsize (float or int) – The bin size.

  • window (int, float, or tuple) – The alignment window. Can be unequal on each side, e.g. (-2, 1).

  • time_unit (str, optional) – Time units of the window and binsize (‘s’ [default], ‘ms’, ‘us’).

  • epochs (IntervalSet, optional) – The epochs to perform the operation over. If None, uses the data’s time_support.

Returns:

The event-triggered average.

Return type:

TsdFrame or TsdTensor

Raises:
  • RuntimeError – If time_unit is invalid, window format is invalid, or data is not regularly sampled.

  • TypeError – If data or events are not valid timeseries objects.

Examples

Compute the ETA of a continuous feature triggered on a single event train:

>>> import pynapple as nap
>>> import numpy as np
>>> times = np.arange(0, 10, 0.1)
>>> feature = nap.Tsd(t=times, d=np.sin(times))
>>> events = nap.Ts(t=[1.0, 3.0, 5.0, 7.0])
>>> eta = nap.compute_event_triggered_average(feature, events, binsize=0.1, window=0.5)
>>> eta
Time (s)            0
----------  ---------
-0.5        0.0788719
-0.4        0.0994986
-0.3        0.119131
-0.2        0.137573
-0.1        0.154641
0           0.170163
0.1         0.183986
0.2         0.19597
0.3         0.205995
0.4         0.213963
0.5         0.219793
dtype: float64, shape: (11, 1)

You can restrict the computation to certain parts of the data by passing epochs:

>>> epochs = nap.IntervalSet(start=[0, 5], end=[4, 9])
>>> eta = nap.compute_event_triggered_average(feature, events, binsize=0.1, window=0.5, epochs=epochs)
>>> eta
Time (s)           0
----------  --------
-0.5        0.323254
-0.4        0.347921
-0.3        0.369112
-0.2        0.386614
-0.1        0.400254
0           0.170163
0.1         0.183986
0.2         0.19597
0.3         0.205995
0.4         0.213963
0.5         0.219793
dtype: float64, shape: (11, 1)

Compute the ETA triggered on multiple spike trains (TsGroup), returning one column per unit:

>>> unit1 = nap.Ts(t=[1.0, 3.0, 5.0])
>>> unit2 = nap.Ts(t=[2.0, 4.0, 6.0])
>>> spikes = nap.TsGroup({0: unit1, 1: unit2})
>>> eta = nap.compute_event_triggered_average(feature, spikes, binsize=0.1, window=0.5)
>>> eta
Time (s)              0           1
----------  -----------  ----------
-0.5         0.0334559   -0.0196095
-0.4         0.0288176   -0.0247378
-0.3         0.0238914   -0.029619
-0.2         0.0187265   -0.0342041
-0.1         0.0133745   -0.0384476
0            0.00788891  -0.0423069
0.1          0.00232445  -0.0457434
0.2         -0.00326324  -0.0487229
0.3         -0.00881832  -0.0512156
0.4         -0.0142853   -0.0531966
0.5         -0.0196095   -0.054646
dtype: float64, shape: (11, 2)

Compute the ETA of a multiple features (TsdFrame), returning a TsdTensor with shape (n_time_bins, n_events, n_features):

>>> values = np.column_stack([np.sin(times), np.cos(times)])
>>> features = nap.TsdFrame(t=times, d=values, columns=["sin", "cos"])
>>> eta = nap.compute_event_triggered_average(features, events, binsize=0.1, window=0.5)
>>> eta
Time (s)
----------  --------------------------
-0.5        [[0.078872, 0.210558] ...]
-0.4        [[0.099499, 0.201632] ...]
-0.3        [[0.119131, 0.190691] ...]
-0.2        [[0.137573, 0.177845] ...]
-0.1        [[0.154641, 0.163222] ...]
0           [[0.170163, 0.146969] ...]
0.1         [[0.183986, 0.129246] ...]
0.2         [[0.19597 , 0.110233] ...]
0.3         [[0.205995, 0.090118] ...]
0.4         [[0.213963, 0.069102] ...]
0.5         [[0.219793, 0.047396] ...]
dtype: float64, shape: (11, 1, 2)
pynapple.process.perievent.compute_perievent(data, events, window, time_unit='s', epochs=None)[source]#

Perievent alignment, handles both discrete and continuous data.

This function automatically detects the data type, then applies the appropriate alignment strategy:

  • discrete data:
    • a single Ts: returns a TsGroup with one element per event

    • multiple Ts in a TsGroup: returns a dictionary with a TsGroup per unit

  • continuous data:
    • regularly sampled Tsd/TsdFrame/TsdTensor: returns aligned object with events as columns and uniform time sampling

    • irregularly sampled data is not supported; interpolate or NaN-pad to a regular grid before calling this function

Parameters:
  • data (Ts, Tsd, TsdFrame, TsdTensor, TsGroup) – The timeseries to align.

  • events (Ts, Tsd, TsdFrame, TsdTensor) – The events to align to. If not a Ts, we simply take the timestamps of the object.

  • window (int, float, tuple) – The alignment window, which can be unequal on each side, e.g. (-2, 1)

  • time_unit (str, optional) – Time units of the window (‘s’ [default], ‘ms’, ‘us’).

  • epochs (IntervalSet, optional) – The epochs to perform the operation over. If None, uses the data’s time_support.

Returns:

The aligned timeseries.

Return type:

TsGroup, TsdFrame, TsdTensor, dict

Raises:

RuntimeError – If time_unit not in [“s”, “ms”, “us”], window format is invalid, or continuous data is not regularly sampled.

Examples

Align discrete data (Ts) to events:

>>> import pynapple as nap
>>> spikes = nap.Ts(t=[0.5, 1.2, 2.1, 3.5, 4.8])
>>> events = nap.Ts(t=[1.0, 3.0])
>>> result = nap.compute_perievent(spikes, events, window=1.0)
>>> result
  Index    rate    events
-------  ------  --------
      0       1         1
      1       1         3
>>> result[0]
Time (s)
-0.5
0.2
shape: 2
>>> result[1]
Time (s)
-0.9
0.5
shape: 2

Align data to events within specific epochs:

>>> spikes = nap.Ts(t=[0.5, 1.2, 2.1, 3.5, 4.8])
>>> events = nap.Ts(t=[1.0, 3.0, 5.0])
>>> epochs = nap.IntervalSet(start=[0, 2.5], end=[2.4, 4.5])
>>> result = nap.compute_perievent(spikes, events, window=1.0, epochs=epochs)
>>> result # only 2 events are included!
  Index    rate    events
-------  ------  --------
      0       1         1
      1       1         3

Align with unequal window:

>>> import pynapple as nap
>>> import numpy as np
>>> spikes = nap.Ts(t=[0.5, 1.2, 2.1, 3.5])
>>> events = nap.Ts(t=[1.0, 3.0])
>>> result = nap.compute_perievent(spikes, events, window=(-0.5, 1.5))
>>> result[0]  # window from -0.5 to +1.5 relative to first event
Time (s)
-0.5
0.2
1.1
shape: 3

Align multiple discrete objects (TsGroup):

>>> unit1 = nap.Ts(t=[0.5, 1.2, 2.1, 3.5])
>>> unit2 = nap.Ts(t=[0.8, 1.5, 3.2, 4.1])
>>> spikes = nap.TsGroup({0: unit1, 1: unit2})
>>> events = nap.Ts(t=[1.0, 3.0])
>>> result = nap.compute_perievent(spikes, events, window=1.0)
>>> result
{0:   Index    rate    events
-------  ------  --------
      0       1         1
      1       1         3, 1:   Index    rate    events
-------  ------  --------
      0     1           1
      1     0.5         3}
>>> result[0] # aligned unit 0
  Index    rate    events
-------  ------  --------
      0       1         1
      1       1         3
>>> result[1] # aligned unit 1
  Index    rate    events
-------  ------  --------
      0     1           1
      1     0.5         3

Align regularly sampled continuous data (Tsd) to events, returning a TsdFrame:

>>> times = np.arange(0, 10, 0.5)
>>> values = np.sin(times)
>>> data = nap.Tsd(t=times, d=values)
>>> events = nap.Ts(t=[2.0, 5.0, 8.0])
>>> result = nap.compute_perievent(data, events, window=1.0)
>>> result
Time (s)           0          1         2
----------  --------  ---------  --------
-1          0.841471  -0.756802  0.656987
-0.5        0.997495  -0.97753   0.938
0           0.909297  -0.958924  0.989358
0.5         0.598472  -0.70554   0.798487
1           0.14112   -0.279415  0.412118
dtype: float64, shape: (5, 3)

Align a regularly sampled continuous data (TsdFrame) to events, returning a TsdTensor:

>>> values = np.column_stack([np.sin(times), np.cos(times)])
>>> data = nap.TsdFrame(t=times, d=values, columns=["sin", "cos"])
>>> result = nap.compute_perievent(data, events, window=1.0)
>>> result
Time (s)
----------  ----------------------------
-1          [[0.841471, 0.540302] ...]
-0.5        [[0.997495, 0.070737] ...]
0           [[ 0.909297, -0.416147] ...]
0.5         [[ 0.598472, -0.801144] ...]
1           [[ 0.14112 , -0.989992] ...]
dtype: float64, shape: (5, 3, 2)
pynapple.process.perievent.compute_spike_triggered_average(data, spikes, binsize, window=0, time_unit='s', epochs=None)[source]#

Alias for compute_event_triggered_average() with spikes as the events argument.

Parameters:
  • data (Tsd, TsdFrame, or TsdTensor) – The continuous timeseries to use as the feature (must be regularly sampled).

  • spikes (Ts, Tsd, TsdFrame, TsdTensor, or TsGroup) – The spike train(s) to align to.

  • binsize (float or int) – The bin size.

  • window (int, float, or tuple) – The alignment window. Can be unequal on each side, e.g. (-2, 1).

  • time_unit (str, optional) – Time units of the window and binsize (‘s’ [default], ‘ms’, ‘us’).

  • epochs (IntervalSet, optional) – The epochs to perform the operation over. If None, uses the data’s time_support.

Returns:

The spike-triggered average.

Return type:

TsdFrame or TsdTensor

Raises:
  • RuntimeError – If time_unit is invalid, window format is invalid, or data is not regularly sampled.

  • TypeError – If data or spikes are not valid timeseries objects.