def read_idf(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = {'Sfix':[],'Ssac':[],'Sblk':[],'Efix':[],'Esac':[],'Eblk':[],'msg':[]} starttime = 0 started = False trialend = False filestarted = False # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n','').replace('\r','').split('\t') # check if the line starts with '##' (denoting header) if '##' in line[0]: # skip processing continue elif '##' not in line[0] and not filestarted: # check the indexes for several key things we want to extract # (we need to do this, because ASCII outputs of the IDF reader # are different, based on whatever the user wanted to extract) timei = line.index("Time") typei = line.index("Type") msgi = -1 xi = {'L':None, 'R':None} yi = {'L':None, 'R':None} sizei = {'L':None, 'R':None} if "L POR X [px]" in line: xi['L'] = line.index("L POR X [px]") if "R POR X [px]" in line: xi['R'] = line.index("R POR X [px]") if "L POR Y [px]" in line: yi['L'] = line.index("L POR Y [px]") if "R POR Y [px]" in line: yi['R'] = line.index("R POR Y [px]") if "L Dia X [px]" in line: sizei['L'] = line.index("L Dia X [px]") if "R Dia X [px]" in line: sizei['R'] = line.index("R Dia X [px]") # set filestarted to True, so we don't attempt to extract # this info on all consecutive lines filestarted = True # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[typei] == 'MSG' and stop in line[msgi]) or i == len(raw)-1: started = False trialend = True # check for new start otherwise else: if start in line or i == len(raw)-1: started = True trialend = True # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data),len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events']['Eblk'] = blink_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) trial['events']['Sfix'], trial['events']['Efix'] = fixation_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) trial['events']['Ssac'], trial['events']['Esac'] = saccade_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = {'Sfix':[],'Ssac':[],'Sblk':[],'Efix':[],'Esac':[],'Eblk':[],'msg':[]} trialend = False # check if the current line contains start message else: if line[typei] == "MSG": if start in line[msgi]: message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(line[timei]) # # # # # # parse line if started: # message lines will usually start with a timestamp, followed # by 'MSG', the trial number and the actual message, e.g.: # "7818328012 MSG 1 # Message: 3" if line[typei] == "MSG": t = int(line[timei]) # time m = line[msgi] # message events['msg'].append([t,m]) # regular lines will contain tab separated values, beginning with # a timestamp, follwed by the values that were chosen to be # extracted by the IDF converter else: # see if current line contains relevant data try: # extract data on POR and pupil size for var in ['x', 'y', 'size']: exec("vi = %si" % var) exec("v = %s" % var) # nothing if vi['L'] == None and vi['R'] == None: val = 'not in IDF' # only left eye elif vi['L'] != None and vi['R'] == None: val = float(line[vi['L']]) # only right eye elif vi['L'] == None and vi['R'] != None: val = float(line[vi['R']]) # average the two eyes, but only if they both # contain valid data elif vi['L'] != None and vi['R'] != None: if float(line[vi['L']]) == 0: val = float(line[vi['R']]) elif float(line[vi['R']]) == 0: val = float(line[vi['L']]) else: val = (float(line[vi['L']]) + float(line[vi['R']])) / 2.0 v.append(val) # extract time data time.append(int(line[timei])-starttime) trackertime.append(int(line[timei])) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data
def read_eyetribe(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = {'Sfix':[],'Ssac':[],'Sblk':[],'Efix':[],'Esac':[],'Eblk':[],'msg':[]} starttime = 0 started = False trialend = False # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n','').replace('\r','').split('\t') # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[0] == 'MSG' and stop in line[3]) or i == len(raw)-1: started = False trialend = True # check for new start otherwise else: if start in line: started = True trialend = True # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data),len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events']['Eblk'] = blink_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) trial['events']['Sfix'], trial['events']['Efix'] = fixation_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) trial['events']['Ssac'], trial['events']['Esac'] = saccade_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = {'Sfix':[],'Ssac':[],'Sblk':[],'Efix':[],'Esac':[],'Eblk':[],'msg':[]} trialend = False # check if the current line contains start message else: if line[0] == "MSG": if start in line[3]: message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(line[2]) # # # # # # parse line if started: # message lines will start with MSG, followed by a tab, then a # timestamp, a tab, the time, a tab and the message, e.g.: # "MSG\t2014-07-01 17:02:33.770\t853589802\tsomething of importance here" if line[0] == "MSG": t = int(line[2]) # time m = line[3] # message events['msg'].append([t,m]) # regular lines will contain tab separated values, beginning with # a timestamp, follwed by the values that were asked to be stored # in the data file. Usually, this comes down to # timestamp, time, fix, state, rawx, rawy, avgx, avgy, psize, # Lrawx, Lrawy, Lavgx, Lavgy, Lpsize, Lpupilx, Lpupily, # Rrawx, Rrawy, Ravgx, Ravgy, Rpsize, Rpupilx, Rpupily # e.g.: # '2014-07-01 17:02:33.770, 853589802, False, 7, 512.5897, 510.8104, 614.6975, 614.3327, 16.8657, # 523.3592, 475.2756, 511.1529, 492.7412, 16.9398, 0.4037, 0.5209, # 501.8202, 546.3453, 609.3405, 623.2287, 16.7916, 0.5539, 0.5209' else: # see if current line contains relevant data try: # extract data x.append(float(line[6])) y.append(float(line[7])) size.append(float(line[8])) time.append(int(line[1])-starttime) trackertime.append(int(line[1])) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data
def read_eyetribe(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } starttime = 0 started = False trialend = False # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n', '').replace('\r', '').split('\t') # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[0] == 'MSG' and stop in line[3]) or i == len(raw) - 1: started = False trialend = True # check for new start otherwise else: if start in line: started = True trialend = True # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data), len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events'][ 'Eblk'] = blink_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Sfix'], trial['events'][ 'Efix'] = fixation_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Ssac'], trial['events'][ 'Esac'] = saccade_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } trialend = False # check if the current line contains start message else: if line[0] == "MSG": if start in line[3]: message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(line[2]) # # # # # # parse line if started: # message lines will start with MSG, followed by a tab, then a # timestamp, a tab, the time, a tab and the message, e.g.: # "MSG\t2014-07-01 17:02:33.770\t853589802\tsomething of importance here" if line[0] == "MSG": t = int(line[2]) # time m = line[3] # message events['msg'].append([t, m]) # regular lines will contain tab separated values, beginning with # a timestamp, follwed by the values that were asked to be stored # in the data file. Usually, this comes down to # timestamp, time, fix, state, rawx, rawy, avgx, avgy, psize, # Lrawx, Lrawy, Lavgx, Lavgy, Lpsize, Lpupilx, Lpupily, # Rrawx, Rrawy, Ravgx, Ravgy, Rpsize, Rpupilx, Rpupily # e.g.: # '2014-07-01 17:02:33.770, 853589802, False, 7, 512.5897, 510.8104, 614.6975, 614.3327, 16.8657, # 523.3592, 475.2756, 511.1529, 492.7412, 16.9398, 0.4037, 0.5209, # 501.8202, 546.3453, 609.3405, 623.2287, 16.7916, 0.5539, 0.5209' else: # see if current line contains relevant data try: # extract data x.append(float(line[6])) y.append(float(line[7])) size.append(float(line[8])) time.append(int(line[1]) - starttime) trackertime.append(int(line[1])) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data
def read_opengaze(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # Parse the header. header = raw.pop(0) header = header.replace('\n', '').replace('\r', '').split('\t') # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } starttime = 0 started = False trialend = False laststart = None # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n', '').replace('\r', '').split('\t') # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[header.index("USER")] != '0' and \ stop in line[header.index("USER")]) \ or i == len(raw)-1: started = False trialend = True # check for new start otherwise else: if start in line[header.index("USER")] \ or i == len(raw)-1: # Only start if the current start is more than 1 # sample away from the previous start. if (laststart == None) or (i != laststart + 1): started = True trialend = True laststart = i # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data), len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events'][ 'Eblk'] = blink_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Sfix'], trial['events'][ 'Efix'] = fixation_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Ssac'], trial['events'][ 'Esac'] = saccade_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } trialend = False # check if the current line contains start message else: if line[header.index("USER")] != '0': if start in line[header.index("USER")]: # Only start if the current start is more than 1 # sample away from the previous start. if (laststart == None) or (i != laststart + 1): message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(1000 * float(line[header.index("TIME")])) laststart = i # # # # # # parse line if started: # Messages are encoded in the user variable, which otherwise # is '0'. NOTE: Sometimes messages repeat in consecutive # samples, by accident. if line[header.index("USER")] != '0': t = int(1000 * float(line[header.index("TIME")])) # time m = line[header.index("USER")] # message events['msg'].append([t, m]) # All lines (when obtained through PyOpenGaze or PyGaze) # should contain the following data: # CNT, TIME, TIME_TICK, # FPOGX, FPOGY, FPOGS, FPOGD, FPOGID, FPOGV, # LPOGX, LPOGY, LPOGV, RPOGX, RPOGY, RPOGV, # BPOGX, BPOGY, BPOGV, # LPCX, LPCY, LPD, LPS, LPV, RPCX, RPCY, RPD, RPS, RPV # LEYEX, LEYEY, LEYEZ, LPUPILD, LPUPILV, # REYEX, REYEY, REYEZ, RPUPILD, RPUPILV, # CX, CY, CS, USER try: # Compute the size of the pupil. left = line[header.index("LPV")] == '1' right = line[header.index("RPV")] == '1' if left and right: s = (float(line[header.index("LPD")]) + \ float(line[header.index("RPD")])) / 2.0 elif left and not right: s = float(line[header.index("LPD")]) elif not left and right: s = float(line[header.index("RPD")]) else: s = 0.0 # extract data x.append(float(line[header.index("BPOGX")])) y.append(float(line[header.index("BPOGY")])) size.append(s) time.append( int(1000 * float(line[header.index("TIME")])) - starttime) trackertime.append( int(1000 * float(line[header.index("TIME")]))) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data
# # # # # # # # # # # # # # USER MESSAGES (I.E. TRIGGERS) # # # # # # # # # # # # # df_triggers = df[df['Event'].notnull()] # Only when Events is not blank. df_triggers['starttime'] = df_triggers['TimeStamp'] df_triggers['label'] = 'message' df_triggers = df_triggers[['starttime', 'Event', 'label']] # # # # # # # # # # # # # # BLINKS # # # # # # # # # # # # # # For tobii, missing = -1. blinks = detectors.blink_detection(x, y, time, missing=-1, minlen=10) Eblk = blinks[1] df_blk = pd.DataFrame(Eblk, columns=['starttime', 'endtime', 'duration']) df_blk['label'] = 'blink' # # # # # # # # # # # # # # OUTPUT # # # # # # # # # # # # # df_metrics = df_triggers.append([df_fix, df_sac, df_blk], ignore_index=True, sort=False) # Append all dataframes. df_metrics = df_metrics.sort_values(by=['starttime' ]) # Sort by starttime (= timestamp). df_metrics = df_metrics.reset_index(drop=True) # Reset the index.
def read_idf(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } starttime = 0 started = False trialend = False filestarted = False # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n', '').replace('\r', '').split('\t') # check if the line starts with '##' (denoting header) if '##' in line[0]: # skip processing continue elif '##' not in line[0] and not filestarted: # check the indexes for several key things we want to extract # (we need to do this, because ASCII outputs of the IDF reader # are different, based on whatever the user wanted to extract) timei = line.index("Time") typei = line.index("Type") msgi = -1 xi = {'L': None, 'R': None} yi = {'L': None, 'R': None} sizei = {'L': None, 'R': None} if "L POR X [px]" in line: xi['L'] = line.index("L POR X [px]") if "R POR X [px]" in line: xi['R'] = line.index("R POR X [px]") if "L POR Y [px]" in line: yi['L'] = line.index("L POR Y [px]") if "R POR Y [px]" in line: yi['R'] = line.index("R POR Y [px]") if "L Dia X [px]" in line: sizei['L'] = line.index("L Dia X [px]") if "R Dia X [px]" in line: sizei['R'] = line.index("R Dia X [px]") # set filestarted to True, so we don't attempt to extract # this info on all consecutive lines filestarted = True # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[typei] == 'MSG' and stop in line[msgi]) or i == len(raw) - 1: started = False trialend = True # check for new start otherwise else: if start in line or i == len(raw) - 1: started = True trialend = True # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data), len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events'][ 'Eblk'] = blink_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Sfix'], trial['events'][ 'Efix'] = fixation_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Ssac'], trial['events'][ 'Esac'] = saccade_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } trialend = False # check if the current line contains start message else: if line[typei] == "MSG": if start in line[msgi]: message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(line[timei]) # # # # # # parse line if started: # message lines will usually start with a timestamp, followed # by 'MSG', the trial number and the actual message, e.g.: # "7818328012 MSG 1 # Message: 3" if line[typei] == "MSG": t = int(line[timei]) # time m = line[msgi] # message events['msg'].append([t, m]) # regular lines will contain tab separated values, beginning with # a timestamp, follwed by the values that were chosen to be # extracted by the IDF converter else: # see if current line contains relevant data try: # extract data on POR and pupil size for var in ['x', 'y', 'size']: exec("vi = %si" % var) exec("v = %s" % var) # nothing if vi['L'] == None and vi['R'] == None: val = 'not in IDF' # only left eye elif vi['L'] != None and vi['R'] == None: val = float(line[vi['L']]) # only right eye elif vi['L'] == None and vi['R'] != None: val = float(line[vi['R']]) # average the two eyes, but only if they both # contain valid data elif vi['L'] != None and vi['R'] != None: if float(line[vi['L']]) == 0: val = float(line[vi['R']]) elif float(line[vi['R']]) == 0: val = float(line[vi['L']]) else: val = (float(line[vi['L']]) + float(line[vi['R']])) / 2.0 v.append(val) # extract time data time.append(int(line[timei]) - starttime) trackertime.append(int(line[timei])) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data
def read_opengaze(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # Parse the header. header = raw.pop(0) header = header.replace('\n','').replace('\r','').split('\t') # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = {'Sfix':[],'Ssac':[],'Sblk':[],'Efix':[],'Esac':[],'Eblk':[],'msg':[]} starttime = 0 started = False trialend = False laststart = None # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n','').replace('\r','').split('\t') # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[header.index("USER")] != '0' and \ stop in line[header.index("USER")]) \ or i == len(raw)-1: started = False trialend = True # check for new start otherwise else: if start in line[header.index("USER")] \ or i == len(raw)-1: # Only start if the current start is more than 1 # sample away from the previous start. if (laststart == None) or (i != laststart + 1): started = True trialend = True laststart = i # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data),len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events']['Eblk'] = blink_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) trial['events']['Sfix'], trial['events']['Efix'] = fixation_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) trial['events']['Ssac'], trial['events']['Esac'] = saccade_detection(trial['x'],trial['y'],trial['trackertime'],missing=missing) # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = {'Sfix':[],'Ssac':[],'Sblk':[],'Efix':[],'Esac':[],'Eblk':[],'msg':[]} trialend = False # check if the current line contains start message else: if line[header.index("USER")] != '0': if start in line[header.index("USER")]: # Only start if the current start is more than 1 # sample away from the previous start. if (laststart == None) or (i != laststart + 1): message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(1000 * float(line[header.index("TIME")])) laststart = i # # # # # # parse line if started: # Messages are encoded in the user variable, which otherwise # is '0'. NOTE: Sometimes messages repeat in consecutive # samples, by accident. if line[header.index("USER")] != '0': t = int(1000 * float(line[header.index("TIME")])) # time m = line[header.index("USER")] # message events['msg'].append([t,m]) # All lines (when obtained through PyOpenGaze or PyGaze) # should contain the following data: # CNT, TIME, TIME_TICK, # FPOGX, FPOGY, FPOGS, FPOGD, FPOGID, FPOGV, # LPOGX, LPOGY, LPOGV, RPOGX, RPOGY, RPOGV, # BPOGX, BPOGY, BPOGV, # LPCX, LPCY, LPD, LPS, LPV, RPCX, RPCY, RPD, RPS, RPV # LEYEX, LEYEY, LEYEZ, LPUPILD, LPUPILV, # REYEX, REYEY, REYEZ, RPUPILD, RPUPILV, # CX, CY, CS, USER try: # Compute the size of the pupil. left = line[header.index("LPV")] == '1' right = line[header.index("RPV")] == '1' if left and right: s = (float(line[header.index("LPD")]) + \ float(line[header.index("RPD")])) / 2.0 elif left and not right: s = float(line[header.index("LPD")]) elif not left and right: s = float(line[header.index("RPD")]) else: s = 0.0 # extract data x.append(float(line[header.index("BPOGX")])) y.append(float(line[header.index("BPOGY")])) size.append(s) time.append(int(1000 * float(line[header.index("TIME")]))-starttime) trackertime.append(int(1000 * float(line[header.index("TIME")]))) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data