Introduction

This notebook explains some core principles underlying timewizard. For fully-worked examples, see the Tutorials, and for a full reference, see the API Reference.

What?

Timewizard is a Python library that makes it easier to work with timeseries data that contain events of interest, especially in the context of neuroscience. Timewizard makes the following tasks quick and efficient:

  • collecting peri-event traces of any-dimensional data, efficiently + with good boundary handling

  • collecting peri-event events (i.e. lick times relative to a stimulus; or spike times for rasters)

  • aligning data sampled at different rates

  • describing stimulus trains (i.e. optogenetic stimuli), or any other kind of events with onsets/offsets

  • matching events across different sensors

Additionally, timewizard provides utility functions for state sequences (i.e. for finding runs and n-grams).

Why?

Existing libraries either:

  • provide functional building blocks, e.g. numpy

  • store your data, e.g. NWB

  • or are very modality-specific, e.g. pynapple.

I use and enjoy all of those packages, but I wanted something that would help me analyze generic timeseries and peri-event data with no fuss.

Analyzing timeseries data can be difficult for a few key reasons:

  • Aligning data collected at different sampling rates is non-trivial, and can be memory intensive if done poorly.

  • Many implementations of peri-stimulus analyses are quite slow.

  • Handling edge cases (i.e. one data stream ends before the other) is mind-numbing and time-consuming.

Timewizard’s goal is to provide a set of generic, API-light, modality-agnostic functions that wrap and simplify common timeseries manipulations.

Core principles

Fewer for-loops: timewizard allows you to collect peri-event data for all your events and all your data in one fell swoop (assuming you have all your data in an np.ndarray). Stop looping over your events!

Note

See: tw.perievent_traces

Only interpolate what you need…: timewizard provides a thin wrapper around scipy.stats.interp1d that makes it easy to only interpolate a particular subset of your data. For example, if you need to know an animal’s position when a given neuron fired, you don’t need to first downsample / upsample all the data; just interpolate its position at the neuron’s firing times, saving time + memory.

Note

See: tw.map_values(...interpolate=True)

…or skip interpolation entirely: timewizard also provides an “nearest value” alternative to interpolation. For example, say you’ve already smoothed neural spike data into a continuous firing rate sampled at 1 kHz; there’s no need to get any more precise than that. (You don’t have to interpolate down to the nearest microsecond because neural firing rates don’t change that quickly). If you then want to know the neural firing rate at some time t, you only need to find the firing rate at some t' within 1 ms of t in your existing firing rate data.

Note

See: tw.map_values(...interpolate=False)

Caveat emptor

  • NB: timewizard assumes that the timestamps of your data are already aligned to a single clock. If you need help synchronizing data across multiple sources, check out the following resources: [todo – add various links explaining sync codes + barcodes + triggering].

Usage

How does my data need to look to use it?

Timewizard functions rely on a very minimal set of assumptions. To wit, your data must:

  • have time along the 0-th axis (TODO: kwarg to change this)

  • be sorted along the time (0-th) axis

  • be convertible to numpy arrays

Head over to the Tutorials to see timewizard in action!