API documentation

Python-package to help with processing of pupillometric and eyetracking data.

This package provides classes for handling pupillometric and eyetracking data as well as tools for plotting and analyzing these data.

Unit Handling:

Distance and angle parameters accept three formats: 1. Plain numbers (assumed to be mm for distances, radians for angles - with warning) 2. String format: “600 mm”, “60 cm”, “20 degrees”, “-90 degrees” 3. Pint Quantity: 600 * ureg.mm, 20 * ureg.degree

The unit registry is available as pypillometry.ureg for advanced users.

Overview

        classDiagram
 EyeData <|-- GazeData
 EyeData <|-- PupilData
 PupilData <|-- GenericEyeData
 GazeData <|-- GenericEyeData

 GazeData: +EyeDataDict data[left_x, left_y, right_x, right_y]
 GazeData: +GazePlotter plot
 GazeData: +set_experimental_setup() (and other gaze-specific functions)
 PupilData: +EyeDataDict data[left_pupil, right_pupil]
 PupilData: +PupilPlotter plot
 PupilData: +pupil_blinks_detect() (and other pupil-specific functions)
 EyeData: +EyeDataDict data[left_pupil, right_pupil, left_x, left_y, right_x, right_y]
 EyeData: +EyePlotter plot
 EyeData: +correct_pupil_foreshortening() (and other functions needing both gaze and pupil data)
    

EyeData([time, left_x, left_y, left_pupil, ...])

Class for handling eye-tracking data.

PupilData([time, left_pupil, right_pupil, ...])

Class representing pupillometric data.

GazeData([time, left_x, left_y, right_x, ...])

Class representing Eye-Tracking data (x,y) from one or two eyes.

GenericEyeData()

Generic class for eyedata.

EyeDataDict(*args, **kwargs)

A dictionary that contains 1-dimensional ndarrays of equal length and with the same datatype (float).

Primary classes

Several different classes are available for handling different types of eye data.

  • PupilData: If you have only pupillometric data, use this class.

  • GazeData: If you only have gaze data, use this class.

  • EyeData: If you have both gaze and pupillometric data, use this class.

These classes inherit from GenericEyeData, which provides some basic, shared functionality for handling eye data.

The data inside each of these classes is stored in the data attribute, which is a dictionary-like object of type EyeDataDict.

Each of these classes provides access to a matching plotter object (from module pypillometry.plot) that is stored in the plot attribute.

EyeData

class pypillometry.EyeData(time=None, left_x=None, left_y=None, left_pupil=None, right_x=None, right_y=None, right_pupil=None, event_onsets=None, event_labels=None, sampling_rate=None, experimental_setup=None, name=None, calibration=None, fill_time_discontinuities=True, keep_orig=False, info=None, inplace=None)[source]

Class for handling eye-tracking data. This class is a subclass of GazeData and PupilData and inherits all their methods and attributes. In addition to the methods in GazeData which implement functions for eye-tracking data and those in PupilData for pupillometric data, EyeData provides methods that need both gaze and pupil data (e.g., foreshortening correction).

Properties such as eyes and variables are inherited from GenericEyeData.

Parameters:
  • time (ndarray) – timing array (in ms) or None, in which case the time-array goes from [0,maxT] using sampling_rate

  • left_x (ndarray) – data from left eye (at least one of the eyes must be provided, both x and y) pupil is optional

  • left_y (ndarray) – data from left eye (at least one of the eyes must be provided, both x and y) pupil is optional

  • left_pupil (ndarray) – data from left eye (at least one of the eyes must be provided, both x and y) pupil is optional

  • right_x (ndarray) – data from right eye (at least one of the eyes must be provided, both x and y) pupil is optional

  • right_y (ndarray) – data from right eye (at least one of the eyes must be provided, both x and y) pupil is optional

  • right_pupil (ndarray) – data from right eye (at least one of the eyes must be provided, both x and y) pupil is optional

  • event_onsets (ndarray) – time-onsets of any events in the data (in ms, matched in time vector)

  • event_labels (ndarray) – for each event in event_onsets, provide a label

  • sampling_rate (float) – sampling-rate of the signal in Hz; if None, it is estimated from the median difference in time (either time or sampling_rate must be provided)

  • experimental_setup (Optional[ExperimentalSetup]) – Geometric model of the experimental setup including screen geometry, eye position, camera position, and screen orientation.

  • name (str) – name of the dataset or None (in which case a random string is selected)

  • calibration (Optional[Dict[str, SpatialCalibration]]) – Dictionary of SpatialCalibration objects, one per eye (keys: ‘left’, ‘right’)

  • fill_time_discontinuities (bool) – sometimes, when the eyetracker loses signal, no entry in the EDF is made; when this option is True, such entries will be made and the signal set to 0 there (or do it later using fill_time_discontinuities())

  • keep_orig (bool) – keep a copy of the original dataset? If True, a copy of the object as initiated in the constructor is stored in member original

  • info (dict) – optional dictionary with additional information about the dataset (stored in member info)

  • inplace (Optional[bool]) – default for methods called with inplace=None: if True, they modify the object in place; if False, they return a modified copy; if None (default), use the package-level setting (see set_default_inplace(), initially True). The method-level inplace argument overrides this.

Examples

>>> import numpy as np
>>> from pypillometry.eyedata import EyeData
>>> d=EyeData(time=np.arange(0, 1000, 1),
...         left_x=np.random.randn(1000),
...         left_y=np.random.randn(1000))
>>> print(d)
Attributes:
blinks

Return blinks (intervals) for all eyes.

events

Events (onsets in ms) as an Events object.

eyes

Return a list of available eyes in the dataset.

plot

Plotting functions for this object (a EyePlotter).

variables

Return a list of available variables in the dataset.

Methods

add_to_history(event)

Add event to history.

blink_stats([eyes, units])

Return statistics on blink durations.

blinks_merge_close([eyes, variables, ...])

Merge blinks that are close together.

copy([new_name])

Make and return a deep-copy of the eyedata object.

correct_pupil_foreshortening([eyes, ...])

Correct pupil data using a simple algorithm to correct for foreshortening effects.

downsample(fsd[, dsfac, inplace])

Simple downsampling scheme using mean within the downsampling window.

drop_data([eyes, variables])

Drop specified eyes and/or variables from the data and return a new object.

drop_original([inplace])

Drop original dataset from record (e.g., to save space).

fill_time_discontinuities([yval, print_info])

Find gaps in the time-vector and fill them in (in-place).

fit_foreshortening(eye[, r, d, intervals, ...])

Fit foreshortening correction model to estimate camera geometry and true pupil size.

from_eyelink(fname[, return_edf_obj, ...])

Reads an eyedata object from an Eyelink file.

from_file(fname)

Reads a GenericEyeData object from a pickle-file.

get_blinks([eyes, variables, units])

Get blinks as Intervals object or dict of Intervals.

get_duration([units])

Return duration of the dataset in units specified.

get_events([units])

Get events as an Events object.

get_interpolated_blinks([eyes, variables, units])

Get interpolated blinks as Intervals object or dict of Intervals.

get_intervals(event_select[, interval, ...])

Return an Intervals object containing intervals relative to event-onsets.

get_pupildata([eye])

Return the pupil data as a PupilData object.

get_segments(intervals, variable[, name])

Extract segments from data using intervals.

get_size()

Return the size of the object in bytes.

interpolate_intervals(intervals[, eyes, ...])

Interpolate data within specified intervals.

mask_as_intervals([eyes, variables, units, ...])

Convert masks to Intervals objects.

mask_eye_divergences([threshold, thr_type, ...])

Calculate Euclidean distance between left and right eye coordinates and detect divergences.

mask_intervals(intervals[, eyes, variables, ...])

Apply Intervals as masks to selected data.

mask_offscreen_coords([eyes, apply_mask, ...])

Detect and mask gaze coordinates that fall outside the screen boundaries.

merge_eyes([eyes, variables, method, ...])

Merge data from both eyes into a single variable.

merge_masks([inplace])

Merge masks of all variables into a single joint mask.

nblinks([eyes, variables])

Return number of detected blinks.

nevents()

Return number of events in data.

print_history()

Pretty-print the history of the current dataset (which manipulations where done on it).

pupil_blinks_detect([eyes, min_duration, ...])

Detect blinks in the pupillary signal using several strategies.

pupil_blinks_interpolate([eyes, store_as, ...])

Interpolating blinks in the pupillary signal.

pupil_estimate_baseline([eyes, variable, ...])

Apply one of the baseline-estimation methods.

pupil_estimate_response([eyes, npar, tmax, ...])

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

pupil_lowpass_filter(cutoff[, order, eyes, ...])

Lowpass-filter pupil signal using a Butterworth-filter.

pupil_merge_eyes([method, lowpass_cutoff, ...])

Merge pupil data from both eyes into a single "merged" variable.

pupil_smooth_window([eyes, window, winsize, ...])

Apply smoothing of the signal using a moving window.

reset_time([t0, inplace])

Resets time so that time t0 becomes time zero.

scale([variables, mean, sd, eyes, inplace])

Scale the signal by subtracting mean and dividing by sd.

set_blinks(intervals[, eyes, variables, ...])

Set blinks for specified eyes and variables (in-place).

set_event_onsets(event_onsets, event_labels)

Set onsets of events in the data (in-place).

set_events(events[, inplace])

Replace event onsets and labels from an Events object.

set_experimental_setup(**kwargs)

Set or update the experimental setup geometry (in-place).

stat_per_event([intervals, interval, ...])

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

sub_slice([start, end, units, inplace])

Return a shortened version of the current object.

summary()

Return a summary of the dataset as a dictionary.

unscale([variables, mean, sd, eyes, inplace])

Scale back to original values using either values provided as arguments or the values stored in params["scale"] by scale().

write_file(fname)

Save to file (using pickle).

correct_pupil_foreshortening(eyes=[], midpoint=None, store_as='pupil', inplace=None)[source]

Correct pupil data using a simple algorithm to correct for foreshortening effects.

Correct the pupil data for foreshortening effects caused by saccades/eye movements. This method is based on a simple algorithm that assumes the pupil appears perfectly circular when fixating midpoint: for each sample, the distance \(\Delta\) (in mm) of the gaze position from midpoint is computed and the pupil signal is multiplied by the correction factor \(\sqrt{1+\Delta^2/d^2}\), where \(d\) is the eye-to-screen distance from the experimental setup. For a more complete model that also estimates the camera position, see fit_foreshortening().

Relevant publication (not the description of the algorithm used here): https://link.springer.com/article/10.3758/s13428-015-0588-x

  • [ ] TODO: when using interpolated pupil data, x/y data may still be missing. Make sure that the pupil data is not touched where x/y is missing

Parameters:
  • eyes (list) – Which eyes to correct. If empty, correct all available eyes.

  • midpoint (tuple or None) – The center of the screen (x,y) in pixels where it is assumed that the pupil is completely circular. If None, the midpoint is taken to be the center of the screen as registered in the experimental_setup.

  • store_as (str) – name of the variable in which to store the corrected pupil data (as data[eye, store_as]); the default “pupil” replaces the original pupil data

  • inplace (bool or None) – Whether to modify the object in place or return a new object. true: modify in place false: return a new object None: use the object’s default setting (initialized in __init__)

Returns:

An EyeData object with the corrected pupil

Return type:

EyeData

Raises:

ValueError – if no experimental setup is set (see set_experimental_setup())

fit_foreshortening(eye, r=None, d=None, intervals=None, target_fs=50.0, lowpass_freq=4.0, lambda_smooth=1.0, knots_per_second=1.0, initial_theta=None, initial_phi=None, verbose=True)[source]

Fit foreshortening correction model to estimate camera geometry and true pupil size.

This method implements Stage 1 of the foreshortening correction algorithm, which jointly estimates the camera position (theta, phi) and the temporal dynamics of true pupil size A0(t) using B-splines. The data is automatically preprocessed (filtered and downsampled) before fitting.

Parameters:
  • eye (str) – Which eye to fit (‘left’ or ‘right’)

  • r (Union[float, str, None]) –

    Eye-to-camera distance. If not provided, uses the r from experimental_setup.

    • Plain number: assumed to be mm (with warning)

    • String: e.g., “600 mm”, “60 cm”

    • Quantity: e.g., 600 * ureg.mm

  • d (Union[float, str, None]) –

    Eye-to-screen distance. If not provided, uses the d from experimental_setup.

    • Plain number: assumed to be mm (with warning)

    • String: e.g., “700 mm”, “70 cm”

    • Quantity: e.g., 700 * ureg.mm

  • intervals (Optional[Intervals]) – Time intervals to use for fitting. If None, uses all available data. Useful for fitting only on calibration periods. The start/end values are compared to the time vector, so they must be in ms.

  • target_fs (float) – Target sampling rate in Hz after downsampling for efficiency. Pupil dynamics are typically well-preserved at 50 Hz.

  • lowpass_freq (float) – Lowpass filter cutoff frequency in Hz. Removes high-frequency noise before downsampling. Should be below target_fs/2 (Nyquist).

  • lambda_smooth (float) – Smoothness regularization weight. Higher values produce smoother A0(t) estimates. Tune via cross-validation if needed.

  • knots_per_second (float) – Number of B-spline knots per second. Controls temporal resolution of A0(t) model. Typical values: 0.5-2.0.

  • initial_theta (Union[float, str, None]) –

    Initial guess for camera polar angle. If None, uses pi/2 (horizontal) as starting point.

    • Plain number: assumed to be radians (with warning)

    • String: e.g., “20 degrees”, “0.349 radians”

    • Quantity: e.g., 20 * ureg.degree

  • initial_phi (Union[float, str, None]) –

    Initial guess for camera azimuthal angle. If None, uses 0 (camera on x-axis) as starting point.

    • Plain number: assumed to be radians (with warning)

    • String: e.g., “-90 degrees”, “-1.57 radians”

    • Quantity: e.g., -90 * ureg.degree

  • verbose (bool) – Print optimization progress and fit statistics.

Returns:

calibration – Fitted calibration object containing camera geometry (theta, phi), spline coefficients for A0(t), and fit quality metrics.

Return type:

ForeshorteningCalibration

Raises:

ValueError – If specified eye doesn’t exist or lacks gaze/pupil data, if the experimental setup is not set or lacks required information, if lowpass_freq is not below the Nyquist frequency or if fewer than 100 valid samples are available.

Notes

The model is:

A_measured(x,y,t) = A0(t) * cos(alpha(x,y; theta, phi))

where:

  • A0(t) = sum_k a_k * B_k(t) is modeled with B-splines

  • cos(alpha) is the foreshortening factor depending on viewing angle

  • theta, phi parameterize camera position in spherical coordinates

The optimization minimizes:

sum_i (A_i - A_pred_i)^2 + lambda_smooth * sum_k (a_{k+1} - a_k)^2

Examples

>>> import pypillometry as pp
>>> data = pp.EyeData.from_eyelink('recording.edf')
>>>
>>> # Set experimental setup
>>> data.set_experimental_setup(
...     screen_resolution=(1920, 1080),
...     physical_screen_size=("52 cm", "29 cm"),
...     eye_to_screen_center="65 cm",
...     camera_offset=("0 cm", "-30 cm", "0 cm"),
... )
>>>
>>> # Fit on calibration period (first 2 minutes)
>>> cal_intervals = pp.Intervals([(0, 120000)], units="ms")
>>> calib = data.fit_foreshortening(
...     eye='left',
...     intervals=cal_intervals
... )
>>>
>>> # Or provide r and d explicitly
>>> calib = data.fit_foreshortening(
...     eye='left',
...     r="60 cm",
...     d="70 cm",
...     intervals=cal_intervals
... )
>>>
>>> # Inspect fit quality
>>> print(calib)
>>> print(f"R² = {calib.fit_metrics['r2']:.3f}")
>>>
>>> # Compute correction for all data
>>> correction_factor = calib.get_correction_factor(
...     data['left', 'x'],
...     data['left', 'y']
... )
>>> corrected_pupil = data['left', 'pupil'] * correction_factor

See also

ForeshorteningCalibration

Container for fitted parameters

correct_pupil_foreshortening

Simple foreshortening correction method

get_pupildata(eye=None)[source]

Return the pupil data as a PupilData object.

Parameters:

eye (str, optional) – Which eye to return data for. If None, the dataset must contain only one eye, which is then used.

Returns:

A PupilData object containing the pupil data of eye (as "<eye>_pupil"), the time vector and the events.

Return type:

PupilData

Raises:

ValueError – if eye is None and there is more than one eye, or if there is no data for eye

property plot

Plotting functions for this object (a EyePlotter).

summary()[source]

Return a summary of the dataset as a dictionary.

Returns:

A dictionary summarizing the dataset.

Return type:

dict

PupilData

class pypillometry.PupilData(time=None, left_pupil=None, right_pupil=None, event_onsets=None, event_labels=None, sampling_rate=None, name=None, fill_time_discontinuities=True, keep_orig=False, info=None, inplace=None)[source]

Class representing pupillometric data.

The class is a subclass of GenericEyeData and inherits all its methods.

If eye-tracking data is available in addition to pupillometry, use the EyeData class.

Properties such as eyes and variables are inherited from GenericEyeData.

Parameters:
  • time (ndarray) – timing array (in ms) or None, in which case the time-array goes from [0,maxT] using sampling_rate

  • left_pupil (ndarray) – data from left eye (at least one of the eyes must be provided)

  • right_pupil (ndarray) – data from right eye (at least one of the eyes must be provided)

  • event_onsets (ndarray) – time-onsets of any events in the data (in ms, matched in time vector)

  • event_labels (ndarray) – for each event in event_onsets, provide a label

  • sampling_rate (float) – sampling-rate of the signal in Hz; if None, it is estimated from the median difference in time (either time or sampling_rate must be provided)

  • name (str) – name of the dataset or None (in which case a random string is selected)

  • fill_time_discontinuities (bool) – sometimes, when the eyetracker loses signal, no entry in the EDF is made; when this option is True, such entries will be made and the signal set to 0 there (or do it later using fill_time_discontinuities())

  • keep_orig (bool) – keep a copy of the original dataset? If True, a copy of the object as initiated in the constructor is stored in member original

  • info (dict) – optional dictionary with additional information about the dataset (stored in member info)

  • inplace (Optional[bool]) – default for methods called with inplace=None: if True, they modify the object in place; if False, they return a modified copy; if None (default), use the package-level setting (see set_default_inplace(), initially True). The method-level inplace argument overrides this.

Attributes:
blinks

Return blinks (intervals) for all eyes.

events

Events (onsets in ms) as an Events object.

eyes

Return a list of available eyes in the dataset.

plot

Plotting functions for this object (a PupilPlotter).

variables

Return a list of available variables in the dataset.

Methods

add_to_history(event)

Add event to history.

blink_stats([eyes, units])

Return statistics on blink durations.

blinks_merge_close([eyes, variables, ...])

Merge blinks that are close together.

copy([new_name])

Make and return a deep-copy of the eyedata object.

downsample(fsd[, dsfac, inplace])

Simple downsampling scheme using mean within the downsampling window.

drop_data([eyes, variables])

Drop specified eyes and/or variables from the data and return a new object.

drop_original([inplace])

Drop original dataset from record (e.g., to save space).

fill_time_discontinuities([yval, print_info])

Find gaps in the time-vector and fill them in (in-place).

from_eyelink(fname[, return_edf_obj, ...])

Reads an eyedata object from an Eyelink file.

from_file(fname)

Reads a GenericEyeData object from a pickle-file.

get_blinks([eyes, variables, units])

Get blinks as Intervals object or dict of Intervals.

get_duration([units])

Return duration of the dataset in units specified.

get_events([units])

Get events as an Events object.

get_interpolated_blinks([eyes, variables, units])

Get interpolated blinks as Intervals object or dict of Intervals.

get_intervals(event_select[, interval, ...])

Return an Intervals object containing intervals relative to event-onsets.

get_segments(intervals, variable[, name])

Extract segments from data using intervals.

get_size()

Return the size of the object in bytes.

interpolate_intervals(intervals[, eyes, ...])

Interpolate data within specified intervals.

mask_as_intervals([eyes, variables, units, ...])

Convert masks to Intervals objects.

mask_intervals(intervals[, eyes, variables, ...])

Apply Intervals as masks to selected data.

merge_eyes([eyes, variables, method, ...])

Merge data from both eyes into a single variable.

merge_masks([inplace])

Merge masks of all variables into a single joint mask.

nblinks([eyes, variables])

Return number of detected blinks.

nevents()

Return number of events in data.

print_history()

Pretty-print the history of the current dataset (which manipulations where done on it).

pupil_blinks_detect([eyes, min_duration, ...])

Detect blinks in the pupillary signal using several strategies.

pupil_blinks_interpolate([eyes, store_as, ...])

Interpolating blinks in the pupillary signal.

pupil_estimate_baseline([eyes, variable, ...])

Apply one of the baseline-estimation methods.

pupil_estimate_response([eyes, npar, tmax, ...])

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

pupil_lowpass_filter(cutoff[, order, eyes, ...])

Lowpass-filter pupil signal using a Butterworth-filter.

pupil_merge_eyes([method, lowpass_cutoff, ...])

Merge pupil data from both eyes into a single "merged" variable.

pupil_smooth_window([eyes, window, winsize, ...])

Apply smoothing of the signal using a moving window.

reset_time([t0, inplace])

Resets time so that time t0 becomes time zero.

scale([variables, mean, sd, eyes, inplace])

Scale the signal by subtracting mean and dividing by sd.

set_blinks(intervals[, eyes, variables, ...])

Set blinks for specified eyes and variables (in-place).

set_event_onsets(event_onsets, event_labels)

Set onsets of events in the data (in-place).

set_events(events[, inplace])

Replace event onsets and labels from an Events object.

stat_per_event([intervals, interval, ...])

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

sub_slice([start, end, units, inplace])

Return a shortened version of the current object.

summary()

Return a summary of the dataset as a dictionary.

unscale([variables, mean, sd, eyes, inplace])

Scale back to original values using either values provided as arguments or the values stored in params["scale"] by scale().

write_file(fname)

Save to file (using pickle).

property plot

Plotting functions for this object (a PupilPlotter).

Detect blinks in the pupillary signal using several strategies. First, blinks are detected as consecutive sequence of blink_val (f.eks., 0 or NaN). Second, blinks are defined as everything between two crossings of the velocity profile (from negative to positive).

Detected blinks are always stored in the object (retrieve them with get_blinks()). When apply_mask=True, the blinks are also applied as masks to the data. When apply_mask=False (default), the detected blinks are returned as Intervals objects.

Finally, detected blinks have to be at least min_duration ms.

Parameters:
  • eyes (list) – list of eyes to process; if empty, all available eyes are processed

  • min_duration (float) – minimum duration in ms for a sequence of missing numbers to be treated as blink

  • blink_val (float) – “missing value” code for the “zero” strategy. Missing samples (NaN) are always detected; samples equal to blink_val (default 0) are detected in addition. Use np.nan to detect only NaN (e.g., for baseline-corrected data where 0 is a valid value). The “zero” strategy always uses the raw data, so regions masked for other reasons are not detected as blinks.

  • winsize (float) – window-size for Savitzky-Golay velocity estimation in ms

  • vel_onset (float or str) –

    velocity threshold to detect blink onset (negative value).

    • If float: threshold in pupil-units per millisecond (e.g., -5.0)

    • If str: percentile of velocity distribution (e.g., “5%” for bottom 5%)

  • vel_offset (float or str) –

    velocity threshold to detect blink offset (positive value).

    • If float: threshold in pupil-units per millisecond (e.g., 5.0)

    • If str: percentile of velocity distribution (e.g., “95%” for top 5%)

  • vel_onset_min_duration (float) – minimum duration in ms that velocity must exceed threshold to detect as onset (to avoid noise-induced false detections)

  • vel_offset_min_duration (float) – minimum duration in ms that velocity must exceed threshold to detect as offset (to avoid noise-induced false detections)

  • strategies (list) – list of strategies to use; so far, use a list containing any combination of “zero” and “velocity”

  • apply_mask (bool) – if True, apply detected blinks as masks to the data and return the object if False (default), return detected blinks as Intervals (or dict of Intervals)

  • ignore_existing_mask (bool) – if True, use raw data ignoring existing masks if False (default), only detect blinks in non-masked data (already masked regions are skipped)

  • inplace (bool or None) – if True, make change in-place and return the object if False, make and return copy before making changes if None, use the object-level setting

Returns:

If apply_mask=True: returns the object (for chaining) If apply_mask=False and single eye: returns Intervals object If apply_mask=False and multiple eyes: returns dict of Intervals objects (keys like "left_pupil")

Return type:

PupilData or Intervals or dict

Interpolating blinks in the pupillary signal.

Implements the blink-interpolation method by Mahot (2013).

Mahot, 2013: https://figshare.com/articles/A_simple_way_to_reconstruct_pupil_size_during_eye_blinks/688001.

The blinks to interpolate are taken from the blinks stored in the object, so blinks have to be detected first (e.g., using pupil_blinks_detect()). The on- and offsets of each blink are refined using the velocity profile before interpolating. Interpolated samples remain masked; the interpolated blinks can be retrieved with get_interpolated_blinks().

This procedure relies heavily on eye-balling (reconstructing visually convincing signal), so it can help to inspect the result visually (e.g., using plot_blinks()) to set good parameter values for winsize, vel_onset, vel_offset and margin (see paper linked above).

Parameters:
  • eyes (str | list) – str or list of eyes to process; if empty, all available eyes are processed

  • store_as (str) – how to store the interpolated data; either “pupil” (default) which replaces the original pupil data or a string that will be used as the new variable name in the data (e.g., “pupilinterp”)

  • method (str) – method to use; so far, only “mahot” is implemented

  • winsize (float) – size of the Savitzky-Golay window in ms

  • vel_onset (float or str) –

    velocity threshold to detect blink onset (negative value).

    • If float: threshold in pupil-units per millisecond (e.g., -5.0)

    • If str: percentile of velocity distribution (e.g., “5%” for bottom 5%)

  • vel_offset (float or str) –

    velocity threshold to detect blink offset (positive value).

    • If float: threshold in pupil-units per millisecond (e.g., 5.0)

    • If str: percentile of velocity distribution (e.g., “95%” for top 5%)

  • margin (Tuple[float, float]) – margin that is subtracted/added to onset and offset (in ms)

  • blinkwindow (float) – how much time before and after each blink to include (in ms)

  • interp_type (str) – type of interpolation accepted by scipy.interpolate.interp1d()

  • inplace (bool or None) – if True, make change in-place and return the object if False, make and return copy before making changes if None, use the object-level setting

Returns:

the object with the interpolated pupil data

Return type:

PupilData

pupil_estimate_baseline(eyes=[], variable='pupil', method='envelope_iter_bspline_2', inplace=None, **kwargs)[source]

Apply one of the baseline-estimation methods.

Parameters:
  • eyes (list or str) – str or list of eyes to process; if empty, all available eyes are processed

  • variable (str) – default is to use the “pupil” but it could be used to process, e.g., interpolated pupil data stored in a different variables, e.g., “pupilinterp”

  • method (str) –

  • inplace (bool or None) – if True, make change in-place and return the object if False, make and return copy before making changes if None, use the object-level setting

  • **kwargs (dict) – named arguments passed to the low-level function in pypillometry.signal.baseline.

Returns:

object with baseline estimated (stored in data[eye, "baseline"])

Return type:

PupilData

Raises:

ValueError – if method is unknown

pupil_estimate_response(eyes=[], npar='free', tmax='free', verbose=50, bounds={'npar': (1, 20), 'tmax': (100, 2000)}, inplace=None)[source]

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

If a baseline has been estimated (see pupil_estimate_baseline()), it is subtracted from the pupil signal before estimating the response; otherwise, a baseline of zero is used.

Parameters:
  • eyes (list or str) – str or list of eyes to process; if empty, all available eyes are processed

  • npar (str | float) – npar-parameter for the canonical response-function or “free”; in case of “free”, the function optimizes for this parameter

  • tmax (str | float) – tmax-parameter for the canonical response-function or “free”; in case of “free”, the function optimizes for this parameter

  • verbose (int) – verbosity level, passed on to pupil_response()

  • bounds (dict) – in case that one or both parameters are estimated, give the lower and upper bounds for the parameters

  • inplace (bool or None) – if True, make change in-place and return the object if False, make and return copy before making changes if None, use the object-level setting

Returns:

the object with the estimated response

Return type:

PupilData

Notes

The predicted response is stored in data[eye, "response"]; the estimated parameters (npar, tmax, the coefficients coef and the bounds) are stored in params["response"][eye].

pupil_lowpass_filter(cutoff, order=2, eyes=[], inplace=None)[source]

Lowpass-filter pupil signal using a Butterworth-filter.

Uses an iterative approach to handle NaN/masked values properly, preventing NaN propagation through the filter (see lowpass_filter_iterative()). The filtered signal replaces the pupil data; the mask is preserved.

Parameters:
  • cutoff (float) – lowpass-filter cutoff frequency in Hz

  • order (int) – filter order

  • eyes (list) – list of eyes to filter; if empty, all available eyes are filtered

  • inplace (bool or None) – if True, make change in-place and return the object if False, make and return copy before making changes if None, use the object-level setting

Returns:

the object with the filtered pupil data

Return type:

PupilData

pupil_merge_eyes(method='local_offset', lowpass_cutoff=0.2, max_iter=10, keep_eyes=True, inplace=None)[source]

Merge pupil data from both eyes into a single “merged” variable.

This method combines left and right pupil signals, handling missing data (masked values) intelligently. Where both eyes are valid, the signals are averaged to reduce noise. Where only one eye is valid, that eye’s data is used (with offset correction if applicable).

Parameters:
  • method (str) –

    Method for merging the two eyes. Options:

    • ”local_offset” (default): Compute a slowly-varying offset between eyes using lowpass filtering. This handles drift over the session. The right eye is shifted to match the left eye’s level before merging.

    • ”offset”: Use a single global offset (mean difference) computed over the entire signal where both eyes are valid.

    • ”both_available”: Only use data where both eyes are valid (take mean). Timepoints where only one eye is valid remain masked.

    # TODO: Implement “signal_quality” method that weights eyes by their # local signal quality (SNR), giving more weight to the cleaner eye.

  • lowpass_cutoff (float) – Cutoff frequency (Hz) for the lowpass filter used in “local_offset” method. Lower values produce a more stable offset that only tracks very slow drift. Default is 0.2 Hz (~5 second time constant).

  • max_iter (int) – Maximum iterations for iterative lowpass filtering in “local_offset” method. Default is 10.

  • keep_eyes (bool) – If True (default), keep the original left/right pupil data. If False, remove the original eye data after merging.

  • inplace (bool | None) – If True, modify in-place. If False, return a copy. If None, use the object’s default setting.

Returns:

The object with merged pupil data stored as “merged_pupil”.

Return type:

PupilData

Raises:

ValueError – If only one eye is available (nothing to merge). If an unknown method is specified.

Notes

The merged signal is stored as “merged_pupil” and can be accessed via data[“merged”, “pupil”] or data[“merged_pupil”].

The mask for the merged signal reflects which timepoints have valid data: - For “local_offset” and “offset”: masked only where BOTH eyes are masked - For “both_available”: masked where EITHER eye is masked

The “local_offset” method is recommended for most use cases as it: 1. Uses all available data (doesn’t discard single-eye timepoints) 2. Handles session-long drift in the inter-ocular difference 3. Produces smooth transitions at boundaries between single/both-eye regions

Examples

>>> # Default: local offset correction
>>> data.pupil_merge_eyes()
>>> merged = data["merged", "pupil"]
>>> # Use global offset (simpler, assumes no drift)
>>> data.pupil_merge_eyes(method="offset")
>>> # Only use timepoints where both eyes are valid
>>> data.pupil_merge_eyes(method="both_available")
>>> # Remove original eye data after merging
>>> data.pupil_merge_eyes(keep_eyes=False)

See also

merge_eyes

Generic merge method in GenericEyeData (masks if either eye invalid)

pypillometry.signal.pupil.pupil_eye_offset

Compute local offset between eyes

pupil_smooth_window(eyes=[], window='hanning', winsize=11, inplace=None)[source]

Apply smoothing of the signal using a moving window. See smooth_window(). The smoothed signal replaces the pupil data; the mask is preserved.

Parameters:
  • eyes (list) – list of eyes to smooth; if empty, all available eyes are smoothed

  • window (str) – (the type of window from ‘flat’, ‘hanning’, ‘hamming’, ‘bartlett’, ‘blackman’); flat window will produce a moving average smoothing.

  • winsize (float) – the length of the window in ms

  • inplace (bool or None) – if True, make change in-place and return the object if False, make and return copy before making changes if None, use the object-level setting

Returns:

the object with the smoothed pupil data

Return type:

PupilData

summary()[source]

Return a summary of the dataset as a dictionary.

Returns:

dictionary containing description of dataset

Return type:

dict

GazeData

class pypillometry.GazeData(time=None, left_x=None, left_y=None, right_x=None, right_y=None, event_onsets=None, event_labels=None, sampling_rate=None, experimental_setup=None, name=None, calibration=None, fill_time_discontinuities=True, keep_orig=False, info=None, inplace=None)[source]

Class representing Eye-Tracking data (x,y) from one or two eyes.

If you also want to store pupil-size, use the EyeData class. If you only want to store pupil-size, use the PupilData class.

Properties such as eyes and variables are inherited from GenericEyeData.

Parameters:
  • time (ndarray) – timing array (in ms) or None, in which case the time-array goes from [0,maxT] using sampling_rate

  • left_x (ndarray) – data from left eye (at least one of the eyes must be provided, both x and y)

  • left_y (ndarray) – data from left eye (at least one of the eyes must be provided, both x and y)

  • right_x (ndarray) – data from right eye (at least one of the eyes must be provided, both x and y)

  • right_y (ndarray) – data from right eye (at least one of the eyes must be provided, both x and y)

  • event_onsets (ndarray) – time-onsets of any events in the data (in ms, matched in time vector)

  • event_labels (ndarray) – for each event in event_onsets, provide a label

  • sampling_rate (float) – sampling-rate of the signal in Hz; if None, it is estimated from the median difference in time (either time or sampling_rate must be provided)

  • experimental_setup (Optional[ExperimentalSetup]) – Geometric model of the experimental setup including screen geometry, eye position, camera position, and screen orientation.

  • name (str) – name of the dataset or None (in which case a random string is selected)

  • calibration (Optional[Dict[str, SpatialCalibration]]) – Dictionary of SpatialCalibration objects, one per eye (keys: ‘left’, ‘right’)

  • fill_time_discontinuities (bool) – sometimes, when the eyetracker loses signal, no entry in the EDF is made; when this option is True, such entries will be made and the signal set to 0 there (or do it later using fill_time_discontinuities())

  • keep_orig (bool) – keep a copy of the original dataset? If True, a copy of the object as initiated in the constructor is stored in member original

  • info (dict) – optional dictionary with additional information about the dataset (stored in member info)

  • inplace (Optional[bool]) – default for methods called with inplace=None: if True, they modify the object in place; if False, they return a modified copy; if None (default), use the package-level setting (see set_default_inplace(), initially True). The method-level inplace argument overrides this.

Attributes:
blinks

Return blinks (intervals) for all eyes.

events

Events (onsets in ms) as an Events object.

eyes

Return a list of available eyes in the dataset.

plot

Plotting functions for this object (a GazePlotter).

variables

Return a list of available variables in the dataset.

Methods

add_to_history(event)

Add event to history.

blink_stats([eyes, units])

Return statistics on blink durations.

blinks_merge_close([eyes, variables, ...])

Merge blinks that are close together.

copy([new_name])

Make and return a deep-copy of the eyedata object.

downsample(fsd[, dsfac, inplace])

Simple downsampling scheme using mean within the downsampling window.

drop_data([eyes, variables])

Drop specified eyes and/or variables from the data and return a new object.

drop_original([inplace])

Drop original dataset from record (e.g., to save space).

fill_time_discontinuities([yval, print_info])

Find gaps in the time-vector and fill them in (in-place).

from_eyelink(fname[, return_edf_obj, ...])

Reads an eyedata object from an Eyelink file.

from_file(fname)

Reads a GenericEyeData object from a pickle-file.

get_blinks([eyes, variables, units])

Get blinks as Intervals object or dict of Intervals.

get_duration([units])

Return duration of the dataset in units specified.

get_events([units])

Get events as an Events object.

get_interpolated_blinks([eyes, variables, units])

Get interpolated blinks as Intervals object or dict of Intervals.

get_intervals(event_select[, interval, ...])

Return an Intervals object containing intervals relative to event-onsets.

get_segments(intervals, variable[, name])

Extract segments from data using intervals.

get_size()

Return the size of the object in bytes.

interpolate_intervals(intervals[, eyes, ...])

Interpolate data within specified intervals.

mask_as_intervals([eyes, variables, units, ...])

Convert masks to Intervals objects.

mask_eye_divergences([threshold, thr_type, ...])

Calculate Euclidean distance between left and right eye coordinates and detect divergences.

mask_intervals(intervals[, eyes, variables, ...])

Apply Intervals as masks to selected data.

mask_offscreen_coords([eyes, apply_mask, ...])

Detect and mask gaze coordinates that fall outside the screen boundaries.

merge_eyes([eyes, variables, method, ...])

Merge data from both eyes into a single variable.

merge_masks([inplace])

Merge masks of all variables into a single joint mask.

nblinks([eyes, variables])

Return number of detected blinks.

nevents()

Return number of events in data.

print_history()

Pretty-print the history of the current dataset (which manipulations where done on it).

reset_time([t0, inplace])

Resets time so that time t0 becomes time zero.

scale([variables, mean, sd, eyes, inplace])

Scale the signal by subtracting mean and dividing by sd.

set_blinks(intervals[, eyes, variables, ...])

Set blinks for specified eyes and variables (in-place).

set_event_onsets(event_onsets, event_labels)

Set onsets of events in the data (in-place).

set_events(events[, inplace])

Replace event onsets and labels from an Events object.

set_experimental_setup(**kwargs)

Set or update the experimental setup geometry (in-place).

stat_per_event([intervals, interval, ...])

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

sub_slice([start, end, units, inplace])

Return a shortened version of the current object.

summary()

Return a summary of the dataset as a dictionary.

unscale([variables, mean, sd, eyes, inplace])

Scale back to original values using either values provided as arguments or the values stored in params["scale"] by scale().

write_file(fname)

Save to file (using pickle).

mask_eye_divergences(threshold=0.99, thr_type='percentile', store_as=None, apply_mask=True, ignore_existing_mask=True, inplace=None)[source]

Calculate Euclidean distance between left and right eye coordinates and detect divergences.

This method computes the distance between corresponding (x,y) coordinates in the left and right eyes. Points where the distance exceeds a threshold are detected as divergences. When apply_mask=True, these points are masked. When apply_mask=False, the divergences are returned as Intervals objects.

Parameters:
  • threshold (float) – If thr_type is “percentile”: percentile value (0-1) for threshold calculation. If thr_type is “pixel”: maximum allowed distance in pixels.

  • thr_type (str) –

    Type of threshold to apply:

    • ”percentile”: threshold is calculated as the given percentile of the distance distribution

    • ”pixel”: threshold is the maximum allowed distance in pixels

  • store_as (str | None) – Variable name to store the distance timeseries. If None, distance is not stored.

  • apply_mask (bool) – If True, apply detected divergences as masks to the data and return self. If False, return detected divergences as an Intervals object.

  • ignore_existing_mask (bool) – If True (default), check all data points including those already masked (e.g., from blinks). If False, only check non-masked data points for divergences.

  • inplace (bool or None) – If True, make change in-place and return the object. If False, make and return copy before making changes. If None, use the object-level setting.

Returns:

If apply_mask=True: returns the object for chaining. If apply_mask=False: returns Intervals object containing detected divergence intervals.

Return type:

GazeData or Intervals

Raises:

ValueError – If both left and right eye data are not available. If thr_type is not “percentile” or “pixel”.

Examples

>>> # Mask divergences at 99th percentile
>>> gaze_data = gaze_data.mask_eye_divergences(threshold=0.99, thr_type="percentile")
>>> # Detect divergences without masking
>>> divergences = gaze_data.mask_eye_divergences(threshold=0.99, apply_mask=False)
>>> # Mask divergences beyond 100 pixels
>>> gaze_data = gaze_data.mask_eye_divergences(threshold=100, thr_type="pixel")
>>> # Only check non-masked data points
>>> gaze_data = gaze_data.mask_eye_divergences(ignore_existing_mask=False)
mask_offscreen_coords(eyes=[], apply_mask=True, ignore_existing_mask=False, inplace=None)[source]

Detect and mask gaze coordinates that fall outside the screen boundaries.

This method identifies points where the (x,y) coordinates fall outside the defined screen limits. When apply_mask=True, these points are masked. When apply_mask=False, the offscreen periods are returned as Intervals objects.

Parameters:
  • eyes (str | list) – Eye(s) to check for offscreen coordinates. If empty, checks all available eyes. Can be a single eye name (e.g., “left”) or a list (e.g., [“left”, “right”]).

  • apply_mask (bool) – If True, apply detected offscreen periods as masks to the data and return self. If False, return detected offscreen periods as dict of Intervals objects.

  • ignore_existing_mask (bool) – If False (default), only check non-masked data points for offscreen coordinates. If True, check all data points including those already masked (e.g., from blinks).

  • inplace (bool or None) – If True, make change in-place and return the object. If False, make and return copy before making changes. If None, use the object-level setting.

Returns:

If apply_mask=True: returns self for chaining. If apply_mask=False: returns dict of Intervals objects (one per eye) containing detected offscreen intervals.

Return type:

GazeData or dict of Intervals

Examples

>>> # Mask offscreen coordinates for all eyes
>>> gaze_data = gaze_data.mask_offscreen_coords()
>>> # Detect offscreen periods without masking
>>> offscreen = gaze_data.mask_offscreen_coords(apply_mask=False)
>>> # Mask offscreen coordinates for left eye only
>>> gaze_data = gaze_data.mask_offscreen_coords(eyes='left')
>>> # Check all data including already masked points (e.g., during blinks)
>>> gaze_data = gaze_data.mask_offscreen_coords(ignore_existing_mask=True)
property plot

Plotting functions for this object (a GazePlotter).

set_experimental_setup(**kwargs)[source]

Set or update the experimental setup geometry (in-place).

Creates a new ExperimentalSetup or updates the existing one with the provided parameters (parameters that are not given are taken from the existing setup). All parameters are passed through to the ExperimentalSetup constructor.

Parameters:

**kwargs (dict) –

Any parameters accepted by ExperimentalSetup:

  • screen_resolution: tuple (width, height) in pixels

  • physical_screen_size: tuple (width, height) with units

  • eye_to_screen_center: distance from the eye to the screen center

  • screen_offset: tuple (delta_x, delta_y) - offset of screen center from eye

  • screen_pitch: tilt angle (alpha_tilt)

  • screen_yaw: tilt angle (beta_tilt)

  • camera_offset: tuple (x, y, z) in eye-centric frame

  • camera_spherical: tuple (theta, phi, r)

  • ipd: inter-pupillary distance

Examples

>>> data.set_experimental_setup(
...     screen_resolution=(1920, 1080),
...     physical_screen_size=("52 cm", "29 cm"),
...     eye_to_screen_center="65 cm",
... )
summary()[source]

Return a summary of the dataset as a dictionary.

Returns:

dictionary containing description of dataset

Return type:

dict

Plotting

class pypillometry.EyePlotter(obj)[source]

Class for plotting combined gaze and pupil data. It provides all methods of GazePlotter and PupilPlotter and additional plots that combine gaze and pupil data.

It is usually not created directly; instead, it is available as the plot attribute of an EyeData object, e.g. d.plot.plot_pupil_foreshortening_error_surface().

Parameters:

obj (GenericEyeData) – the data object to plot (stored as obj)

Methods

plot_blinks([eyes, variables, pdf_file, ...])

Plot detected blinks in separate subplots.

plot_calibration([eyes, show_surface, ...])

Plot spatial calibration data for one or more eyes in subplots.

plot_experimental_setup([theta, phi, ...])

Plot visualization of eye-tracking experimental setup geometry.

plot_heatmap([plot_range, eyes, ...])

Plot EyeData as a heatmap.

plot_intervals(intervals[, eyes, variables, ...])

Plotting data around intervals.

plot_masked([eyes, variables, units, merge, ...])

Plot masked intervals for specified eyes and variables.

plot_pupil_foreshortening_error_surface([...])

Plot a heatmap showing average pupil size across x/y gaze positions.

plot_scanpath([plot_range, eyes, ...])

Plot EyeData as a scanpath.

plot_timeseries([plot_range, variables, ...])

Plot a part of the EyeData.

plot_timeseries_segments([pdf_file, interv, ...])

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

pupil_plot([eyes, plot_range, show_events, ...])

Make a plot of the pupil data using matplotlib.

pupil_plot_segments([pdf_file, interv, ...])

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

plot_experimental_setup(theta=None, phi=None, calibration=None, show_gaze_samples=True, n_gaze_samples=9, ax=None, viewing_angle=None, projection='2d')[source]

Plot visualization of eye-tracking experimental setup geometry.

Shows the spatial relationship between eye, camera, and screen using the experimental parameters stored in the EyeData object. Delegates to ExperimentalSetup.plot().

Parameters:
  • theta (Optional[float]) – Camera polar angle; a float is interpreted as radians, a string can carry units (e.g., “20 deg”). If None, uses calibration’s theta (if calibration is given), else setup’s theta.

  • phi (Optional[float]) – Camera azimuthal angle; a float is interpreted as radians, a string can carry units (e.g., “-90 deg”). If None, uses calibration’s phi (if calibration is given), else setup’s phi.

  • calibration (ForeshorteningCalibration, optional) – Fitted calibration object containing theta and phi.

  • show_gaze_samples (bool) – Show sample gaze vectors to screen positions

  • n_gaze_samples (int) – Number of sample gaze positions

  • ax (Optional[Axes]) – Existing axis to plot on (only for ‘3d’ projection)

  • viewing_angle (tuple) – Viewing angle for 3D projection (elev, azim) or (elev, azim, roll). Each element is parsed like theta, i.e. use strings with units (e.g., ("30 deg", "-60 deg")); plain numbers are interpreted as radians.

  • projection (str) – ‘2d’ for three orthogonal views, ‘3d’ for interactive 3D view

Return type:

tuple

Returns:

  • fig (matplotlib Figure)

  • ax (matplotlib axis or array of axes)

Raises:

ValueError – if the data object has no experimental_setup

Examples

>>> # Use camera geometry from setup
>>> data.plot.plot_experimental_setup()
>>>
>>> # Use fitted angles from calibration
>>> calib = data.fit_foreshortening(eye='left')
>>> data.plot.plot_experimental_setup(calibration=calib)
>>>
>>> # Override angles
>>> data.plot.plot_experimental_setup(theta=np.radians(20), phi=np.radians(-90))
plot_pupil_foreshortening_error_surface(eyes=[], plot_range=(-inf, inf), units='sec', show_screen=True, cmap='jet', gridsize=30, vmin=None, vmax=None, min_samples=None, smooth=None, limits=None)[source]

Plot a heatmap showing average pupil size across x/y gaze positions.

This visualizes how pupil size varies across different gaze positions, which can reveal foreshortening effects (pupils appear smaller when looking away from the camera) or other spatial artifacts. Each eye is plotted in a separate subplot.

Parameters:
  • eyes (Union[str, List[str]]) – Which eye(s) to plot: “left”, “right”, “average”, or a list of these. Default is [] which plots all available eyes.

  • plot_range (tuple) – The time range to include in the analysis. Default is (-np.inf, +np.inf), i.e. all data.

  • units (str) – Time units for plot_range. Default is “sec”.

  • show_screen (bool) – Whether to plot the screen limits. Default is True.

  • cmap (str) – Colormap to use. Default is “jet”.

  • gridsize (int) – Number of bins in each direction. Default is 30.

  • vmin (Optional[float]) – Minimum value for color scale. If None, uses data minimum.

  • vmax (Optional[float]) – Maximum value for color scale. If None, uses data maximum.

  • min_samples (Optional[int]) – Minimum number of samples required in a bin to display it. Bins with fewer samples will not be shown. If None (default), automatically calculates a threshold at the 10th percentile of bin counts, effectively displaying only the top 90% of bins by sample count.

  • smooth (Optional[float]) – If provided, applies Gaussian smoothing to the binned surface. The value is the sigma of the Gaussian kernel in bin units (e.g., smooth=1 applies minimal smoothing with a 1-bin sigma, smooth=2 applies more smoothing). When smooth is provided, uses a rectangular grid instead of hexbin.

  • limits (Optional[Tuple[float, float, float, float]]) – Axis limits as (xmin, xmax, ymin, ymax). If not provided, uses screen limits when available (and data falls within), otherwise uses data extent.

Returns:

Creates a matplotlib figure with the heatmap(s)

Return type:

None

Examples

Plot foreshortening effect for left eye:

>>> data.plot.plot_pupil_foreshortening_error_surface('left')

Plot for multiple eyes:

>>> data.plot.plot_pupil_foreshortening_error_surface(['left', 'right'])

Plot all available eyes with custom color range:

>>> data.plot.plot_pupil_foreshortening_error_surface(vmin=3, vmax=5)

Plot with a specific minimum sample threshold:

>>> data.plot.plot_pupil_foreshortening_error_surface(min_samples=50)

Plot with Gaussian smoothing:

>>> data.plot.plot_pupil_foreshortening_error_surface(smooth=1.5)

Plot with custom limits:

>>> data.plot.plot_pupil_foreshortening_error_surface(limits=(0, 1920, 0, 1080))
class pypillometry.PupilPlotter(obj)[source]

Class for plotting pupil data. The class is initialized with a GenericEyeData object and provides methods to plot the data in various ways.

It is usually not created directly; instead, it is available as the plot attribute of a PupilData object, e.g. d.plot.pupil_plot().

Parameters:

obj (GenericEyeData) – the data object to plot (stored as obj)

Methods

plot_blinks([eyes, variables, pdf_file, ...])

Plot detected blinks in separate subplots.

plot_intervals(intervals[, eyes, variables, ...])

Plotting data around intervals.

plot_masked([eyes, variables, units, merge, ...])

Plot masked intervals for specified eyes and variables.

plot_timeseries([plot_range, variables, ...])

Plot a part of the EyeData.

plot_timeseries_segments([pdf_file, interv, ...])

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

pupil_plot([eyes, plot_range, show_events, ...])

Make a plot of the pupil data using matplotlib.

pupil_plot_segments([pdf_file, interv, ...])

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

Plot detected blinks in separate subplots.

Parameters:
  • eyes (str | list) – Eyes to plot

  • variables (str | list) – Variables to plot

  • pdf_file (str | None) – Save to PDF file if provided

  • nrow (int) – Number of rows per figure

  • ncol (int) – Number of columns per figure

  • figsize (tuple) – Figure size (width, height)

  • pre_blink (float) – Time before blink to include (in ms)

  • post_blink (float) – Time after blink to include (in ms)

  • units (str) – Display units for time axis

  • show_index (bool) – Show blink index numbers

Returns:

List of matplotlib Figure objects

Return type:

list

pupil_plot(eyes=[], plot_range=(-inf, inf), show_events=True, show_blinks=True, units='sec', label_prefix='', style=None)[source]

Make a plot of the pupil data using matplotlib.

Has pupil-specific options which makes it different from plot_timeseries(). All eyes are plotted into the current axes.

Parameters:
  • eyes (str | list) – eye(s) to plot; if empty, all eyes with pupil data are plotted

  • plot_range (Tuple[float, float]) – plot from start to end (in units of units)

  • show_events (bool) – plot events as vertical lines with labels

  • show_blinks (bool) – highlight masked regions of the pupil data (e.g., detected blinks) with a red background

  • units (str) – one of “sec”=seconds (default), “ms”=millisec, “min”=minutes, “h”=hours

  • label_prefix (str) – Prefix to add to labels in the legend. Useful for overlaying multiple datasets. Default is “” (no prefix).

  • style (dict) –

    Styling for plotted lines. Can be:

    • Single dict: Applied to all eyes with automatic differentiation (e.g., {‘color’: ‘red’})

    • Dict of dicts: Per-eye styling (e.g., {‘left’: {‘linestyle’: ‘-‘}, ‘right’: {‘linestyle’: ‘–‘}})

    Default is None (uses matplotlib defaults with automatic per-eye colors and linestyles).

Raises:

ValueError – if plot_range does not overlap with the data

Return type:

None

pupil_plot_segments(pdf_file=None, interv=1, figsize=(15, 5), ylim=None, units='min', **kwargs)[source]

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

Parameters:
  • pdf_file (Optional[str]) – file name to store the PDF; if None, no PDF is written

  • interv (float) – duration of each of the segments to be plotted (in units specified by units)

  • figsize (Tuple[int,int]) – dimensions of the figures

  • ylim (Tuple[float,float] or None) – y-axis limits for the plots; if None, matplotlib’s automatic limits are used

  • units (str) – Time units for segment boundaries passed to pupil_plot(). Default “min”.

  • **kwargs – arguments passed to pupil_plot()

Returns:

one figure per segment; None if pdf_file is given

Return type:

list of matplotlib.figure.Figure or None

class pypillometry.GazePlotter(obj)[source]

Class for plotting gaze data. The class is initialized with a GenericEyeData object and provides methods to plot the data in various ways.

It is usually not created directly; instead, it is available as the plot attribute of a GazeData object, e.g. d.plot.plot_heatmap().

Parameters:

obj (GenericEyeData) – the data object to plot (stored as obj)

Methods

plot_calibration([eyes, show_surface, ...])

Plot spatial calibration data for one or more eyes in subplots.

plot_heatmap([plot_range, eyes, ...])

Plot EyeData as a heatmap.

plot_intervals(intervals[, eyes, variables, ...])

Plotting data around intervals.

plot_masked([eyes, variables, units, merge, ...])

Plot masked intervals for specified eyes and variables.

plot_scanpath([plot_range, eyes, ...])

Plot EyeData as a scanpath.

plot_timeseries([plot_range, variables, ...])

Plot a part of the EyeData.

plot_timeseries_segments([pdf_file, interv, ...])

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

plot_calibration(eyes=None, show_surface=True, interpolation='rbf', figsize=(10, 8))[source]

Plot spatial calibration data for one or more eyes in subplots.

Creates a figure with subplots for each eye and calls the plot() method on each SpatialCalibration object to show calibration accuracy with target points (black X), measured points (dark blue +), and optional interpolated error surface.

Parameters:
  • eyes (Union[str, list, None]) – Which eye(s) to plot. If None or empty list, plots all available eyes. Can be a single eye name (e.g., ‘left’) or list of eye names (e.g., [‘left’, ‘right’]).

  • show_surface (bool) – If True, show interpolated error surface as background. If False, show only the calibration points.

  • interpolation (str) – Interpolation method for surface (only used if show_surface=True). Options: ‘rbf’, ‘linear’, ‘cubic’, ‘nearest’

  • figsize (tuple) – Figure size per subplot (width, height) in inches.

Returns:

  • fig (matplotlib.figure.Figure) – The figure object

  • axes (list or matplotlib.axes.Axes) – List of axis objects (or single axis if only one eye)

Raises:

ValueError – If no calibration data is available

Examples

>>> import pypillometry as pp
>>> data = pp.EyeData.from_eyelink('data.edf')
>>> # Plot all eyes with surface
>>> fig, axes = data.plot.plot_calibration()
>>>
>>> # Plot only left eye without surface
>>> fig, ax = data.plot.plot_calibration(eyes='left', show_surface=False)
>>>
>>> # Plot specific eyes
>>> fig, axes = data.plot.plot_calibration(eyes=['left', 'right'])
plot_heatmap(plot_range=(-inf, inf), eyes=[], show_screen=True, show_masked=False, rois=None, roi_style={}, units='sec', cmap='jet', gridsize=30, min_samples=1, smooth=None, limits=None)[source]

Plot EyeData as a heatmap. Typically used for a large amount of data to spot the most frequent locations. To plot a scanpath, use plot_scanpath() instead. Each eye is plotted in a separate subplot of the current figure (a new figure is created if none exists); the colorbar shows the number of samples per bin.

Parameters:
  • plot_range (tuple) – The time range to plot (in units). Default is (-np.inf, +np.inf), i.e. all data.

  • eyes (list) – The eyes to plot. Default is [], which means all available data (“left”, “right”, average, regression, …)

  • show_screen (bool) – Whether to plot the screen limits (if an experimental setup is available). Default is True.

  • show_masked (bool) – Whether to plot the masked data (because of blinks, artifacts, …). Default is False.

  • rois (List[ROI]) – List of ROIs (ROI) to plot. Default is None.

  • roi_style (dict) –

    Style for the ROIs, passed as keyword arguments to the ROIs’ plot() method. Default is {} (ROI defaults). Example:

    {
        "facecolor": "red",
        "edgecolor": "black",
        "linewidth": 2,
        "alpha": 0.5
    }
    

  • units (str) – The units of plot_range (“ms”, “sec”, “min”, “h”). Default is “sec”.

  • cmap (str) – The colormap to use. Default is “jet”.

  • gridsize (int | str) – The gridsize for the hexbin plot or histogram. If “auto”, the square root of the number of samples in plot_range is used. Default is 30.

  • min_samples (Optional[int]) – Minimum number of samples required in a bin to display it. Bins with fewer samples will not be shown. If None, automatically calculates a threshold at the 10th percentile of bin counts. Default is 1.

  • smooth (Optional[float]) – If provided, applies Gaussian smoothing to the binned histogram. The value is the sigma of the Gaussian kernel in bin units (e.g., smooth=1 applies minimal smoothing with a 1-bin sigma, smooth=2 applies more smoothing). When smooth is provided, uses a rectangular grid instead of hexbin.

  • limits (Optional[Tuple[float, float, float, float]]) – Axis limits as (xmin, xmax, ymin, ymax). If not provided, uses screen limits when available (and data falls within), otherwise uses data extent.

Raises:

ValueError – if plot_range does not overlap with the data

Return type:

None

plot_scanpath(plot_range=(-inf, inf), eyes=[], show_screen=True, rois=None, roi_style={}, show_onsets=True, title='', units=None, figsize=(10, 10))[source]

Plot EyeData as a scanpath. Typically used for single trials or another small amount of data. To plot a larger amount of data, use plot_heatmap() instead.

If several eyes are available, they are plotted in the same figure in different colors. You can choose between them using the eyes parameter. The samples are drawn as dots colored by time. A new figure is created for the plot.

Parameters:
  • plot_range (tuple) – The time range to plot (in units). Default is (-np.inf, +np.inf), i.e. all data.

  • eyes (list) – The eyes to plot. Default is [], which means all available data (“left”, “right”, average, regression, …)

  • show_screen (bool) – Whether to plot the screen limits (if an experimental setup is available). Default is True.

  • rois (List[ROI]) – List of ROIs (ROI) to plot. Default is None.

  • roi_style (dict) –

    Style for the ROIs, passed as keyword arguments to the ROIs’ plot() method. Default is {} (ROI defaults). Example:

    {
        "facecolor": "red",
        "edgecolor": "black",
        "linewidth": 2,
        "alpha": 0.5
    }
    

  • show_onsets (bool) – Whether to plot the event labels at the gaze position at event onset. Plotted only for the first eye. Default is True.

  • title (str) – The title of the plot. Default is “”.

  • units (str) – The units of plot_range (“ms”, “sec”, “min”, “h”). If None (default), the units of the time vector (ms) are used.

  • figsize (tuple) – The figure size (width, height) in inches. Default is (10,10).

Raises:

ValueError – if plot_range does not overlap with the data

Return type:

None

Supporting classes

These classes are used internally by the main classes will only rarely be used directly by the user.

GenericEyeData

class pypillometry.GenericEyeData[source]

Generic class for eyedata. Defines the basic structure of an eyedata object and implements some basic functions.

Attributes:
blinks

Return blinks (intervals) for all eyes.

events

Events (onsets in ms) as an Events object.

eyes

Return a list of available eyes in the dataset.

variables

Return a list of available variables in the dataset.

Methods

add_to_history(event)

Add event to history.

blink_stats([eyes, units])

Return statistics on blink durations.

blinks_merge_close([eyes, variables, ...])

Merge blinks that are close together.

copy([new_name])

Make and return a deep-copy of the eyedata object.

downsample(fsd[, dsfac, inplace])

Simple downsampling scheme using mean within the downsampling window.

drop_data([eyes, variables])

Drop specified eyes and/or variables from the data and return a new object.

drop_original([inplace])

Drop original dataset from record (e.g., to save space).

fill_time_discontinuities([yval, print_info])

Find gaps in the time-vector and fill them in (in-place).

from_eyelink(fname[, return_edf_obj, ...])

Reads an eyedata object from an Eyelink file.

from_file(fname)

Reads a GenericEyeData object from a pickle-file.

get_blinks([eyes, variables, units])

Get blinks as Intervals object or dict of Intervals.

get_duration([units])

Return duration of the dataset in units specified.

get_events([units])

Get events as an Events object.

get_interpolated_blinks([eyes, variables, units])

Get interpolated blinks as Intervals object or dict of Intervals.

get_intervals(event_select[, interval, ...])

Return an Intervals object containing intervals relative to event-onsets.

get_segments(intervals, variable[, name])

Extract segments from data using intervals.

get_size()

Return the size of the object in bytes.

interpolate_intervals(intervals[, eyes, ...])

Interpolate data within specified intervals.

mask_as_intervals([eyes, variables, units, ...])

Convert masks to Intervals objects.

mask_intervals(intervals[, eyes, variables, ...])

Apply Intervals as masks to selected data.

merge_eyes([eyes, variables, method, ...])

Merge data from both eyes into a single variable.

merge_masks([inplace])

Merge masks of all variables into a single joint mask.

nblinks([eyes, variables])

Return number of detected blinks.

nevents()

Return number of events in data.

print_history()

Pretty-print the history of the current dataset (which manipulations where done on it).

reset_time([t0, inplace])

Resets time so that time t0 becomes time zero.

scale([variables, mean, sd, eyes, inplace])

Scale the signal by subtracting mean and dividing by sd.

set_blinks(intervals[, eyes, variables, ...])

Set blinks for specified eyes and variables (in-place).

set_event_onsets(event_onsets, event_labels)

Set onsets of events in the data (in-place).

set_events(events[, inplace])

Replace event onsets and labels from an Events object.

stat_per_event([intervals, interval, ...])

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

sub_slice([start, end, units, inplace])

Return a shortened version of the current object.

summary()

Return a summary of the GenericEyedata-object.

unscale([variables, mean, sd, eyes, inplace])

Scale back to original values using either values provided as arguments or the values stored in params["scale"] by scale().

write_file(fname)

Save to file (using pickle).

add_to_history(event)[source]

Add event to history.

Usually called by the keephistory decorator.

Parameters:

event (dict) – description of the operation with keys “funcstring” (printable call) and “funcname” (method name)

Return statistics on blink durations.

Uses the blinks stored for the “pupil” variable of each eye (see stats()).

Parameters:
  • eyes (list) – eye(s) to consider; if empty, all available eyes

  • units (str) – Units for statistics: “ms”, “sec”, “min”, or “h”. Default “ms”.

Returns:

Dictionary mapping eye name to stats dict (number, mean, sd, min, max and total duration of blinks), or None if no blinks

Return type:

dict

Return blinks (intervals) for all eyes.

Returns:

dictionary with blinks for each eye

Return type:

dict

Merge blinks that are close together.

Parameters:
  • eyes (list) – eye(s) to process; if empty, all available eyes

  • variables (list) – variable(s) to process; if empty, all available variables

  • distance (float) – Merge blinks closer than this distance (in units specified by units). Default 100.

  • units (str) – Units for distance. Can be “ms”, “sec”, “min”, or “h”. Default “ms”.

  • apply_mask (bool) – If True, store the merged blinks, apply them as masks to the data and return the object. If False, return merged blinks as dict of Intervals objects without storing them or applying masks.

  • inplace (bool | None) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor). Only relevant when apply_mask=True.

Returns:

If apply_mask=True: returns modified object for chaining. If apply_mask=False: returns dict of Intervals objects (one per eye/variable combination).

Return type:

GenericEyeData or dict of Intervals

copy(new_name=None)[source]

Make and return a deep-copy of the eyedata object.

Parameters:

new_name (Optional[str]) – New name for the copy. If None, “_copy” is appended to the original name.

Returns:

deep copy of the object (same class as the original)

Return type:

GenericEyeData

downsample(fsd, dsfac=False, inplace=None)[source]

Simple downsampling scheme using mean within the downsampling window.

All data fields and the time-vector are downsampled simultaneously. See pypillometry.signal.baseline.downsample(). Masked samples are left out of the window means; a new sample is masked only if all samples in its window were masked. Stored blinks (in sample indices) are rescaled to the new sampling rate.

Parameters:
  • fsd (float) – new sampling-rate (in Hz) or decimate-factor

  • dsfac (bool) – if False (default), fsd is the new sampling rate (the decimate factor is int(fs/fsd)); if True, fsd is the decimate factor

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

the downsampled object (self or a copy, depending on inplace)

Return type:

GenericEyeData

drop_data(eyes=[], variables=[])[source]

Drop specified eyes and/or variables from the data and return a new object.

This method never works in place - it always returns a new object. All data of the given eyes and all data of the given variables are dropped (together with their stored blinks). The returned object’s class is determined by what data remains:

  • If only pupil variables remain: returns PupilData

  • If only x/y variables remain: returns GazeData

  • If both pupil and x/y remain: returns EyeData

Parameters:
  • eyes (list) – Eyes to drop (e.g., [‘left’] or [‘right’] or [‘left’, ‘right’]); if empty, no eye is dropped

  • variables (list) – Variables to drop (e.g., [‘pupil’] or [‘x’, ‘y’]); if empty, no variable is dropped

Returns:

A new object with the specified data removed, cast to the appropriate class.

Return type:

GenericEyeData subclass

Raises:

ValueError – If dropping would result in no data remaining.

Examples

>>> # Drop left eye data
>>> right_only = data.drop_data(eyes=['left'])
>>>
>>> # Drop pupil data, keep only gaze
>>> gaze_only = data.drop_data(variables=['pupil'])
>>>
>>> # Drop right eye and pupil data
>>> left_gaze = data.drop_data(eyes=['right'], variables=['pupil'])
drop_original(inplace=None)[source]

Drop original dataset from record (e.g., to save space).

Sets the original attribute (stored when the object was created with keep_orig=True) to None.

Parameters:

inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

the object without the original data (self or a copy, depending on inplace)

Return type:

GenericEyeData

property events

Events (onsets in ms) as an Events object.

Shortcut for get_events() with default arguments.

property eyes: List[str]

Return a list of available eyes in the dataset.

fill_time_discontinuities(yval=nan, print_info=True)[source]

Find gaps in the time-vector and fill them in (in-place).

A gap is a step between consecutive time points that is larger than twice the median step. New time points are inserted into each gap at the median step size and all data variables are set to yval at these new time points; they are masked as missing. Existing masks are kept and stored blinks (in sample indices) are moved to the new sample positions. This is called by the constructor when fill_time_discontinuities=True.

Parameters:
  • yval (float, optional) – value used for the data in the filled-in gaps; default NaN, so the filled-in samples are masked as missing data

  • print_info (bool, optional) – if True (default), log the number of gaps that are filled in

Returns:

the object itself (always modified in-place)

Return type:

GenericEyeData

Reads an eyedata object from an Eyelink file.

All “messages” are stored as event_labels (can be filtered later) and it tries to be smart to detect different information from the EDF file. Spatial calibration/validation data is automatically parsed and stored in the calibration attribute as SpatialCalibration objects. Eyelink codes missing pupil samples (e.g., during blinks) as 0; these are converted to NaN (and therefore masked).

However, the EDF file may contain other information of interest, e.g., eyelink-detected saccades, etc. If you need more control, use the “eyelinkio” package directly and create the object manually.

Parameters:
  • fname (str) – filename of the EDF file (or URL)

  • return_edf_obj (bool) – if True, return a tuple with the eyedata object and the object returned by the “eyelinkio” package; if False (default), return only the eyedata object

  • remove_eyelink_triggers (bool) – if True (default), remove all Eyelink triggers from the event_labels (related to eye-tracker settings, calibration, validation etc)

  • **kwargs – additional arguments passed to pypillometry.io.read_eyelink() (e.g., cache_file)

Returns:

object of the class this method is called on (e.g., EyeData), or tuple with that object and the object returned by the “eyelinkio” package

Return type:

GenericEyeData or tuple

Examples

>>> import pypillometry as pp
>>> d = pp.EyeData.from_eyelink('data.edf')
>>> # Access calibration data
>>> print(d.calibration['left'])
<SpatialCalibration: left eye, HV9, n=9, error=0.45±0.23° (max=0.79°)>
classmethod from_file(fname)[source]

Reads a GenericEyeData object from a pickle-file. Use as pypillometry.PupilData.from_file("yourfile.pd").

The file is read with pypillometry.io.read_pickle(), so fname can also be a URL.

Parameters:

fname (str) – filename (or URL)

Returns:

the object stored in the file (its class is the one that was stored, independent of the class this method is called on)

Return type:

GenericEyeData

Get blinks as Intervals object or dict of Intervals.

If no blinks are stored for an eye/variable, an empty Intervals object is returned for it.

Parameters:
  • eyes (str | list) – Eye(s) to get blinks for; if empty, all available eyes. If multiple, returns dict.

  • variables (str | list) – Variable(s) to get blinks for; if empty, all available variables. If multiple, returns dict.

  • units (str | None) – Units for intervals: “ms”, “sec”, “min”, “h”, or None for indices

Returns:

If single eye and variable: returns Intervals object. If multiple eyes/variables: returns dict with keys like “left_pupil”.

Return type:

Intervals or dict

Examples

>>> blinks = data.get_blinks('left', 'pupil')
>>> blinks_ms = data.get_blinks('left', 'pupil', units="ms")
>>> blinks_dict = data.get_blinks(['left', 'right'], 'pupil')
>>> blinks_idx = blinks_ms.to_units("indices")
get_duration(units='min')[source]

Return duration of the dataset in units specified.

Parameters:

units (str, optional) – unit one of “min”, “sec”, “h”, by default “min”

Returns:

duration of dataset in specified units

Return type:

float

get_events(units='ms')[source]

Get events as an Events object.

Returns the event onsets and labels stored in the dataset as an Events object, which provides convenient filtering and display capabilities.

Parameters:

units (str) – Units for the event onsets: “ms”, “sec”, “min”, or “h”. Default is “ms” (the internal storage format).

Returns:

Events object containing the event onsets and labels

Return type:

Events

Examples

>>> events = data.get_events()
>>> len(events)
42
>>> # Get events in seconds
>>> events_sec = data.get_events(units="sec")
>>> # Filter and work with events
>>> stim_events = data.get_events().filter("stim")

See also

set_events

Replace events from an Events object

get_intervals

Extract intervals around events

Get interpolated blinks as Intervals object or dict of Intervals.

Interpolated blinks are the blink regions that were successfully interpolated by pupil_blinks_interpolate(). These may differ from detected blinks because:

  • Blink boundaries are refined using velocity thresholds

  • Some blinks may be skipped if they’re too short to interpolate

If no interpolated blinks are stored for an eye/variable, an empty Intervals object is returned for it.

Parameters:
  • eyes (str | list) – Eye(s) to get interpolated blinks for; if empty, all available eyes. If multiple, returns dict.

  • variables (str | list) – Variable(s) to get interpolated blinks for; if empty, all available variables. If multiple, returns dict.

  • units (str | None) – Units for intervals: “ms”, “sec”, “min”, “h”, or None for indices

Returns:

If single eye and variable: returns Intervals object. If multiple eyes/variables: returns dict with keys like “left_pupil”.

Return type:

Intervals or dict

See also

get_blinks

Get detected (not interpolated) blinks

pupil_blinks_interpolate

Interpolate blinks

get_intervals(event_select, interval=(-200, 200), units=None, label=None, **kwargs)[source]

Return an Intervals object containing intervals relative to event-onsets. For example, extract the interval before and after a stimulus has been presented. It is possible to select based on the event label, e.g. only select events matching “stimulus” or “response”. It is also possible to select the intervals situated between two different events, e.g., trial start and response by specifying event_select as a tuple with two entries.

Parameters:
  • event_select (str, tuple, function, or Events) –

    variable describing which events to select and align to

    • if str: use all events whose label contains the string

    • if function: apply function to all labels, use those where the function returns True

    • if tuple: use the intervals between the events selected by the first and the second entry (each a str or function); interval[0] is added to the first and interval[1] to the second event. Both selectors must result in identical number of events.

    • if Events: use the events from the Events object directly

  • interval (tuple) – time-window relative to event-onset (0 is event-onset); i.e., negative numbers are before the event, positive numbers after. Units are defined by the units parameter. Default (-200, 200).

  • units (str | None) – units of the interval (one of “ms”, “sec”, “min”, “h”); units=None (default) means that the interval is in sampling units (i.e., indices into the time-array)

  • label (str | None) – optional label for the Intervals object. If None, a label is automatically generated from the event_select parameter

  • **kwargs – passed onto the event_select function

Returns:

Intervals object containing interval on- and offsets for each match, with associated metadata (event labels, indices, units)

Return type:

Intervals

get_segments(intervals, variable, name=None)[source]

Extract segments from data using intervals.

Creates a SegmentedEyeData object containing equal-length segments of a single variable extracted at the specified intervals.

Parameters:
  • intervals (Intervals) – Intervals object defining the segments to extract (from get_intervals())

  • variable (str) – Variable to extract in “eye_variable” format (e.g., “left_pupil”, “right_x”)

  • name (str) – Name for the segmented dataset. If None, uses intervals.label or “segments”

Returns:

Object containing the extracted segments with mask information

Return type:

SegmentedEyeData

Examples

>>> # Extract pupil segments around stimulus events
>>> intervals = data.get_intervals("stimulus", interval=(-200, 800), units="ms")
>>> segments = data.get_segments(intervals, "left_pupil")
>>> segments.plot()
>>> # Apply baseline correction
>>> segments_bc = segments.baseline_correct(window=(-200, 0))

See also

get_intervals

Create Intervals object from events

SegmentedEyeData

Class holding segmented data

get_size()[source]

Return the size of the object in bytes.

Returns:

Total size of the object, including data and all attributes.

Return type:

ByteSize

interpolate_intervals(intervals, eyes=[], variables=[], method='linear', margin=(-20, 20), store_as_suffix=None, inplace=None)[source]

Interpolate data within specified intervals.

This function replaces data within the specified intervals with interpolated values based on boundary points outside each interval. The interpolated samples are also marked as masked. Intervals without valid (non-NaN) boundary points on both sides are skipped with a warning.

Parameters:
  • intervals (Intervals or dict) –

    Either:

    • A single Intervals object: applied to all specified eyes/variables

    • A dict of Intervals: keys like “left_pupil”, “right_x”, etc. When dict is provided, eyes and variables are ignored.

  • eyes (str or list of str, optional) – eye(s) to interpolate; if empty, all available eyes. Ignored if intervals is a dict.

  • variables (str or list of str, optional) – variable(s) to interpolate; if empty, all available variables. Ignored if intervals is a dict.

  • method (str, default "linear") – Interpolation method. Options: “linear”, “nearest”, “zero”, “slinear”, “quadratic”, “cubic”, “previous”, “next”. Passed to scipy.interpolate.interp1d.

  • margin (tuple, default (-20, 20)) – Time window (in ms) before and after the interval to collect boundary points for interpolation. Boundary points are taken from abs(margin[0]) ms before the start and abs(margin[1]) ms after the end of each interval (the signs are ignored). For higher-order methods like “cubic” or “quadratic”, more boundary points from this margin are used to fit the interpolation curve.

  • store_as_suffix (str or None, default None) – If None, replace the original data. If a string, store interpolated data in a new variable with this suffix (e.g., “_interp” creates “left_pupil_interp”).

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

The object with interpolated data (self or a copy, depending on inplace).

Return type:

GenericEyeData

Examples

Interpolate blinks for left eye pupil data:

>>> blinks = data.get_blinks(eyes='left', variables='pupil')
>>> data.interpolate_intervals(blinks, eyes=['left'], variables=['pupil'])

Interpolate using a dict of intervals:

>>> blinks = data.get_blinks()  # returns dict
>>> data.interpolate_intervals(blinks)

Store interpolated data in a new variable:

>>> data.interpolate_intervals(blinks, store_as_suffix="_interp")
>>> # Access via data['left', 'pupil_interp']

Use cubic interpolation with wider margin:

>>> data.interpolate_intervals(blinks, method="cubic", margin=(-50, 50))

See also

mask_intervals

Apply intervals as masks without interpolation

get_blinks

Retrieve stored blink intervals

mask_as_intervals(eyes=[], variables=[], units=None, label=None)[source]

Convert masks to Intervals objects.

Each contiguous run of masked samples becomes one interval.

Parameters:
  • eyes (str | list) – Eye(s) to get masks for; if empty, all available eyes. If multiple, returns dict.

  • variables (str | list) – Variable(s) to get masks for; if empty, all available variables. If multiple, returns dict (combinations not present in the data are left out).

  • units (str | None) – Units for intervals: “ms”, “sec”, “min”, “h”, or None for indices. Default is None (indices).

  • label (str | None) – Descriptive label for the intervals. Default is None.

Returns:

If single eye and variable: returns Intervals object. If multiple eyes/variables: returns dict with keys like “left_pupil”.

Return type:

Intervals or dict

Examples

>>> mask_intervals = data.mask_as_intervals('left', 'pupil')
>>> mask_ms = data.mask_as_intervals('left', 'pupil', units='ms')
>>> mask_dict = data.mask_as_intervals(['left', 'right'], 'pupil')
mask_intervals(intervals, eyes=[], variables=[], inplace=None)[source]

Apply Intervals as masks to selected data.

Takes detected intervals (e.g., blinks, artifacts) and applies them as masks to specified eyes and variables. Existing masks are kept (the new mask is added to them).

Parameters:
  • intervals (Intervals or dict) –

    Either:

    • A single Intervals object: applied to all specified eyes/variables

    • A dict of Intervals: keys like “left_pupil”, “right_x”, etc. When dict is provided, eyes and variables are ignored.

  • eyes (str or list of str, optional) – eye(s) to apply mask to (e.g., ["left", "right"]); if empty, all available eyes. Ignored if intervals is a dict.

  • variables (str or list of str, optional) – variable(s) to apply mask to (e.g., ["pupil", "x", "y"]); if empty, all available variables. Ignored if intervals is a dict.

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

The object with masks applied (self or a copy, depending on inplace).

Return type:

GenericEyeData

Examples

Apply blinks from a single Intervals object to left eye pupil data:

>>> blinks = data.pupil_blinks_detect(apply_mask=False)
>>> data.mask_intervals(blinks['left_pupil'], eyes=['left'], variables=['pupil'])

Apply a dict of intervals (one per eye/variable):

>>> blinks = data.pupil_blinks_detect(apply_mask=False)
>>> data.mask_intervals(blinks)  # eyes and variables ignored

Chain with other operations:

>>> data.mask_intervals(blinks).pupil_lowpass_filter(cutoff=5)

See also

pupil_blinks_detect

Detect blinks with optional masking

get_blinks

Retrieve stored blink intervals

merge_eyes(eyes=[], variables=[], method='mean', keep_eyes=True, inplace=None)[source]

Merge data from both eyes into a single variable.

The merged data is stored under the eye name “mean” (e.g., obj["mean", "pupil"]). A sample is masked in the merged data if it is masked in any of the merged eyes.

Parameters:
  • eyes (str or list of str, optional) – eye(s) to merge; if empty, all available eyes

  • variables (str or list of str, optional) – variable(s) to merge; if empty, all available variables

  • method (str, optional) – which method to use for merging; currently only “mean” is implemented, by default “mean”

  • keep_eyes (bool, optional) – keep original eye data (True, default) or drop it together with its stored blinks (False)

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

the object with merged data (self or a copy, depending on inplace)

Return type:

GenericEyeData

merge_masks(inplace=None)[source]

Merge masks of all variables into a single joint mask.

This function creates a joint mask by taking the logical OR of all individual masks using get_mask(), then applies this joint mask to all variables.

Parameters:

inplace (bool, optional) – If True, make change in-place and return the object. If False, make and return copy before making changes. If None, use the object’s default setting.

Returns:

The object with merged masks.

Return type:

GenericEyeData

Return number of detected blinks. Should be run after pupil_blinks_detect().

By default, all eyes and variables are considered.

Parameters:
  • eyes (str or list of str, optional) – eye(s) to consider; if empty, all available eyes

  • variables (str or list of str, optional) – variable(s) to consider; if empty, all available variables

Returns:

number of detected blinks per eye/variable, with keys like “left_pupil”; combinations without blinks are left out

Return type:

int

nevents()[source]

Return number of events in data.

Return type:

int

params: dict

Constructor

print_history()[source]

Pretty-print the history of the current dataset (which manipulations where done on it).

reset_time(t0=None, inplace=None)[source]

Resets time so that time t0 becomes time zero.

t0 is subtracted from the time-vector and from the event onsets.

Parameters:
  • t0 (float | None) – time (in ms) that becomes the new time zero; if None, use the first time point (so that the time-vector starts at zero)

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

the object with shifted time (self or a copy, depending on inplace)

Return type:

GenericEyeData

scale(variables=[], mean=None, sd=None, eyes=[], inplace=None)[source]

Scale the signal by subtracting mean and dividing by sd. If these variables are not provided, use the signal’s mean and std. Specify whether to scale x, y, pupil or other variables.

Parameters:
  • variables (str or list of str, optional) – variables to scale; can be “pupil”, “x”,”y”, “baseline”, “response” or any other variable that is available in the dataset; either a string or a list of strings; available variables can be checked with obj.variables; empty list means all variables

  • mean (Union[float, dict, None]) – mean to subtract from signal; if None, use the signal’s mean (of the non-masked samples); if float, use the same value for all eyes and variables; if dict, provide mean for each eye and variable as {eye: {variable: value}}

  • sd (Union[float, dict, None]) – sd to scale with; if None, use the signal’s std (of the non-masked samples); if float, use the same value for all eyes and variables; if dict, provide sd for each eye and variable as {eye: {variable: value}}

  • eyes (str or list of str, optional) – eye(s) to consider; if empty, all available eyes

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

the scaled object (self or a copy, depending on inplace)

Return type:

GenericEyeData

Notes

Scaling-parameters are being saved in the params[“scale”] attribute and are used by unscale().

Set blinks for specified eyes and variables (in-place).

Parameters:
  • intervals (Intervals, dict or None) –

    Either:

    • a single Intervals object: stored for all specified eyes/variables;

    • a dict of Intervals (or None) with keys like “left_pupil”, “right_x”, etc.; when a dict is provided, eyes and variables are ignored;

    • None: remove the stored blinks for the specified eyes/variables (the mask is not changed).

  • eyes (str or list of str, optional) – eye(s) to set blinks for (e.g., ["left", "right"]); if empty, all available eyes. Ignored if intervals is a dict.

  • variables (str or list of str, optional) – variable(s) to set blinks for (e.g., ["pupil", "x", "y"]); if empty, all available variables. Ignored if intervals is a dict.

  • apply_mask (bool, optional) – If True, also apply the intervals as mask to the data (existing masks are kept). If False, only store intervals. Default is True.

set_event_onsets(event_onsets, event_labels)[source]

Set onsets of events in the data (in-place).

Parameters:
  • event_onsets (ndarray) – array of onsets (in ms); None removes all events

  • event_labels (ndarray) – array of labels (strings), same length as event_onsets; if None, all labels are set to 0

Raises:

ValueError – if any onset is outside the range of the time-vector or if event_labels and event_onsets differ in length

See also

set_events

set events from an Events object

set_events(events, inplace=None)[source]

Replace event onsets and labels from an Events object.

This method updates the internal event_onsets and event_labels arrays from an Events object. The Events object’s onsets are automatically converted to milliseconds (the internal storage format) if needed.

Parameters:
  • events (Events) – Events object containing the new events to set

  • inplace (bool, optional) – if True, make change in-place and return the object if False, make and return copy before making changes if None, use the setting of the object (specified in constructor)

Returns:

The object with updated events (may be self or a copy depending on inplace)

Return type:

GenericEyeData

Examples

>>> # Filter events and set them back
>>> events = data.get_events()
>>> stim_events = events.filter("stim")
>>> data.set_events(stim_events)
>>> # Modify events and update
>>> events = data.get_events()
>>> # ... filter or modify events ...
>>> data.set_events(events)

See also

get_events

Get events as an Events object

set_event_onsets

Lower-level method to set events from arrays

stat_per_event(intervals=None, interval=None, event_select=None, eyes=[], variables=[], statfct=<function mean>, units='ms', **kwargs)[source]

Return result of applying a statistical function to data in a given interval relative to event-onsets. For example, extract mean pupil-size in interval before trial onset.

Parameters:
  • intervals (Intervals, optional) – Intervals object to use, in any time units or in sample indices (units=None, the default of get_intervals()). If provided, interval and event_select are ignored.

  • interval (Tuple[float, float]) – time-window relative to event-onset (0 is event-onset), in units given by units. Required if intervals is not provided.

  • event_select (str or function, optional) – variable describing which events to select and align to see get_intervals() for details. Required if intervals is not provided.

  • eyes (str | list) – eye(s) to consider; if empty, all available eyes

  • variables (str | list) – variable(s) to consider; if empty, all available variables

  • statfct (Callable) – function mapping a masked array to a single number; it must ignore masked samples (e.g., np.mean (default) or np.ma.median, but not np.median; a warning is logged otherwise). Intervals where all samples are masked give NaN.

  • units (str) – units for interval parameter (if used); default “ms”

  • **kwargs – passed onto the event_select function

Returns:

one array per eye/variable (keys like “left_pupil”), with one value per interval/event

Return type:

dict

sub_slice(start=-inf, end=inf, units=None, inplace=None)[source]

Return a shortened version of the current object.

The result contains all data (and events) between start and end (inclusive), in units given by units (one of “ms”, “sec”, “min”, “h”). start and end refer to the values of the time-vector (not to the time since the start of the recording). Masks are kept; stored blinks (in sample indices) are shifted and cut to the new range.

Parameters:
  • start (float) – start for new dataset; default: beginning of the data

  • end (float) – end of new dataset; default: end of the data

  • units (str) – time units in which start and end are provided (one of “ms”, “sec”, “min”, “h”). If units is None, use the units in the time vector (ms).

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

the shortened object (self or a copy, depending on inplace)

Return type:

GenericEyeData

abstractmethod summary()[source]

Return a summary of the GenericEyedata-object.

Return type:

dict

unscale(variables=[], mean=None, sd=None, eyes=[], inplace=None)[source]

Scale back to original values using either values provided as arguments or the values stored in params[“scale”] by scale().

The signal is multiplied by sd and mean is added.

Parameters:
  • variables (str or list of str, optional) – variables to unscale; can be “pupil”, “x”,”y”, “baseline”, “response” or any other variable that is available in the dataset; either a string or a list of strings; available variables can be checked with obj.variables; empty list means all variables

  • mean (None or dict, optional) – mean to add to the signal as {eye: {variable: value}}; if None, use the mean stored by scale()

  • sd (None or dict, optional) – sd to multiply the signal with as {eye: {variable: value}}; if None, use the sd stored by scale()

  • eyes (str or list of str, optional) – eye(s) to consider; if empty, all available eyes

  • inplace (bool or None, optional) – if True, make change in-place and return the object; if False, make and return copy before making changes; if None, use the object-level setting (specified in the constructor)

Returns:

the unscaled object (self or a copy, depending on inplace)

Return type:

GenericEyeData

property variables: List[str]

Return a list of available variables in the dataset.

write_file(fname)[source]

Save to file (using pickle).

Parameters:

fname (str) – filename

EyeDataDict

class pypillometry.EyeDataDict(*args, **kwargs)[source]

A dictionary that contains 1-dimensional ndarrays of equal length and with the same datatype (float). Drops empty entries (None or length-0 ndarrays).

Keys stored in this dictionary have the following shape: (eye)_(variable) where eye can be any string identifier (e.g., “left”, “right”, “mean”, “median”, “regress”, or any other custom identifier) and variable is any string identifier (e.g., “x”, “y”, “pupil”, “baseline”, “response”, or any other custom identifier).

Values are stored as given (converted to float); NaN values are masked. No other values are treated as missing (e.g., a pupil size of 0 is kept); converting missing-value codes to NaN is up to the code that reads the data.

The dictionary can be indexed by a string “eye_variable” or by a tuple (“eye”, “variable”) like data[“left”,”x”] or data[“left_x”].

Attributes:
eyes

List of all available eyes.

variables

List of all available variables.

Methods

clear()

copy()

Create a deep copy of the dictionary.

count_masked([per_key])

Count the number of missing values based on masks.

get(k[,d])

get_available_eyes([variable])

Return a list of available eyes.

get_available_variables()

Return a list of available variables.

get_eye(eye)

Return a subset EyeDataDict with all variables for a given eye.

get_mask([key])

Get mask for a specific key or joint mask across all keys.

get_size()

Return the size of the dictionary in bytes.

get_variable(variable)

Return a subset EyeDataDict with all eyes for a given variable.

items()

keys()

pop(k[,d])

value.

popitem()

as a 2-tuple; but raise KeyError if D is empty.

set_mask(key, mask)

Set mask for a specific key.

set_with_mask(key, value[, mask, preserve_mask])

Set data array with explicit mask control.

setdefault(k[,d])

update([E, ]**F)

If E present and has a .keys() method, does:

values()

copy()[source]

Create a deep copy of the dictionary.

Return type:

EyeDataDict

count_masked(per_key=False)[source]

Count the number of missing values based on masks.

Parameters:

per_key (bool) – If True, return a dictionary with counts per key. If False, return maximum count across all keys. Default is False.

Returns:

If per_key is False, returns maximum number of missing values across all keys. If per_key is True, returns a dictionary mapping keys to their missing value counts.

Return type:

Union[int, Dict[str, int]]

Examples

>>> d = EyeDataDict(left_x=[1,2,3], left_y=[4,5,6])
>>> d.set_mask("left_x", [0,1,0])  # second value is missing
>>> d.set_mask("left_y", [1,0,1])  # first and last values are missing
>>> d.count_masked()  # max missing values
2
>>> d.count_masked(per_key=True)  # missing values per key
{'left_x': 1, 'left_y': 2}
property eyes: List[str]

List of all available eyes.

get_available_eyes(variable=None)[source]

Return a list of available eyes.

Parameters:

variable (str, optional) – If specified, return only eyes for this variable.

Returns:

names of the available eyes (e.g., ["left", "right"]), in no particular order

Return type:

list of str

get_available_variables()[source]

Return a list of available variables.

Returns:

names of the available variables (e.g., ["x", "y", "pupil"]), in no particular order

Return type:

list of str

get_eye(eye)[source]

Return a subset EyeDataDict with all variables for a given eye.

Parameters:

eye (str) – The eye to get data for (‘left’, ‘right’, ‘mean’, etc.)

Returns:

A new EyeDataDict containing only data for the specified eye

Return type:

EyeDataDict

Examples

>>> d = EyeDataDict(left_x=[1,2], left_y=[3,4], right_x=[5,6])
>>> left_data = d.get_eye('left')
>>> print(left_data.data.keys())
dict_keys(['left_x', 'left_y'])
get_mask(key=None)[source]

Get mask for a specific key or joint mask across all keys.

Parameters:

key (str) – Key to get mask for. If None, returns logical OR of all masks.

Returns:

Mask array for specified key, or joint mask if no key given.

Return type:

NDArray

get_size()[source]

Return the size of the dictionary in bytes.

Returns:

Total size in bytes.

Return type:

ByteSize

get_variable(variable)[source]

Return a subset EyeDataDict with all eyes for a given variable.

Parameters:

variable (str) – The variable to get data for (‘x’, ‘y’, ‘pupil’, etc.)

Returns:

A new EyeDataDict containing only data for the specified variable

Return type:

EyeDataDict

set_mask(key, mask)[source]

Set mask for a specific key.

Parameters:
  • key (str) – Key of the data (e.g., “left_pupil”)

  • mask (NDArray) – Mask array (1 for masked, 0 for valid values) with the same shape as the data; converted to int

Raises:
  • KeyError – if there is no data for key

  • ValueError – if mask does not have the same shape as the data

Return type:

None

set_with_mask(key, value, mask=None, preserve_mask=False)[source]

Set data array with explicit mask control.

This method provides more control over mask handling than __setitem__, which always resets the mask to zeros (except for NaN values).

Parameters:
  • key (Union[str, Tuple[str, str]]) – Dictionary key for the data (e.g., “left_pupil” or (“left”, “pupil”))

  • value (NDArray) – Data array to store

  • mask (Optional[NDArray]) – Mask array to use. If None and preserve_mask=True, keeps existing mask. If None and preserve_mask=False, creates new zero mask (with NaNs masked).

  • preserve_mask (bool) – If True and mask is None, preserve the existing mask for this key. Ignored if mask is explicitly provided.

Return type:

None

Examples

>>> # Set data and preserve existing mask
>>> data_dict.set_with_mask("left_pupil", new_values, preserve_mask=True)
>>> # Set data with explicit mask
>>> data_dict.set_with_mask("left_pupil", new_values, mask=new_mask)
>>> # Set data with fresh zero mask (same as __setitem__)
>>> data_dict.set_with_mask("left_pupil", new_values)
property variables: List[str]

List of all available variables.

Stateless signal-processing functions

These functions are used by the main classes to process the data. They are stateless, meaning that they do not store any state between calls.

baseline.py

Functions for estimating tonic pupillary fluctuations (baseline).

pypillometry.signal.baseline.baseline_envelope(tx, sy, event_onsets, fs=1000, lp=2, prominence_thr=80, interp_method='cubic')[source]

Extract baseline based on the lower envelope of the (filtered) signal.

Steps:

  • filter away noise

  • detect high-prominence troughs in the signal

  • calculate lower envelope based on these peaks

Parameters:
  • tx (np.ndarray) – time-vector (any unit; the baseline is evaluated at tx)

  • sy (np.ndarray) – raw pupil signal (must not contain NaN)

  • event_onsets (np.ndarray) – onsets of events (stimuli/responses); currently not used

  • fs (float) – sampling rate in Hz

  • lp (float) – low-pass filter cutoff in Hz for removing random noise

  • prominence_thr (float) – percentile (in [0, 100]) of the prominence distribution (of the peaks) to use for determining prominent peaks (see scipy.signal.peak_prominences())

  • interp_method ({"cubic", "linear", "spline"}) –

    • “linear”: linear interpolation between the high-prominence peaks

    • ”cubic”: cubic interpolation through all high-prominence peaks

    • ”spline”: a smoothing spline that is guaranteed to go through all high-prominence peaks and smoothes through all the other (lower-prominence) peaks

Returns:

base – baseline estimate (same length as tx)

Return type:

np.ndarray

Raises:

ValueError – if interp_method is not one of the supported methods

pypillometry.signal.baseline.baseline_envelope_iter_bspline(tx, sy, event_onsets, fs, fsd=10, lp=2, lam_sig=1, lam_min=1, lam_max=100, verbose=0)[source]

Extract baseline based (re-)estimating the lower envelope using B-splines. See notebook baseline_interp.ipynb for details. The signal is downsampled (to fsd Hz) for speed.

The B-spline fits are done with a Stan model (baseline_model_asym_laplac.stan, variational inference via cmdstanpy); in between, the event-related responses are estimated with pupil_response() (fixed npar=10, tmax=917) and removed before the second round of peak detection.

Parameters:
  • tx (np.ndarray) – time-vector in milliseconds

  • sy (np.ndarray) – raw pupil signal (must not contain NaN)

  • event_onsets (np.ndarray) – onsets of events (stimuli/responses) in milliseconds

  • fs (float) – sampling rate in Hz

  • fsd (float) – downsampled sampling rate in Hz (if too slow, decrease)

  • lp (float) – lowpass-filter cutoff in Hz (applied before downsampling)

  • lam_sig (float) – parameter steering how much the baseline is shaped by the non-peaks of the signal

  • lam_min (float) – weight given to the lowest-prominence peaks; peak prominences are mapped linearly to [lam_min, lam_max]

  • lam_max (float) – weight given to the highest-prominence peaks

  • verbose (int) – not used (progress is reported via the logger)

Returns:

  • txd (np.ndarray) – downsampled time-vector (ms)

  • syd (np.ndarray) – downsampled and lowpass-filtered pupil signal

  • base2 (np.ndarray) – final baseline estimate (after the second round), sampled at txd

  • base1 (np.ndarray) – baseline estimate after the first round, sampled at txd

pypillometry.signal.baseline.baseline_pupil_model(tx, sy, event_onsets, fs=1000, lp1=2, lp2=0.2)[source]

Extract baseline based on filtering after removing stim-locked activity.

Steps:

  • filter away noise

  • regress out event-locked activity from the filtered signal using NNLS

  • remove modeled signal from filtered data

  • run another lowpass-filter to get rid of spurious signals

Parameters:
  • tx (np.ndarray) – time-vector

  • sy (np.ndarray) – raw pupil signal (must not contain NaN)

  • event_onsets (np.ndarray) – onsets of events (stimuli/responses), in the same units as tx (each onset is assigned to the closest sample in tx)

  • fs (float) – sampling rate in Hz

  • lp1 (float) – low-pass filter cutoff in Hz for removing random noise

  • lp2 (float) – low-pass filter cutoff in Hz for removing spurious peaks from the baseline-signal

Returns:

base – baseline estimate (same length as sy)

Return type:

np.ndarray

pypillometry.signal.baseline.bspline(txd, knots, spline_degree=3)[source]

Re-implementation from https://mc-stan.org/users/documentation/case-studies/splines_in_stan.html. Similar behaviour as R’s bs() function from the splines-library.

Parameters:
  • txd (np.ndarray) – time-vector (any unit, same as knots)

  • knots (np.ndarray) – location of the knots (including the boundary knots)

  • spline_degree (int) – degree of the spline (default 3, cubic)

Returns:

B – matrix of basis functions, shape (len(txd), len(knots)+spline_degree-1)

Return type:

np.ndarray

pypillometry.signal.baseline.butter_lowpass(cutoff, fs, order=5)[source]

Get lowpass-filter coefficients for Butterworth-filter.

Parameters:
  • cutoff (float) – lowpass-filter cutoff in Hz

  • fs (float) – sampling rate in Hz

  • order (int) – filter order

Returns:

b, a – numerator and denominator filter coefficients (see scipy.signal.butter())

Return type:

np.ndarray

pypillometry.signal.baseline.butter_lowpass_filter(data, cutoff, fs, order=5)[source]

Lowpass-filter signal using a Butterworth-filter.

The filter is applied forward and backward (scipy.signal.filtfilt()), so the result has zero phase shift. data must not contain NaN values.

Parameters:
  • data (np.ndarray) – data to lowpass-filter

  • cutoff (float) – lowpass-filter cutoff in Hz

  • fs (float) – sampling rate in Hz

  • order (int) – filter order

Returns:

y – filtered data

Return type:

np.ndarray

pypillometry.signal.baseline.downsample(y, R)[source]

Simple downsampling scheme using mean within the downsampling window.

The signal is split into consecutive windows of R samples and each window is replaced by its mean (ignoring NaN). If the length of y is not a multiple of R, the last window is shorter.

Parameters:
  • y (np.ndarray) – signal to downsample

  • R (int) – decimate-factor (number of samples per window)

Returns:

y2 – downsampled data of length ceil(len(y)/R)

Return type:

np.ndarray

Logging

By default, the log-level is set to INFO which results in a moderate amount of logging information. The logging can be turned off by running logging_disable() and turned back on by running logging_enable(). You can also set the log-level to DEBUG or WARN by running logging_set_level().

pypillometry.logging_set_level(level='INFO')[source]

Set the logging level for all pypillometry submodules.

In the case of DEBUG, the logging for cmdstanpy is also enabled.

Parameters:

level (str) – The logging level. Can be one of “DEBUG”, “INFO”, “WARNING”, “ERROR”, “CRITICAL”.

pypillometry.logging_disable()[source]

Disable logging for all pypillometry submodules.

pypillometry.logging_enable()[source]

Enable logging for all pypillometry submodules.

Modules

io.py

Read/Write data from/to disk.

pypillometry.io.load_study_local(path, config_file='pypillometry_conf.py', subjects=None)[source]

Read a study from a local directory using the configuration file.

The configuration file must define a dict raw_data (subject ID -> dict of data files, relative to path) and a function read_subject(info) that returns the data for one subject; it is called with the working directory changed to path.

Parameters:
  • path (str) – Local path where the study data is stored

  • config_file (str) – Name of the configuration file. Default is “pypillometry_conf.py”. It is first looked up in the current working directory and, if not found there, in path.

  • subjects (list[str]) – List of subject IDs to load. If None, all subjects will be loaded. If a subject ID is provided that doesn’t exist in the data, it will be skipped.

Returns:

  • study_data (dict) – Dictionary containing the loaded study data (subject ID -> result of read_subject)

  • config (module) – Module containing the configuration (pypillometry_conf.py imported as a module)

pypillometry.io.load_study_osf(osf_id, path, subjects=None, force_download=False, config_file='pypillometry_conf.py', session=None)[source]

Read a study from OSF using the configuration file. Example: https://osf.io/p2u74/

The configuration file (downloaded from the project) must define a dict raw_data (subject ID -> dict of data files) and a function read_subject(info) that returns the data for one subject. The listing of the project’s files is cached in path/info_osf.pkl and data files are only downloaded if they are not yet in path.

Parameters:
  • osf_id (str) – The OSF project ID

  • path (str) – Local path where files should be downloaded/stored

  • subjects (list[str]) – List of subject IDs to load. If None, all subjects will be loaded. If a subject ID is provided that doesn’t exist in the data, it will be skipped.

  • force_download (bool) – If True, force re-download (including the file listing) even if files exist locally. Default False.

  • config_file (str) – Name of the configuration file. Default is “pypillometry_conf.py”

  • session (Optional[Session]) – Authenticated session for accessing private projects. If None, uses unauthenticated requests.

Returns:

  • study_data (dict) – Dictionary containing the loaded study data (subject ID -> result of read_subject)

  • config (module) – Module containing the configuration (pypillometry_conf.py imported as a module)

pypillometry.io.osf_authenticate(access_token, validate=True, session=None, timeout=10.0)[source]

Authenticate against the OSF API using a personal access token.

Parameters:
  • access_token (str) – Personal access token generated on OSF.

  • validate (bool) – If True (default), verify the token by calling /v2/users/me/.

  • session (Optional[Session]) – Existing session to configure. If None, a new session is created.

  • timeout (float) – Timeout (in seconds) for the validation request when validate is True.

Returns:

Session configured with the OSF bearer token.

Return type:

Session

Raises:

ValueError – If no access token is provided or validation fails.

Read an Eyelink file/URL and return the object returned by the “eyelinkio” package.

Requires the optional package eyelinkio. Its console output is only shown when the log level is “DEBUG”.

Parameters:
  • source (str) – filename of the Eyelink EDF file or URL (OSF client URLs such as https://osf.io/<id> are converted to download URLs)

  • cache_file (str) – filename to cache the file in case it is downloaded from a URL; if None, the file is downloaded to a temporary file

  • force_download (bool) – if True, force re-download even if cache_file exists locally

  • session (Optional[Session]) – requests session to use for the download (e.g., from osf_authenticate() for private projects)

Returns:

object returned by eyelinkio.read_edf()

Return type:

eyelinkio.EDF

See also

pypillometry.GenericEyeData.from_eyelink

create an eyedata object from an EDF file

pypillometry.io.read_pickle(fname)[source]

Read a Python object from a file using pickle.

Parameters:

fname (str) – filename or URL to load data from (URLs are downloaded into memory, without authentication)

Returns:

loaded object

Return type:

object

pypillometry.io.write_pickle(obj, fname)[source]

Store any Python object in a file using pickle.

Parameters:
  • obj (object) – object to save

  • fname (str) – filename to save to

example_data.py

Example datasets for pypillometry.

This module provides example datasets for pypillometry. The datasets are used in the documentation and for testing purposes. Most of them are stored on OSF: https://osf.io/p2u74/

pypillometry.example_data.get_available_datasets()[source]

Return available example datasets.

Returns a dictionary that displays as a nicely formatted pandas DataFrame in Jupyter notebooks but can be used as a normal dict otherwise.

Returns:

A dictionary (subclass of dict) containing all dataset metadata. When displayed in Jupyter, it will render as a pandas DataFrame with columns for Dataset name, Type, and Description.

Return type:

DatasetDict

Examples

>>> datasets = get_available_datasets()
>>> # In Jupyter, this displays as a nice DataFrame
>>> datasets
>>> # But you can still use it like a normal dict
>>> datasets['rlmw_002']
pypillometry.example_data.get_example_data(key)[source]

Load example data for a given example (see example_datasets).

Parameters:

key (str) – Key of the example dataset. Available keys are in the dictionary example_datasets.

Returns:

The example dataset as an EyeData, GazeData or PupilData object.

Return type:

EyeData, GazeData or PupilData

Indices and tables