Source code for pyutils_sh.gaze

"""
Functions for calculating various gaze/eye-tracking related statistics.
"""

import numpy as np


[docs]def cross_correlation(person1, person2, framerate=25, constrain_seconds=2): """ Calculate cross-correlation between two gaze signals. This function takes 2 lists/arrays of data, each containing an individual's coded gaze data from an eye-tracker, and calculates the normalized max cross-correlation value with its associated lag. Additionally, it will also return the cross-correlation value at 0 lag, as well as the entire normalized array as a Python list. Negative lag value means person2 lagged behind person1 by x frames e.g. A = [0,1,1,1,0,0,0] B = [0,0,0,1,1,1,0] cross_correlation(A,B) Positive lag value means person1 lagged behind person2 by x frames e.g. A = [0,0,0,1,1,1,0] B = [0,1,1,1,0,0,0] cross_correlation(A,B) Parameters ---------- person1 : ndarray or list 1D array of person 1's gaze over time, coded as 0 = not looking, 1 = looking. The values represent whether the person was looking at a target at a particular point in time. person2 : ndarray or list 1D array of person 2's gaze over time, coded as 0 = not looking, 1 = looking. The values represent whether the person was looking at a target at a particular point in time. framerate : int, optional The framerate (frames per second) of the eye-tracker. constrain_seconds : int, optional Number of seconds to constrain the cross-correlation values by. The returned lags and cross-correlations will be centered around 0 lag by this many seconds. Returns ------- max_R : float Maximum (normalized) cross-correlation value. max_lag_adj : float Lag at which max cross-correlation occurs. zero_R : float Cross-correlation value at 0 lag. norm_array : list A list of all (normalized) cross-correlation values. """ # convert lists to numpy arrays x = np.array(person1) y = np.array(person2) # calculate cross correlation values correlations = np.correlate(x, y, "full") # trim the cross-correlation values to a range (-lag_limits : +lag_limits) # trim AFTER cross correlation calculation to avoid 0 padding of signals # assumes x and y are equal length lag_limits = constrain_seconds * framerate trimmed_correlations = correlations[len(x) - 1 - lag_limits : len(x) + lag_limits] # normalize the cross-correlation values for ease of comparison between # subjects norm_array = trimmed_correlations / (np.linalg.norm(x) * np.linalg.norm(y)) # get maximum normalized cross-correlation value max_R = max(norm_array) # get lag of max correlation value max_lag = np.argmax(norm_array) # trimmed array is now 2*(lag_limits)+1 elements long # adjust it so that lag 0 is a complete match max_lag_adj = max_lag - lag_limits # Get the normalized zero lag correlation value zero_R = norm_array[lag_limits] return float(max_R), float(max_lag_adj), float(zero_R), norm_array.tolist()