def getDM(exp, driftCorr = True, excludeErrors = True, saccTooFast = None, saccTooSlow = None,\ rtTooFast = None, rtTooSlow = None, rtVar = 'rtFromStim', \ exclFailedChecks = True, \ fixCheck1TooLong = 1000, fixCheck2TooLong = 1000, cutoffHeavy = 0, \ onlyControl = True, excludeFillers = True): """ Applies several exclusion criteria to obtain a filtered dm. Arguments: dm --- data matrix exp --- {"004A", "004B"}, string indicating whether first or second experiment is analysed Keyword arguments: excludeErrors --- Boolean indicating whether error trials should be excluded. Default = False. saccTooFast --- Cutoff for exclusion of too-fast saccades. Set to None to deactivate this filter. Default = 80. saccTooSlow --- Cutoff for exclusion of too-slow saccades. Set to None to deactivate this filter. rtTooFast --- Cutoff for exclusion of too-fast RTs. Set to None to deactivate this filter. rtTooSlow --- Cutoff for exclusion of too-slow RTs. Set to None to deactivate this filter. rtVar --- rt variable to use for excluding too fast and/or too slow response times. exclFailedChecks --- Boolean indicating whether or not to excude trials on which one or more fix checks failed. Default = False fixCheckTooLong1 --- Cutoff for excluding too long fixation checks. Set to None to deactivate this filter. Default = 700, based on looking at plt.hist(dm['durCheck1']) fixCheckTooLong2 --- Cutoff for excluding too long fixation check on object. Set to None to deactivate. Default = 450, based on looking at plt.hist(dm['durCheck2']) drifCorr --- cutoffHeavy --- minimum deviation necessary to indicate one side of the object as heavier. In px. Default = 8. onlyControl --- indicates whether only trials in which manipulation was not manipulated, should be included. Default = True. excludeFillers --- Default = True. """ if driftCorr: fName = "selected_dm_%s_WITH_drift_corr.csv" % exp else: fName = "selected_dm_%s_NO_drift_corr.csv" % exp if exp == "004C": data = "./dm_004C_simulation.csv" a = np.genfromtxt(data, dtype=None, delimiter=",") dm = DataMatrix(a) # Add some important column headers: dm = dm.addField("file", dtype = str) dm = dm.addField("accuracy") dm = dm.addField("contrast_side", dtype = str) dm["file"] = "simulation" dm["accuracy"] = 1 dm["contrast_side"] = "test" dm["contrast_side"][np.where(dm["mask_side"] == "right")] = "_left" dm["contrast_side"][np.where(dm["mask_side"] == "control")] = "control" dm["contrast_side"][np.where(dm["mask_side"] == "left")] = "right" else: dm = ascParser.parseAsc(exp = exp, driftCorr = driftCorr) # Start by applying some general selections (such that # the reported exclusion percentages will not differ depending # on when you execute those): # Exclude practice trials: dm = dm.select("rep != 'practice'") # For the second experiment, exclude Dash and Sebastiaan: if exp == "004B": # Exclude Sebastiaan: dm = dm.select('file != "00401.asc"') # Exclude Dash because he's left handed: dm = dm.select('file != "00402.asc"') if onlyControl: dm = dm.select("mask_side == 'control'") if excludeFillers: dm = dm.select("symm == 'asymm'") if excludeErrors: dm = dm.select('accuracy == 1') # 'Real' selections: # During parsing, tirals on which the variable 'response' did not contain # an int were given the value -1. Otherwise the dm will make all the # 'response' values strings. Therefore, start by excluding those eventual # -1's: dm = dm.select("response != -1") # Remove all trials on which saccLat1 doesn't have a value: dm = dm.select("saccLat1 != ''") # Negative initial saccade latencies should not happen: dm = dm.select('saccLat1 > 0.') # Add column header indicating whether drift correction was used: dm = dm.addField("driftCorr", dtype = str) dm["driftCorr"] = driftCorr # Add a column header indicating which experiment is analysed: dm = dm.addField("exp", dtype = str) dm["exp"] = exp # Add variable indicating whether CoG is to the left or to the # right: # For objects with handle right, and without mask applied: # - negative xCoG means: heavier on the left # - pos means: heavier on the right dm = dm.addField('heavySide', dtype = str) dm["heavySide"] = 'control' dm["heavySide"][np.where(dm["xCoG"] >= cutoffHeavy)] = 'right__' dm["heavySide"][np.where(dm["xCoG"] <= -cutoffHeavy)] = 'left__' # Some stuff we can't do for the simulation, because those columns don't # exist: if exp != "004C": # Add variable indicating experimental half (first or second): dm = dm.addField("half", dtype = str) dm["half"] = "first" dm["half"][np.where(dm["block_count"] >= 3)] = "second" if saccTooFast != None: dm = dm.select('saccLat1 > %s'%saccTooFast) if saccTooSlow != None: dm = dm.select('saccLat1 < %s'%saccTooSlow) if rtTooFast != None: dm = dm.select('%s > %s'%(rtVar,rtTooFast)) if rtTooSlow != None: dm = dm.select('%s < %s'%(rtVar,rtTooSlow)) # Filter on screen coordinates: # Y: if exp != "004C": dm = dm.select("endYRaw1 < %s" % constants.screenH) dm = dm.select("endYRaw1 > 0") # X: dm = dm.select("endXRaw1 < %s" % constants.screenW) dm = dm.select("endXRaw1 > 0") # Re-code initial y coordinates such that we can use one cutoff # for both upwards and downwards saccade to see whether they were in # the right direction (i.e. > center coordinate): dm = dm.addField("sacc_dir") dm["sacc_dir"] = dm["endYRaw1"] dm["sacc_dir"][dm.where("visual_field == 'upper'")] = \ dm["endYRaw1"][dm.where("visual_field == 'upper'")]+\ constants.yCen # Select saccades that were in the right vertical direction: dm.select("sacc_dir > %s" % str(constants.yCen)) # Exclude trials on which a fixation check failed or took too long: if exp == "004A": if exclFailedChecks: # Note why those will probably never lead to exclusions anymore: # in those cases durCheck1 or durCheck2 would have the value -1000 (because they # couldnt be calculated) and therefore are already excluded above. dm = dm.select('checkFixDotFailed == "False"') dm = dm.select('checkObjectFailed == "False"') if fixCheck1TooLong != None: dm = dm.select('durCheck1 < %s' % fixCheck1TooLong) if fixCheck2TooLong != None: dm = dm.select('durCheck2 < %s' % fixCheck2TooLong) if exp != "004C": # Negative new RT's should not happen: dm = dm.select('rtFromStim > 0') dm.save(fName) return dm
def getDM(driftCorr, excludeErrors = False, saccTooFast = 80, saccTooSlow = None,\ rtTooFast = None, rtTooSlow = None, rtVar = 'rtFromStim'): """ Applies several exclusion criteria to obtain a filtered dm. Arguments: dm --- data matrix Keyword arguments: excludeErrors --- Boolean indicating whether error trials should be excluded. Default = False. saccTooFast --- Cutoff for exclusion of too-fast saccades. Set to None to deactivate this filter. Default = 80. saccTooSlow --- Cutoff for exclusion of too-slow saccades. Set to None to deactivate this filter. rtTooFast --- Cutoff for exclusion of too-fast RTs. Set to None to deactivate this filter. rtTooSlow --- Cutoff for exclusion of too-slow RTs. Set to None to deactivate this filter. rtVar --- rt variable to use for excluding too fast and/or too slow response times. drifCorr --- """ # Declare constants: #src = '/home/lotje/python-libs/studies/_004' if driftCorr: fName = "selected_dm_WITH_drift_corr.csv" else: fName = "selected_dm_NO_drift_corr.csv" if '--shortcut' in sys.argv: a = np.genfromtxt(fName, dtype=None, delimiter=",") dm = DataMatrix(a) #dm = CsvReader(fName, delimiter=',').dataMatrix() return dm dm = ascParser004B.parseAsc(driftCorr = driftCorr) # Exclude Sebastiaan: dm = dm.select('file != "00401.asc"') # Exclude Dash because he's left handed: dm = dm.select('file != "00402.asc"') # Add column header indicating whether drift correction was used: dm = dm.addField("driftCorr", dtype = str) dm["driftCorr"] = driftCorr # Make a new variable (instead of 'mask_side') that indicates the # highest contrast side: dm = dm.addField('contrast_side', dtype = str) dm['contrast_side'][np.where(dm['mask_side'] == "right")] = "_left" dm['contrast_side'][np.where(dm['mask_side'] == "left")] = "right" dm['contrast_side'][np.where(dm['mask_side'] == "control")] = "control" # Add variable indicating whether CoG is to the left or to the # right: # For objects with handle right, and without mask applied: # - negative xCoG means: heavier on the left # - pos means: heavier on the right dm = dm.addField('heavySide', dtype = str) dm["heavySide"] = 'left' dm["heavySide"][np.where(dm["xCoG"] >= 0)] = 'right' # Add variable indicating experimental half (first or second): dm = dm.addField("half", dtype = str) dm["half"] = "first" dm["half"][np.where(dm["block_count"] >= 3)] = "second" # Exclude practice trials: dm = dm.select("rep != 'practice'") # During parsing, tirals on which the variable 'response' did not contain # an int were given the value -1. Otherwise the dm will make all the # 'response' values strings. Therefore, start by excluding those eventual # -1's: dm = dm.select("response != -1") # Saccade latencies of 0 (or -1) should not happen: # If no saccade is detected during a trial, 'saccLat' is changed from -1000 # to -1 during parsing: dm = dm.select('saccLat1 > 0') # Negative new RT's should not happen: dm = dm.select('rtFromStim > 0') # Add values indicating whether the eyes landed towards the handle (positive # values) or towards the other side of the object (negative values): # Also, make sure all values are eventually converted to visual degrees: # If first landing position is empty, skip the trial: dm = dm.select("endX1 != ''") # Without any correction: dm = dm.addField("pxTowardsHandle") dm = dm.addField("degrTowardsHandle") indicesRight = np.where(dm["handle_side"] == 'right') indicesLeft = np.where(dm["handle_side"] == 'left') dm["pxTowardsHandle"][indicesRight] = (dm["endX1"][indicesRight]) dm["pxTowardsHandle"][indicesLeft] = dm["endX1"][indicesRight]*-1 dm["degrTowardsHandle"] = dm["pxTowardsHandle"]/studies._004.constants.ratioPxDegr ## With CoG correction based on the original bitmap (without mask): #dm = dm.addField("pxTowardsHandleCorr") #dm = dm.addField("degrTowardsHandleCorr") #indicesRight = np.where(dm["handle_side"] == 'right') #indicesLeft = np.where(dm["handle_side"] == 'left') #dm["pxTowardsHandleCorr"][indicesRight] = (dm["endXCorr"][indicesRight]) #dm["pxTowardsHandleCorr"][indicesLeft] = dm["endXCorr"][indicesRight]*-1 #dm["degrTowardsHandleCorr"] = dm["pxTowardsHandleCorr"]/constants.ratioPxDegr ## Wit CoG correction with taking mask into account:: #dm = dm.addField("pxTowardsHandleCorrMask") #dm = dm.addField("degrTowardsHandleCorrMask") #indicesRight = np.where(dm["handle_side"] == 'right') #indicesLeft = np.where(dm["handle_side"] == 'left') #dm["pxTowardsHandleCorrMask"][indicesRight] = \ #(dm["endXCorrMask"][indicesRight]) #dm["pxTowardsHandleCorrMask"][indicesLeft] = \ #dm["endXCorrMask"][indicesRight]*-1 #dm["degrTowardsHandleCorrMask"] = \ #dm["pxTowardsHandleCorrMask"]/constants.ratioPxDegr # Convert landing positions to visual degrees: dm = dm.addField("endXDegr") #dm = dm.addField("endXCorrDegr") #dm = dm.addField("endXCorrMaskDegr") dm["endXDegr"] = dm["endX1"]/studies._004.constants.ratioPxDegr #dm["endXCorrDegr"] = dm["endXCorr"]/constants.ratioPxDegr #dm["endXCorrMaskDegr"] = dm["endXCorrMask"]/constants.ratioPxDegr # Convert starting position to visual degrees: dm = dm.addField("startX1Degr") dm["startX1Degr"] = dm["startX1"]/studies._004.constants.ratioPxDegr #dm = dm.addField("rtFromLanding") #dm['rtFromLanding'] = dm['rtFromStim']-dm['saccLandingTime1'] if saccTooFast != None: dm = dm.select('saccLat1 > %s'%saccTooFast) if saccTooSlow != None: dm = dm.select('saccLat1 < %s'%saccTooSlow) if rtTooFast != None: dm = dm.select('%s > %s'%(rtVar,rtTooFast)) if rtTooSlow != None: dm = dm.select('%s < %s'%(rtVar,rtTooSlow)) if excludeErrors: dm = dm.select('accuracy == 1') dm.save(fName) return dm