Overview

The package is divided into separate sub-modules that solve specific subtasks (pre-processing, baseline estimation etc). The functions in these modules operate on plain numpy.array’s or standard Python-structures. While these functions can be used directly, an easier approach is to use the class PupilData which wraps these functions in a convenient way. Each object of class PupilData represents one dataset of pupillometric data, including time, signal and external events (trial onsets, stimulus presentations, responses, etc). By calling the member functions of such an object, the corresponding function from one of the sub-modules is called using the appropriate arguments.

Reading/writing pupillometric data

So far, reading in data is not part of the pypillometry-package. This is because the format of the eyetracker-files will vary depending on the setup of the eyetracker (there are many ways to represent event-triggers) and the actual model of the eyetracker. Python provides excellent functionality to parse text-based datafiles and we therefore give guidance how to use these tools rather than trying to implement that functionality in our package.

There are many ways in which pupillometric data can be read into Python. For example, Eyelink’s ASC-format generated by the EDF2ASC conversion tool outputs space-separated data that can be easily loaded using the I/O functionality of the pandas package .

Data is input into pypillometry using the constructor of the PupilData object.

However, data that has been converted into PupilData-objects can be easily saved and restored (using shelve).

d=PupilData(...) # create PupilData object after manually loading data
# save the dataset into a shelve-file
d.write_file("dataset.pd")

# load it from the file
d2=PupilData.from_file("dataset.pd")

An example for importing data from Eyelink EDF-files

Pipeline-based processing

pypillometry implements a pipeline-like approach where each operation executed on a PupilData-object returns a copy of the (modified) object. This enables the “chaining” of commands as follows:

d=PupilData.from_file("data/test.pd").blinks_detect().blinks_merge().lowpass_filter(3).downsample(50)

This command loads a data-file (test.pd), applies a 3Hz low-pass filter to it, downsamples the signal to 50 Hz, detects blinks in the signal and merges short, successive blinks together. The final result of this processing-pipeline is stored in object d. This object stores also the complete history of the operations applied to the dataset and allows to transfer it to a new dataset.

See the following page more on this: Pipeline-based processing in pypillometry

Pre-processing data

Assuming you have generated a PupilData object, a range of pre-processing functions are available. The main pre-processing issues with pupillometric data are:

  • artifacts and missing data due to blinks (these can usually be corrected/interpolated)

  • missing data/artifacts from other sources (e.g., looking away, eyetracker losing pupil for other reasons)

  • smoothing/downsampling to get rid of high-freq low-amp noise

Smoothing/low-pass filtering

In most cases, pupillometric data should be low-pass filtered (e.g., using a cutoff of 4 Hz Jackson & Sirois, 2009) or smoothed in other ways (e.g., with a running-window).

Tge following is a list of functions for smoothing:

PupilData.lowpass_filter(cutoff[, order, …])

Lowpass-filter signal using a Butterworth-filter, see pypillometry.baseline.butter_lowpass_filter().

PupilData.smooth_window([window, winsize, …])

Apply smoothing of the signal using a moving window.

PupilData.downsample(fsd[, dsfac, inplace])

Simple downsampling scheme using mean within the downsampling window.

Changing/Slicing data

Often, pupillometric data needs to be trimmed, e.g., to remove pre-experiment recordings or to remove unusable parts of the data (PupilData.sub_slice()). The timing should usually be realigned to the start of the experiment (PupilData.reset_time()). Furthermore, a scaling (e.g., Z-transform) of the pupil-data can be useful for comparing multiple subjects (PupilData.scale()).

The following is a list of available functions for these purposes:

PupilData.sub_slice([start, end, units])

Return a new PupilData object that is a shortened version of the current one (contains all data between start and end in units given by units (one of “ms”, “sec”, “min”, “h”).

PupilData.copy([new_name])

Make and return a deep-copy of the pupil data.

PupilData.scale([mean, sd, inplace])

Scale the pupillary signal by subtracting mean and dividing by sd.

PupilData.unscale([mean, sd, inplace])

Scale back to original values using either values provided as arguments or the values stored in scale_params.

PupilData.reset_time([t0, inplace])

Resets time so that the time-array starts at time zero (t0).

Plotting/Summarizing Data

Plotting

It is crucial to validate preprocessing steps by visually inspecting the results using plots. Therefore, pypillometry implements several plotting facilities that encourage active exploration of the dataset.

Please see the tutorial Plotting of pupillometric data for more details.

PupilData.plot([plot_range, interactive, …])

Make a plot of the pupil data using matplotlib or pypillometry.convenience.plot_pupil_ipy() if interactive=True.

PupilData.plot_segments([overlay, pdffile, …])

Plot the whole dataset chunked up into segments (usually to a PDF file).

PupilData.blinks_plot([pdf_file, nrow, …])

Plot the detected blinks into separate figures each with nrow x ncol subplots.

plotpd(*args[, subplots, baseline])

Plotting for PupilData objects.

plotpd_ia(*args[, figsize, baseline, events])

Interactive plotting for multiple PupilData objects.

PupilData.get_erpd(erpd_name, event_select)

Extract event-related pupil dilation (ERPD).

Inspecting/Summarizing

The package also provides several functions for summarizing datasets. Simply print()`ing a :class:`PupilData object gives a readable summary of the main properties of the dataset and also prints the complete history of the results. By calling PupilData.summary(), summary data can be arranged and summarized in tabular form.

See the notebook Summarizing pupillometric data for more details.

PupilData.summary()

Return a summary of the PupilData-object.

PupilData.stat_per_event(interval[, …])

Return result of applying a statistical function to pupillometric data in a given interval relative to event-onsets.

PupilData.get_erpd(erpd_name, event_select)

Extract event-related pupil dilation (ERPD).

Modeling the pupillometric signal

For some applications, it is interesting to model the full pupillometric signal as consisting of a (tonic) baseline and a (phasic) response component. The package implements novel algorithms developed in our lab and documentation will become available here.

More details are availabel in this notebook: Modeling the pupillometric signal.

PupilData.estimate_baseline([method, inplace])

Apply one of the baseline-estimation methods.

PupilData.estimate_response([npar, tmax, …])

Estimate pupil-response based on event-onsets, see pypillometry.pupil.pupil_response().

PupilData.stat_per_event(interval[, …])

Return result of applying a statistical function to pupillometric data in a given interval relative to event-onsets.

Artificial Data

For validation and testing purposes, it can be useful to generate artificial datasets. The package implements a FakePupilData as inheriting from regular PupilData and therefore shares all its functionality. In addition to that, FakePupilData stores “ground-truth” data and parameters that was used while creating the artificial data.

The function create_fake_pupildata() allows to quickly create datasets generating according to a provided experimental structure (see the functions documentation for an overview over the many available options).

FakePupilData(pupil[, sampling_rate, time, …])

Simulated pupil data for validation purposes.

create_fake_pupildata(**kwargs)

Return a pyillometry.pupildata.FakePupilData object by buildling it with pypillometry.fakedata.get_dataset().