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
GazeDataandPupilDataand 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
eyesandvariablesare inherited fromGenericEyeData.- Parameters:
time (
ndarray) – timing array (in ms) or None, in which case the time-array goes from [0,maxT] using sampling_rateleft_x (
ndarray) – data from left eye (at least one of the eyes must be provided, both x and y) pupil is optionalleft_y (
ndarray) – data from left eye (at least one of the eyes must be provided, both x and y) pupil is optionalleft_pupil (
ndarray) – data from left eye (at least one of the eyes must be provided, both x and y) pupil is optionalright_x (
ndarray) – data from right eye (at least one of the eyes must be provided, both x and y) pupil is optionalright_y (
ndarray) – data from right eye (at least one of the eyes must be provided, both x and y) pupil is optionalright_pupil (
ndarray) – data from right eye (at least one of the eyes must be provided, both x and y) pupil is optionalevent_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 labelsampling_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 originalinfo (
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 (seeset_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:
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
GenericEyeDataobject 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 datainplace (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:
- 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
ForeshorteningCalibrationContainer for fitted parameters
correct_pupil_foreshorteningSimple 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:
- 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).
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
GenericEyeDataand inherits all its methods.If eye-tracking data is available in addition to pupillometry, use the
EyeDataclass.Properties such as
eyesandvariablesare inherited fromGenericEyeData.- Parameters:
time (
ndarray) – timing array (in ms) or None, in which case the time-array goes from [0,maxT] using sampling_rateleft_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 labelsampling_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 originalinfo (
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 (seeset_default_inplace(), initially True). The method-level inplace argument overrides this.
- Attributes:
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
GenericEyeDataobject 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).
- pupil_blinks_detect(eyes=[], min_duration=20, blink_val=0, winsize=11, vel_onset=-5.0, vel_offset=5.0, vel_onset_min_duration=5.0, vel_offset_min_duration=5.0, strategies=['zero', 'velocity'], apply_mask=False, ignore_existing_mask=False, inplace=None)[source]¶
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 blinkblink_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 msvel_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
- pupil_blinks_interpolate(eyes=[], store_as='pupil', method='mahot', winsize=25, vel_onset=-5.0, vel_offset=5.0, margin=(10, 30), blinkwindow=500, interp_type='cubic', inplace=None)[source]¶
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 withget_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 processedstore_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 msvel_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 byscipy.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:
- 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) –“envelope_iter_bspline_1”:
baseline_envelope_iter_bspline()with one iteration”envelope_iter_bspline_2” (default):
baseline_envelope_iter_bspline()with two iterations
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:
- 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 parametertmax (
str|float) – tmax-parameter for the canonical response-function or “free”; in case of “free”, the function optimizes for this parameterverbose (
int) – verbosity level, passed on topupil_response()bounds (
dict) – in case that one or both parameters are estimated, give the lower and upper bounds for the parametersinplace (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:
Notes
The predicted response is stored in
data[eye, "response"]; the estimated parameters (npar, tmax, the coefficients coef and the bounds) are stored inparams["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 Hzorder (
int) – filter ordereyes (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:
- 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:
- 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_eyesGeneric merge method in GenericEyeData (masks if either eye invalid)
pypillometry.signal.pupil.pupil_eye_offsetCompute 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 msinplace (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:
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
EyeDataclass. If you only want to store pupil-size, use thePupilDataclass.Properties such as
eyesandvariablesare inherited fromGenericEyeData.- Parameters:
time (
ndarray) – timing array (in ms) or None, in which case the time-array goes from [0,maxT] using sampling_rateleft_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 labelsampling_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 originalinfo (
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 (seeset_default_inplace(), initially True). The method-level inplace argument overrides this.
- Attributes:
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
GenericEyeDataobject 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
ExperimentalSetupor 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", ... )