diff --git a/data/_demo_eye_tracking_2021_Sep_28_2219.csv b/data/_demo_eye_tracking_2021_Sep_28_2219.csv new file mode 100644 index 0000000000000000000000000000000000000000..44a3ea68bf23576a73f95a0793b7f4ad9623f672 --- /dev/null +++ b/data/_demo_eye_tracking_2021_Sep_28_2219.csv @@ -0,0 +1 @@ +participant,session,date,expName,psychopyVersion,frameRate, diff --git a/data/_demo_eye_tracking_2021_Sep_28_2219.log b/data/_demo_eye_tracking_2021_Sep_28_2219.log new file mode 100644 index 0000000000000000000000000000000000000000..d34b34689a623a2f931bd1008e2992031d83a20b --- /dev/null +++ b/data/_demo_eye_tracking_2021_Sep_28_2219.log @@ -0,0 +1,52 @@ +1.1199 WARNING We strongly recommend you activate the PTB sound engine in PsychoPy prefs as the preferred audio engine. Its timing is vastly superior. Your prefs are currently set to use ['sounddevice', 'PTB', 'pyo', 'pygame'] (in that order). +4.9436 WARNING User requested fullscreen with size [1536 960], but screen is actually [1920, 1080]. Using actual size +9.2275 EXP Created window1 = Window(allowGUI=False, allowStencil=False, autoLog=True, backendConf=UNKNOWN, bitsMode=UNKNOWN, blendMode='avg', bpc=(8, 8, 8), color=array([-1, -1, -1]), colorSpace='rgb', depthBits=8, fullscr=, gamma=None, gammaErrorPolicy='raise', lms=UNKNOWN, monitor=, multiSample=False, name='window1', numSamples=2, pos=[0.0, 0.0], screen=0, size=array([1920, 1080]), stencilBits=0, stereo=False, units='height', useFBO=True, useRetina=False, viewOri=0.0, viewPos=None, viewScale=None, waitBlanking=True, winType='pyglet') +9.2282 EXP window1: mouseVisible = True +9.2283 EXP window1: recordFrameIntervals = False +9.3927 EXP window1: recordFrameIntervals = True +9.5767 EXP window1: recordFrameIntervals = False +9.8129 EXP Created webcamWarning = TextStim(__class__=, alignHoriz=method-wrapper(...), alignText='center', alignVert=method-wrapper(...), anchorHoriz='center', anchorVert='center', antialias=True, autoLog=True, bold=False, color=array([1, 1, 1]), colorSpace='rgb', contrast=1.0, depth=-1.0, flipHoriz=False, flipVert=False, font='Arial', fontFiles=[], height=0.05, italic=False, languageStyle='LTR', name='webcamWarning', opacity=1, ori=0.0, pos=array([0., 0.]), rgb=UNKNOWN, text=str(...), units='height', win=Window(...), wrapWidth=1) +9.8214 EXP Created instruction1Txt = TextStim(__class__=, alignHoriz=method-wrapper(...), alignText='center', alignVert=method-wrapper(...), anchorHoriz='center', anchorVert='center', antialias=True, autoLog=True, bold=False, color=array([1, 1, 1]), colorSpace='rgb', contrast=1.0, depth=-1.0, flipHoriz=False, flipVert=False, font='Arial', fontFiles=[], height=0.05, italic=False, languageStyle='LTR', name='instruction1Txt', opacity=1, ori=0.0, pos=array([0., 0.]), rgb=UNKNOWN, text=str(...), units='height', win=Window(...), wrapWidth=1) +9.8481 EXP Created calibrationTxt = TextStim(__class__=, alignHoriz=method-wrapper(...), alignText='center', alignVert=method-wrapper(...), anchorHoriz='center', anchorVert='center', antialias=True, autoLog=True, bold=False, color=array([1, 1, 1]), colorSpace='rgb', contrast=1.0, depth=0.0, flipHoriz=False, flipVert=False, font='Arial', fontFiles=[], height=0.05, italic=False, languageStyle='LTR', name='calibrationTxt', opacity=1, ori=0.0, pos=array([0., 0.]), rgb=UNKNOWN, text=str(...), units='height', win=Window(...), wrapWidth=1) +9.8482 EXP window1: mouseVisible = True +9.8509 EXP Created calibration_square = Rect(__class__=, autoDraw=False, autoLog=True, closeShape=True, color=method-wrapper(...), colorSpace='rgb', contrast=None, depth=-1.0, fillColor=array([1, 1, 1]), fillColorSpace='rgb', fillRGB=UNKNOWN, interpolate=True, lineColor=array([1, 1, 1]), lineColorSpace='rgb', lineRGB=UNKNOWN, lineWidth=1.0, name='calibration_square', opacity=1, ori=0.0, pos=array([0., 0.]), size=array([0.02, 0.02]), units='height', vertices=ndarray(...), win=Window(...)) +9.8510 EXP window1: mouseVisible = True +9.8523 EXP Created polygon = ShapeStim(__class__=, autoDraw=False, autoLog=True, closeShape=True, color=method-wrapper(...), colorSpace='rgb', contrast=None, depth=-1.0, fillColor=array([1, 1, 1]), fillColorSpace='rgb', fillRGB=UNKNOWN, interpolate=True, lineColor=array([1, 1, 1]), lineColorSpace='rgb', lineRGB=UNKNOWN, lineWidth=1.0, name='polygon', opacity=1, ori=0.0, pos=array([0., 0.]), size=array([1., 1.]), units='height', vertices=ndarray(...), win=Window(...), windingRule=None) +9.8533 EXP Created tracking_square = Rect(__class__=, autoDraw=False, autoLog=True, closeShape=True, color=method-wrapper(...), colorSpace='rgb', contrast=None, depth=-2.0, fillColor=array([1, 1, 1]), fillColorSpace='rgb', fillRGB=UNKNOWN, interpolate=True, lineColor=array([1, 1, 1]), lineColorSpace='rgb', lineRGB=UNKNOWN, lineWidth=1.0, name='tracking_square', opacity=1, ori=0.0, pos=array([0., 0.]), size=array([0.02, 0.02]), units='height', vertices=ndarray(...), win=Window(...)) +9.8668 EXP Created trackingTxt = TextStim(__class__=, alignHoriz=method-wrapper(...), alignText='center', alignVert=method-wrapper(...), anchorHoriz='center', anchorVert='center', antialias=True, autoLog=True, bold=False, color=array([1, 1, 1]), colorSpace='rgb', contrast=1.0, depth=-3.0, flipHoriz=False, flipVert=False, font='Arial', fontFiles=[], height=0.05, italic=False, languageStyle='LTR', name='trackingTxt', opacity=1, ori=0.0, pos=array([0., 0.]), rgb=UNKNOWN, text=str(...), units='height', win=Window(...), wrapWidth=1) +9.8991 EXP webcamWarning: autoDraw = True +11.7167 DATA Keypress: space +13.8775 DATA Keypress: space +21.8251 DATA Keypress: space +22.0103 DATA Keypress: space +22.1913 DATA Keypress: space +37.0699 DATA Mouse: Left button down, pos=(1010,575) +37.1536 DATA Mouse: Left button up, pos=(1010,575) +38.2212 DATA Mouse: Left button down, pos=(986,527) +38.2869 DATA Mouse: Left button up, pos=(986,527) +38.3699 DATA Mouse: Left button down, pos=(986,527) +38.4358 DATA Mouse: Left button up, pos=(986,527) +38.4857 DATA Mouse: Left button down, pos=(986,527) +38.5695 DATA Mouse: Left button up, pos=(986,527) +38.6198 DATA Mouse: Left button down, pos=(986,527) +38.7026 DATA Mouse: Left button up, pos=(986,527) +39.2196 DATA Mouse: Left button down, pos=(1068,580) +39.2865 DATA Mouse: Left button up, pos=(1068,580) +39.3692 DATA Mouse: Left button down, pos=(1068,580) +39.4532 DATA Mouse: Left button up, pos=(1068,580) +40.2692 DATA Mouse: Left button down, pos=(736,484) +40.3520 DATA Mouse: Left button up, pos=(735,485) +41.2026 DATA Mouse: Left button down, pos=(737,506) +41.3348 DATA Mouse: Left button up, pos=(737,506) +42.0191 DATA Mouse: Left button down, pos=(645,440) +42.1347 DATA Mouse: Left button up, pos=(645,440) +42.6010 DATA Mouse: Left button down, pos=(685,366) +42.7346 DATA Mouse: Left button up, pos=(685,366) +43.1517 DATA Mouse: Left button down, pos=(846,304) +43.2691 DATA Mouse: Left button up, pos=(846,304) +50.0166 DATA Mouse: Left button down, pos=(908,311) +50.1491 DATA Mouse: Left button up, pos=(908,311) +51.8008 DATA Mouse: Left button down, pos=(854,630) +51.9154 DATA Mouse: Left button up, pos=(854,630) +54.8145 DATA Keypress: escape +57.4681 EXP window1: mouseVisible = True diff --git a/data/_demo_eye_tracking_2021_Sep_28_2219.psydat b/data/_demo_eye_tracking_2021_Sep_28_2219.psydat new file mode 100644 index 0000000000000000000000000000000000000000..b7847582d741e7b12681a80f461053d4fbe955c3 Binary files /dev/null and b/data/_demo_eye_tracking_2021_Sep_28_2219.psydat differ diff --git a/demo_eye_tracking2-legacy-browsers.js b/demo_eye_tracking2-legacy-browsers.js index 848bdd402a11e7b6c07a0c4439af85d7d1ae6070..6cf040f17cf10d15eeb959d4e40cc6a04aab1970 100644 --- a/demo_eye_tracking2-legacy-browsers.js +++ b/demo_eye_tracking2-legacy-browsers.js @@ -2,12 +2,6 @@ * Demo_Eye_Tracking2 Test * ***************************/ - -// store info about the experiment session: -let expName = 'demo_eye_tracking2'; // from the Builder filename that created this script -let expInfo = {'participant': '', 'session': '001'}; - -// Start code blocks for 'Before Experiment' // init psychoJS: const psychoJS = new PsychoJS({ debug: true @@ -20,6 +14,12 @@ psychoJS.openWindow({ units: 'height', waitBlanking: true }); + +// store info about the experiment session: +let expName = 'demo_eye_tracking2'; // from the Builder filename that created this script +let expInfo = {'participant': '', 'session': '001'}; + +// Start code blocks for 'Before Experiment' // schedule the experiment: psychoJS.schedule(psychoJS.gui.DlgFromDict({ dictionary: expInfo, @@ -43,7 +43,7 @@ flowScheduler.add(calibrationIntroRoutineBegin()); flowScheduler.add(calibrationIntroRoutineEachFrame()); flowScheduler.add(calibrationIntroRoutineEnd()); const trialsLoopScheduler = new Scheduler(psychoJS); -flowScheduler.add(trialsLoopBegin(trialsLoopScheduler)); +flowScheduler.add(trialsLoopBegin, trialsLoopScheduler); flowScheduler.add(trialsLoopScheduler); flowScheduler.add(trialsLoopEnd); flowScheduler.add(trackingTrialRoutineBegin()); @@ -67,10 +67,10 @@ psychoJS.experimentLogger.setLevel(core.Logger.ServerLevel.EXP); var frameDur; -async function updateInfo() { +function updateInfo() { expInfo['date'] = util.MonotonicClock.getDateStr(); // add a simple timestamp expInfo['expName'] = expName; - expInfo['psychopyVersion'] = '2021.2.3'; + expInfo['psychopyVersion'] = '2021.1.4'; expInfo['OS'] = window.navigator.platform; // store frame rate of monitor if we can measure it successfully @@ -99,12 +99,13 @@ var calibrationClock; var calibration_square; var calibrationClick; var trackingTrialClock; +var polygon; var tracking_square; var trackingTxt; var tracking_resp; var globalClock; var routineTimer; -async function experimentInit() { +function experimentInit() { // Initialize components for Routine "initializeEyetracking" initializeEyetrackingClock = new util.Clock(); //initialize params of the webgazer package (used for eye tracking) @@ -176,13 +177,22 @@ async function experimentInit() { calibrationClick.mouseClock = new util.Clock(); // Initialize components for Routine "trackingTrial" trackingTrialClock = new util.Clock(); + polygon = new visual.ShapeStim ({ + win: psychoJS.window, name: 'polygon', + vertices: [[-[(- 0.25), 0.3][0]/2.0, -[(- 0.25), 0.3][1]/2.0], [+[(- 0.25), 0.3][0]/2.0, -[(- 0.25), 0.3][1]/2.0], [0, [(- 0.25), 0.3][1]/2.0]], + ori: 0.0, pos: [0, 0], + lineWidth: 1.0, lineColor: new util.Color('white'), + fillColor: new util.Color('white'), + opacity: undefined, depth: -1, interpolate: true, + }); + tracking_square = new visual.Rect ({ win: psychoJS.window, name: 'tracking_square', width: [0.02, 0.02][0], height: [0.02, 0.02][1], ori: 0.0, pos: [0, 0], lineWidth: 1.0, lineColor: new util.Color('white'), fillColor: new util.Color('white'), - opacity: undefined, depth: 0, interpolate: true, + opacity: undefined, depth: -2, interpolate: true, }); trackingTxt = new visual.TextStim({ @@ -193,7 +203,7 @@ async function experimentInit() { units: undefined, pos: [0, 0], height: 0.05, wrapWidth: undefined, ori: 0.0, color: new util.Color('white'), opacity: undefined, - depth: -1.0 + depth: -3.0 }); tracking_resp = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true}); @@ -211,9 +221,7 @@ var frameN; var continueRoutine; var initializeEyetrackingComponents; function initializeEyetrackingRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'initializeEyetracking'------- t = 0; initializeEyetrackingClock.reset(); // clock @@ -254,8 +262,8 @@ function initializeEyetrackingRoutineBegin(snapshot) { } -function initializeEyetrackingRoutineEachFrame() { - return async function () { +function initializeEyetrackingRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'initializeEyetracking'------- // get current time t = initializeEyetrackingClock.getTime(); @@ -303,8 +311,8 @@ function initializeEyetrackingRoutineEachFrame() { } -function initializeEyetrackingRoutineEnd() { - return async function () { +function initializeEyetrackingRoutineEnd(snapshot) { + return function () { //------Ending Routine 'initializeEyetracking'------- initializeEyetrackingComponents.forEach( function(thisComponent) { if (typeof thisComponent.setAutoDraw === 'function') { @@ -322,9 +330,7 @@ function initializeEyetrackingRoutineEnd() { var _inst1_resp_allKeys; var inst1Components; function inst1RoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'inst1'------- t = 0; inst1Clock.reset(); // clock @@ -350,8 +356,8 @@ function inst1RoutineBegin(snapshot) { } -function inst1RoutineEachFrame() { - return async function () { +function inst1RoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'inst1'------- // get current time t = inst1Clock.getTime(); @@ -418,8 +424,8 @@ function inst1RoutineEachFrame() { } -function inst1RoutineEnd() { - return async function () { +function inst1RoutineEnd(snapshot) { + return function () { //------Ending Routine 'inst1'------- inst1Components.forEach( function(thisComponent) { if (typeof thisComponent.setAutoDraw === 'function') { @@ -444,9 +450,7 @@ function inst1RoutineEnd() { var gotValidClick; var calibrationIntroComponents; function calibrationIntroRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'calibrationIntro'------- t = 0; calibrationIntroClock.reset(); // clock @@ -471,8 +475,8 @@ function calibrationIntroRoutineBegin(snapshot) { var prevButtonState; var _mouseButtons; -function calibrationIntroRoutineEachFrame() { - return async function () { +function calibrationIntroRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'calibrationIntro'------- // get current time t = calibrationIntroClock.getTime(); @@ -536,15 +540,15 @@ function calibrationIntroRoutineEachFrame() { var _mouseXYs; -function calibrationIntroRoutineEnd() { - return async function () { +function calibrationIntroRoutineEnd(snapshot) { + return function () { //------Ending Routine 'calibrationIntro'------- calibrationIntroComponents.forEach( function(thisComponent) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } }); - // store data for psychoJS.experiment (ExperimentHandler) + // store data for thisExp (ExperimentHandler) _mouseXYs = calibrationMouse.getPos(); _mouseButtons = calibrationMouse.getPressed(); psychoJS.experiment.addData('calibrationMouse.x', _mouseXYs[0]); @@ -562,38 +566,34 @@ function calibrationIntroRoutineEnd() { var trials; var currentLoop; -function trialsLoopBegin(trialsLoopScheduler, snapshot) { - return async function() { - TrialHandler.fromSnapshot(snapshot); // update internal variables (.thisN etc) of the loop - - // set up handler to look after randomisation of conditions etc - trials = new TrialHandler({ - psychoJS: psychoJS, - nReps: 1, method: TrialHandler.Method.RANDOM, - extraInfo: expInfo, originPath: undefined, - trialList: 'calibration_trials.xlsx', - seed: undefined, name: 'trials' - }); - psychoJS.experiment.addLoop(trials); // add the loop to the experiment - currentLoop = trials; // we're now the current loop - - // Schedule all the trials in the trialList: - trials.forEach(function() { - const snapshot = trials.getSnapshot(); - - trialsLoopScheduler.add(importConditions(snapshot)); - trialsLoopScheduler.add(calibrationRoutineBegin(snapshot)); - trialsLoopScheduler.add(calibrationRoutineEachFrame()); - trialsLoopScheduler.add(calibrationRoutineEnd()); - trialsLoopScheduler.add(endLoopIteration(trialsLoopScheduler, snapshot)); - }); - - return Scheduler.Event.NEXT; - } +function trialsLoopBegin(trialsLoopScheduler) { + // set up handler to look after randomisation of conditions etc + trials = new TrialHandler({ + psychoJS: psychoJS, + nReps: 1, method: TrialHandler.Method.RANDOM, + extraInfo: expInfo, originPath: undefined, + trialList: 'calibration_trials.xlsx', + seed: undefined, name: 'trials' + }); + psychoJS.experiment.addLoop(trials); // add the loop to the experiment + currentLoop = trials; // we're now the current loop + + // Schedule all the trials in the trialList: + trials.forEach(function() { + const snapshot = trials.getSnapshot(); + + trialsLoopScheduler.add(importConditions(snapshot)); + trialsLoopScheduler.add(calibrationRoutineBegin(snapshot)); + trialsLoopScheduler.add(calibrationRoutineEachFrame(snapshot)); + trialsLoopScheduler.add(calibrationRoutineEnd(snapshot)); + trialsLoopScheduler.add(endLoopIteration(trialsLoopScheduler, snapshot)); + }); + + return Scheduler.Event.NEXT; } -async function trialsLoopEnd() { +function trialsLoopEnd() { psychoJS.experiment.removeLoop(trials); return Scheduler.Event.NEXT; @@ -603,9 +603,7 @@ async function trialsLoopEnd() { var callib_color; var calibrationComponents; function calibrationRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'calibration'------- t = 0; calibrationClock.reset(); // clock @@ -645,8 +643,8 @@ function calibrationRoutineBegin(snapshot) { var frameRemains; -function calibrationRoutineEachFrame() { - return async function () { +function calibrationRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'calibration'------- // get current time t = calibrationClock.getTime(); @@ -758,15 +756,15 @@ function calibrationRoutineEachFrame() { } -function calibrationRoutineEnd() { - return async function () { +function calibrationRoutineEnd(snapshot) { + return function () { //------Ending Routine 'calibration'------- calibrationComponents.forEach( function(thisComponent) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } }); - // store data for psychoJS.experiment (ExperimentHandler) + // store data for thisExp (ExperimentHandler) _mouseXYs = calibrationClick.getPos(); _mouseButtons = calibrationClick.getPressed(); psychoJS.experiment.addData('calibrationClick.x', _mouseXYs[0]); @@ -784,9 +782,7 @@ function calibrationRoutineEnd() { var _tracking_resp_allKeys; var trackingTrialComponents; function trackingTrialRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'trackingTrial'------- t = 0; trackingTrialClock.reset(); // clock @@ -804,6 +800,7 @@ function trackingTrialRoutineBegin(snapshot) { document.getElementById('webgazerVideoFeed').style.display = 'none'; // keep track of which components have finished trackingTrialComponents = []; + trackingTrialComponents.push(polygon); trackingTrialComponents.push(tracking_square); trackingTrialComponents.push(trackingTxt); trackingTrialComponents.push(tracking_resp); @@ -817,14 +814,28 @@ function trackingTrialRoutineBegin(snapshot) { } -function trackingTrialRoutineEachFrame() { - return async function () { +function trackingTrialRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'trackingTrial'------- // get current time t = trackingTrialClock.getTime(); frameN = frameN + 1;// number of completed frames (so 0 is the first frame) // update/draw components on each frame + // *polygon* updates + if (t >= 0.0 && polygon.status === PsychoJS.Status.NOT_STARTED) { + // keep track of start time/frame for later + polygon.tStart = t; // (not accounting for frame time here) + polygon.frameNStart = frameN; // exact frame index + + polygon.setAutoDraw(true); + } + + + if (polygon.status === PsychoJS.Status.STARTED){ // only update if being drawn + polygon.setFillColor(new util.Color(thisCol), false); + } + // *tracking_square* updates if (t >= 0.0 && tracking_square.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later @@ -926,8 +937,8 @@ function trackingTrialRoutineEachFrame() { } -function trackingTrialRoutineEnd() { - return async function () { +function trackingTrialRoutineEnd(snapshot) { + return function () { //------Ending Routine 'trackingTrial'------- trackingTrialComponents.forEach( function(thisComponent) { if (typeof thisComponent.setAutoDraw === 'function') { @@ -951,7 +962,7 @@ function trackingTrialRoutineEnd() { function endLoopIteration(scheduler, snapshot) { // ------Prepare for next entry------ - return async function () { + return function () { if (typeof snapshot !== 'undefined') { // ------Check if user ended loop early------ if (snapshot.finished) { @@ -973,14 +984,14 @@ function endLoopIteration(scheduler, snapshot) { function importConditions(currentLoop) { - return async function () { + return function () { psychoJS.importAttributes(currentLoop.getCurrentTrial()); return Scheduler.Event.NEXT; }; } -async function quitPsychoJS(message, isCompleted) { +function quitPsychoJS(message, isCompleted) { // Check for and save orphaned data if (psychoJS.experiment.isEntryEmpty()) { psychoJS.experiment.nextEntry(); @@ -995,6 +1006,8 @@ async function quitPsychoJS(message, isCompleted) { + + psychoJS.window.close(); psychoJS.quit({message: message, isCompleted: isCompleted}); diff --git a/demo_eye_tracking2.js b/demo_eye_tracking2.js index 0f97f96aba4b49a4e51014fc7941686cba7e5329..4deed88439f5f51b5aadac7afe061df5b57de758 100644 --- a/demo_eye_tracking2.js +++ b/demo_eye_tracking2.js @@ -2,20 +2,17 @@ * Demo_Eye_Tracking2 Test * ***************************/ -import { core, data, sound, util, visual } from './lib/psychojs-2021.2.3.js'; -const { PsychoJS } = core; -const { TrialHandler } = data; -const { Scheduler } = util; +import { PsychoJS } from './lib/core-2021.1.4.js'; +import * as core from './lib/core-2021.1.4.js'; +import { TrialHandler } from './lib/data-2021.1.4.js'; +import { Scheduler } from './lib/util-2021.1.4.js'; +import * as visual from './lib/visual-2021.1.4.js'; +import * as sound from './lib/sound-2021.1.4.js'; +import * as util from './lib/util-2021.1.4.js'; //some handy aliases as in the psychopy scripts; const { abs, sin, cos, PI: pi, sqrt } = Math; const { round } = util; - -// store info about the experiment session: -let expName = 'demo_eye_tracking2'; // from the Builder filename that created this script -let expInfo = {'participant': '', 'session': '001'}; - -// Start code blocks for 'Before Experiment' // init psychoJS: const psychoJS = new PsychoJS({ debug: true @@ -28,6 +25,12 @@ psychoJS.openWindow({ units: 'height', waitBlanking: true }); + +// store info about the experiment session: +let expName = 'demo_eye_tracking2'; // from the Builder filename that created this script +let expInfo = {'participant': '', 'session': '001'}; + +// Start code blocks for 'Before Experiment' // schedule the experiment: psychoJS.schedule(psychoJS.gui.DlgFromDict({ dictionary: expInfo, @@ -51,7 +54,7 @@ flowScheduler.add(calibrationIntroRoutineBegin()); flowScheduler.add(calibrationIntroRoutineEachFrame()); flowScheduler.add(calibrationIntroRoutineEnd()); const trialsLoopScheduler = new Scheduler(psychoJS); -flowScheduler.add(trialsLoopBegin(trialsLoopScheduler)); +flowScheduler.add(trialsLoopBegin, trialsLoopScheduler); flowScheduler.add(trialsLoopScheduler); flowScheduler.add(trialsLoopEnd); flowScheduler.add(trackingTrialRoutineBegin()); @@ -75,10 +78,10 @@ psychoJS.experimentLogger.setLevel(core.Logger.ServerLevel.EXP); var frameDur; -async function updateInfo() { +function updateInfo() { expInfo['date'] = util.MonotonicClock.getDateStr(); // add a simple timestamp expInfo['expName'] = expName; - expInfo['psychopyVersion'] = '2021.2.3'; + expInfo['psychopyVersion'] = '2021.1.4'; expInfo['OS'] = window.navigator.platform; // store frame rate of monitor if we can measure it successfully @@ -107,12 +110,13 @@ var calibrationClock; var calibration_square; var calibrationClick; var trackingTrialClock; +var polygon; var tracking_square; var trackingTxt; var tracking_resp; var globalClock; var routineTimer; -async function experimentInit() { +function experimentInit() { // Initialize components for Routine "initializeEyetracking" initializeEyetrackingClock = new util.Clock(); //initialize params of the webgazer package (used for eye tracking) @@ -184,13 +188,22 @@ async function experimentInit() { calibrationClick.mouseClock = new util.Clock(); // Initialize components for Routine "trackingTrial" trackingTrialClock = new util.Clock(); + polygon = new visual.ShapeStim ({ + win: psychoJS.window, name: 'polygon', + vertices: [[-[(- 0.25), 0.3][0]/2.0, -[(- 0.25), 0.3][1]/2.0], [+[(- 0.25), 0.3][0]/2.0, -[(- 0.25), 0.3][1]/2.0], [0, [(- 0.25), 0.3][1]/2.0]], + ori: 0.0, pos: [0, 0], + lineWidth: 1.0, lineColor: new util.Color('white'), + fillColor: new util.Color('white'), + opacity: undefined, depth: -1, interpolate: true, + }); + tracking_square = new visual.Rect ({ win: psychoJS.window, name: 'tracking_square', width: [0.02, 0.02][0], height: [0.02, 0.02][1], ori: 0.0, pos: [0, 0], lineWidth: 1.0, lineColor: new util.Color('white'), fillColor: new util.Color('white'), - opacity: undefined, depth: 0, interpolate: true, + opacity: undefined, depth: -2, interpolate: true, }); trackingTxt = new visual.TextStim({ @@ -201,7 +214,7 @@ async function experimentInit() { units: undefined, pos: [0, 0], height: 0.05, wrapWidth: undefined, ori: 0.0, color: new util.Color('white'), opacity: undefined, - depth: -1.0 + depth: -3.0 }); tracking_resp = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true}); @@ -219,9 +232,7 @@ var frameN; var continueRoutine; var initializeEyetrackingComponents; function initializeEyetrackingRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'initializeEyetracking'------- t = 0; initializeEyetrackingClock.reset(); // clock @@ -261,8 +272,8 @@ function initializeEyetrackingRoutineBegin(snapshot) { } -function initializeEyetrackingRoutineEachFrame() { - return async function () { +function initializeEyetrackingRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'initializeEyetracking'------- // get current time t = initializeEyetrackingClock.getTime(); @@ -310,8 +321,8 @@ function initializeEyetrackingRoutineEachFrame() { } -function initializeEyetrackingRoutineEnd() { - return async function () { +function initializeEyetrackingRoutineEnd(snapshot) { + return function () { //------Ending Routine 'initializeEyetracking'------- for (const thisComponent of initializeEyetrackingComponents) { if (typeof thisComponent.setAutoDraw === 'function') { @@ -329,9 +340,7 @@ function initializeEyetrackingRoutineEnd() { var _inst1_resp_allKeys; var inst1Components; function inst1RoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'inst1'------- t = 0; inst1Clock.reset(); // clock @@ -356,8 +365,8 @@ function inst1RoutineBegin(snapshot) { } -function inst1RoutineEachFrame() { - return async function () { +function inst1RoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'inst1'------- // get current time t = inst1Clock.getTime(); @@ -424,8 +433,8 @@ function inst1RoutineEachFrame() { } -function inst1RoutineEnd() { - return async function () { +function inst1RoutineEnd(snapshot) { + return function () { //------Ending Routine 'inst1'------- for (const thisComponent of inst1Components) { if (typeof thisComponent.setAutoDraw === 'function') { @@ -450,9 +459,7 @@ function inst1RoutineEnd() { var gotValidClick; var calibrationIntroComponents; function calibrationIntroRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'calibrationIntro'------- t = 0; calibrationIntroClock.reset(); // clock @@ -476,8 +483,8 @@ function calibrationIntroRoutineBegin(snapshot) { var prevButtonState; var _mouseButtons; -function calibrationIntroRoutineEachFrame() { - return async function () { +function calibrationIntroRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'calibrationIntro'------- // get current time t = calibrationIntroClock.getTime(); @@ -541,15 +548,15 @@ function calibrationIntroRoutineEachFrame() { var _mouseXYs; -function calibrationIntroRoutineEnd() { - return async function () { +function calibrationIntroRoutineEnd(snapshot) { + return function () { //------Ending Routine 'calibrationIntro'------- for (const thisComponent of calibrationIntroComponents) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } } - // store data for psychoJS.experiment (ExperimentHandler) + // store data for thisExp (ExperimentHandler) _mouseXYs = calibrationMouse.getPos(); _mouseButtons = calibrationMouse.getPressed(); psychoJS.experiment.addData('calibrationMouse.x', _mouseXYs[0]); @@ -567,37 +574,33 @@ function calibrationIntroRoutineEnd() { var trials; var currentLoop; -function trialsLoopBegin(trialsLoopScheduler, snapshot) { - return async function() { - TrialHandler.fromSnapshot(snapshot); // update internal variables (.thisN etc) of the loop - - // set up handler to look after randomisation of conditions etc - trials = new TrialHandler({ - psychoJS: psychoJS, - nReps: 1, method: TrialHandler.Method.RANDOM, - extraInfo: expInfo, originPath: undefined, - trialList: 'calibration_trials.xlsx', - seed: undefined, name: 'trials' - }); - psychoJS.experiment.addLoop(trials); // add the loop to the experiment - currentLoop = trials; // we're now the current loop - - // Schedule all the trials in the trialList: - for (const thisTrial of trials) { - const snapshot = trials.getSnapshot(); - trialsLoopScheduler.add(importConditions(snapshot)); - trialsLoopScheduler.add(calibrationRoutineBegin(snapshot)); - trialsLoopScheduler.add(calibrationRoutineEachFrame()); - trialsLoopScheduler.add(calibrationRoutineEnd()); - trialsLoopScheduler.add(endLoopIteration(trialsLoopScheduler, snapshot)); - } - - return Scheduler.Event.NEXT; +function trialsLoopBegin(trialsLoopScheduler) { + // set up handler to look after randomisation of conditions etc + trials = new TrialHandler({ + psychoJS: psychoJS, + nReps: 1, method: TrialHandler.Method.RANDOM, + extraInfo: expInfo, originPath: undefined, + trialList: 'calibration_trials.xlsx', + seed: undefined, name: 'trials' + }); + psychoJS.experiment.addLoop(trials); // add the loop to the experiment + currentLoop = trials; // we're now the current loop + + // Schedule all the trials in the trialList: + for (const thisTrial of trials) { + const snapshot = trials.getSnapshot(); + trialsLoopScheduler.add(importConditions(snapshot)); + trialsLoopScheduler.add(calibrationRoutineBegin(snapshot)); + trialsLoopScheduler.add(calibrationRoutineEachFrame(snapshot)); + trialsLoopScheduler.add(calibrationRoutineEnd(snapshot)); + trialsLoopScheduler.add(endLoopIteration(trialsLoopScheduler, snapshot)); } + + return Scheduler.Event.NEXT; } -async function trialsLoopEnd() { +function trialsLoopEnd() { psychoJS.experiment.removeLoop(trials); return Scheduler.Event.NEXT; @@ -607,9 +610,7 @@ async function trialsLoopEnd() { var callib_color; var calibrationComponents; function calibrationRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'calibration'------- t = 0; calibrationClock.reset(); // clock @@ -648,8 +649,8 @@ function calibrationRoutineBegin(snapshot) { var frameRemains; -function calibrationRoutineEachFrame() { - return async function () { +function calibrationRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'calibration'------- // get current time t = calibrationClock.getTime(); @@ -761,15 +762,15 @@ function calibrationRoutineEachFrame() { } -function calibrationRoutineEnd() { - return async function () { +function calibrationRoutineEnd(snapshot) { + return function () { //------Ending Routine 'calibration'------- for (const thisComponent of calibrationComponents) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } } - // store data for psychoJS.experiment (ExperimentHandler) + // store data for thisExp (ExperimentHandler) _mouseXYs = calibrationClick.getPos(); _mouseButtons = calibrationClick.getPressed(); psychoJS.experiment.addData('calibrationClick.x', _mouseXYs[0]); @@ -787,9 +788,7 @@ function calibrationRoutineEnd() { var _tracking_resp_allKeys; var trackingTrialComponents; function trackingTrialRoutineBegin(snapshot) { - return async function () { - TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date - + return function () { //------Prepare to start Routine 'trackingTrial'------- t = 0; trackingTrialClock.reset(); // clock @@ -807,6 +806,7 @@ function trackingTrialRoutineBegin(snapshot) { document.getElementById('webgazerVideoFeed').style.display = 'none'; // keep track of which components have finished trackingTrialComponents = []; + trackingTrialComponents.push(polygon); trackingTrialComponents.push(tracking_square); trackingTrialComponents.push(trackingTxt); trackingTrialComponents.push(tracking_resp); @@ -819,14 +819,28 @@ function trackingTrialRoutineBegin(snapshot) { } -function trackingTrialRoutineEachFrame() { - return async function () { +function trackingTrialRoutineEachFrame(snapshot) { + return function () { //------Loop for each frame of Routine 'trackingTrial'------- // get current time t = trackingTrialClock.getTime(); frameN = frameN + 1;// number of completed frames (so 0 is the first frame) // update/draw components on each frame + // *polygon* updates + if (t >= 0.0 && polygon.status === PsychoJS.Status.NOT_STARTED) { + // keep track of start time/frame for later + polygon.tStart = t; // (not accounting for frame time here) + polygon.frameNStart = frameN; // exact frame index + + polygon.setAutoDraw(true); + } + + + if (polygon.status === PsychoJS.Status.STARTED){ // only update if being drawn + polygon.setFillColor(new util.Color(thisCol), false); + } + // *tracking_square* updates if (t >= 0.0 && tracking_square.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later @@ -928,8 +942,8 @@ function trackingTrialRoutineEachFrame() { } -function trackingTrialRoutineEnd() { - return async function () { +function trackingTrialRoutineEnd(snapshot) { + return function () { //------Ending Routine 'trackingTrial'------- for (const thisComponent of trackingTrialComponents) { if (typeof thisComponent.setAutoDraw === 'function') { @@ -953,7 +967,7 @@ function trackingTrialRoutineEnd() { function endLoopIteration(scheduler, snapshot) { // ------Prepare for next entry------ - return async function () { + return function () { if (typeof snapshot !== 'undefined') { // ------Check if user ended loop early------ if (snapshot.finished) { @@ -975,14 +989,14 @@ function endLoopIteration(scheduler, snapshot) { function importConditions(currentLoop) { - return async function () { + return function () { psychoJS.importAttributes(currentLoop.getCurrentTrial()); return Scheduler.Event.NEXT; }; } -async function quitPsychoJS(message, isCompleted) { +function quitPsychoJS(message, isCompleted) { // Check for and save orphaned data if (psychoJS.experiment.isEntryEmpty()) { psychoJS.experiment.nextEntry(); @@ -997,6 +1011,8 @@ async function quitPsychoJS(message, isCompleted) { + + psychoJS.window.close(); psychoJS.quit({message: message, isCompleted: isCompleted}); diff --git a/demo_eye_tracking2.psyexp b/demo_eye_tracking2.psyexp index a4167787fda546d13d42dcda8fac3b7bfbee1a22..dc9184ffecb524ad38369cc6fd4300c486adba07 100644 --- a/demo_eye_tracking2.psyexp +++ b/demo_eye_tracking2.psyexp @@ -1,5 +1,5 @@  - + @@ -330,6 +330,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -345,7 +387,7 @@ - + diff --git a/demo_eye_tracking2_lastrun.py b/demo_eye_tracking2_lastrun.py new file mode 100644 index 0000000000000000000000000000000000000000..32c11bc83ac03aeec146e135b66e81415598f010 --- /dev/null +++ b/demo_eye_tracking2_lastrun.py @@ -0,0 +1,689 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +This experiment was created using PsychoPy3 Experiment Builder (v2021.1.4), + on 九月 28, 2021, at 22:19 +If you publish work using this script the most relevant publication is: + + Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019) + PsychoPy2: Experiments in behavior made easy Behav Res 51: 195. + https://doi.org/10.3758/s13428-018-01193-y + +""" + +from __future__ import absolute_import, division + +from psychopy import locale_setup +from psychopy import prefs +from psychopy import sound, gui, visual, core, data, event, logging, clock, colors +from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED, + STOPPED, FINISHED, PRESSED, RELEASED, FOREVER) + +import numpy as np # whole numpy lib is available, prepend 'np.' +from numpy import (sin, cos, tan, log, log10, pi, average, + sqrt, std, deg2rad, rad2deg, linspace, asarray) +from numpy.random import random, randint, normal, shuffle, choice as randchoice +import os # handy system and path functions +import sys # to get file system encoding + +from psychopy.hardware import keyboard + + + +# Ensure that relative paths start from the same directory as this script +_thisDir = os.path.dirname(os.path.abspath(__file__)) +os.chdir(_thisDir) + +# Store info about the experiment session +psychopyVersion = '2021.1.4' +expName = 'demo_eye_tracking' # from the Builder filename that created this script +expInfo = {'participant': '', 'session': '001'} +dlg = gui.DlgFromDict(dictionary=expInfo, sortKeys=False, title=expName) +if dlg.OK == False: + core.quit() # user pressed cancel +expInfo['date'] = data.getDateStr() # add a simple timestamp +expInfo['expName'] = expName +expInfo['psychopyVersion'] = psychopyVersion + +# Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc +filename = _thisDir + os.sep + u'data/%s_%s_%s' % (expInfo['participant'], expName, expInfo['date']) + +# An ExperimentHandler isn't essential but helps with data saving +thisExp = data.ExperimentHandler(name=expName, version='', + extraInfo=expInfo, runtimeInfo=None, + originPath='C:\\Users\\yyshu\\Downloads\\stroop-master\\eyetracking\\demo_eye_tracking2_lastrun.py', + savePickle=True, saveWideText=True, + dataFileName=filename) +# save a log file for detail verbose info +logFile = logging.LogFile(filename+'.log', level=logging.EXP) +logging.console.setLevel(logging.WARNING) # this outputs to the screen, not a file + +endExpNow = False # flag for 'escape' or other condition => quit the exp +frameTolerance = 0.001 # how close to onset before 'same' frame + +# Start Code - component code to be run after the window creation + +# Setup the Window +win = visual.Window( + size=[1536, 960], fullscr=True, screen=0, + winType='pyglet', allowGUI=False, allowStencil=False, + monitor='testMonitor', color=[-1,-1,-1], colorSpace='rgb', + blendMode='avg', useFBO=True, + units='height') +# store frame rate of monitor if we can measure it +expInfo['frameRate'] = win.getActualFrameRate() +if expInfo['frameRate'] != None: + frameDur = 1.0 / round(expInfo['frameRate']) +else: + frameDur = 1.0 / 60.0 # could not measure, so guess + +# create a default keyboard (e.g. to check for escape) +defaultKeyboard = keyboard.Keyboard() + +# Initialize components for Routine "initializeEyetracking" +initializeEyetrackingClock = core.Clock() +webcamWarning = visual.TextStim(win=win, name='webcamWarning', + text='This experiment uses eye tracking. \n\nYou should see your web-browser request access to your webcam. You might need to click on this text to make that happen. Please permit access, and wait a little while. Your webcam video should appear in the top-left of the screen.', + font='Arial', + pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0, + color='white', colorSpace='rgb', opacity=None, + languageStyle='LTR', + depth=-1.0); + +# Initialize components for Routine "inst1" +inst1Clock = core.Clock() +instruction1Txt = visual.TextStim(win=win, name='instruction1Txt', + text='Webgazer initialized. \nPress space to move on', + font='Arial', + pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0, + color='white', colorSpace='rgb', opacity=None, + languageStyle='LTR', + depth=-1.0); +inst1_resp = keyboard.Keyboard() + +# Initialize components for Routine "calibrationIntro" +calibrationIntroClock = core.Clock() +calibrationTxt = visual.TextStim(win=win, name='calibrationTxt', + text="OK great! we are almost ready to get started. \n\nFirst we need to calibrate the eye tracker. Please try to keep your head still. If you move your head too far away, you'r webcam will appear in the top left corner. If this happens, please move back into view. \n\nWhite squares will appear at different locations on the screen. Please click each square with your mouse.\n\nClick anywhere with the mouse to continue...", + font='Arial', + pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0, + color='white', colorSpace='rgb', opacity=None, + languageStyle='LTR', + depth=0.0); +calibrationMouse = event.Mouse(win=win) +x, y = [None, None] +calibrationMouse.mouseClock = core.Clock() + +# Initialize components for Routine "calibration" +calibrationClock = core.Clock() +calibration_square = visual.Rect( + win=win, name='calibration_square', + width=(0.02, 0.02)[0], height=(0.02, 0.02)[1], + ori=0.0, pos=[0,0], + lineWidth=1.0, colorSpace='rgb', lineColor='white', fillColor='white', + opacity=None, depth=-1.0, interpolate=True) +calibrationClick = event.Mouse(win=win) +x, y = [None, None] +calibrationClick.mouseClock = core.Clock() + +# Initialize components for Routine "trackingTrial" +trackingTrialClock = core.Clock() +polygon = visual.ShapeStim( + win=win, name='polygon', + vertices=[[-(-0.25, 0.3)[0]/2.0,-(-0.25, 0.3)[1]/2.0], [+(-0.25, 0.3)[0]/2.0,-(-0.25, 0.3)[1]/2.0], [0,(-0.25, 0.3)[1]/2.0]], + ori=0.0, pos=(0, 0), + lineWidth=1.0, colorSpace='rgb', lineColor='white', fillColor='white', + opacity=None, depth=-1.0, interpolate=True) +tracking_square = visual.Rect( + win=win, name='tracking_square', + width=(0.02, 0.02)[0], height=(0.02, 0.02)[1], + ori=0.0, pos=(0, 0), + lineWidth=1.0, colorSpace='rgb', lineColor='white', fillColor='white', + opacity=None, depth=-2.0, interpolate=True) +trackingTxt = visual.TextStim(win=win, name='trackingTxt', + text='Great! we are now tracking your eye movements! look around the screen to see how it works! \n\nPlease remember is important for you to keep your head still during the experiment. \n\nPress space to start', + font='Arial', + pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0, + color='white', colorSpace='rgb', opacity=None, + languageStyle='LTR', + depth=-3.0); +tracking_resp = keyboard.Keyboard() + +# Create some handy timers +globalClock = core.Clock() # to track the time since experiment started +routineTimer = core.CountdownTimer() # to track time remaining of each (non-slip) routine + +# ------Prepare to start Routine "initializeEyetracking"------- +continueRoutine = True +# update component parameters for each repeat +# keep track of which components have finished +initializeEyetrackingComponents = [webcamWarning] +for thisComponent in initializeEyetrackingComponents: + thisComponent.tStart = None + thisComponent.tStop = None + thisComponent.tStartRefresh = None + thisComponent.tStopRefresh = None + if hasattr(thisComponent, 'status'): + thisComponent.status = NOT_STARTED +# reset timers +t = 0 +_timeToFirstFrame = win.getFutureFlipTime(clock="now") +initializeEyetrackingClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip +frameN = -1 + +# -------Run Routine "initializeEyetracking"------- +while continueRoutine: + # get current time + t = initializeEyetrackingClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=initializeEyetrackingClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *webcamWarning* updates + if webcamWarning.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + webcamWarning.frameNStart = frameN # exact frame index + webcamWarning.tStart = t # local t and not account for scr refresh + webcamWarning.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(webcamWarning, 'tStartRefresh') # time at next scr refresh + webcamWarning.setAutoDraw(True) + + # check for quit (typically the Esc key) + if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): + core.quit() + + # check if all components have finished + if not continueRoutine: # a component has requested a forced-end of Routine + break + continueRoutine = False # will revert to True if at least one component still running + for thisComponent in initializeEyetrackingComponents: + if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: + continueRoutine = True + break # at least one component has not yet finished + + # refresh the screen + if continueRoutine: # don't flip if this routine is over or we'll get a blank screen + win.flip() + +# -------Ending Routine "initializeEyetracking"------- +for thisComponent in initializeEyetrackingComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) +thisExp.addData('webcamWarning.started', webcamWarning.tStartRefresh) +thisExp.addData('webcamWarning.stopped', webcamWarning.tStopRefresh) +# the Routine "initializeEyetracking" was not non-slip safe, so reset the non-slip timer +routineTimer.reset() + +# ------Prepare to start Routine "inst1"------- +continueRoutine = True +# update component parameters for each repeat +inst1_resp.keys = [] +inst1_resp.rt = [] +_inst1_resp_allKeys = [] +# keep track of which components have finished +inst1Components = [instruction1Txt, inst1_resp] +for thisComponent in inst1Components: + thisComponent.tStart = None + thisComponent.tStop = None + thisComponent.tStartRefresh = None + thisComponent.tStopRefresh = None + if hasattr(thisComponent, 'status'): + thisComponent.status = NOT_STARTED +# reset timers +t = 0 +_timeToFirstFrame = win.getFutureFlipTime(clock="now") +inst1Clock.reset(-_timeToFirstFrame) # t0 is time of first possible flip +frameN = -1 + +# -------Run Routine "inst1"------- +while continueRoutine: + # get current time + t = inst1Clock.getTime() + tThisFlip = win.getFutureFlipTime(clock=inst1Clock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *instruction1Txt* updates + if instruction1Txt.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + instruction1Txt.frameNStart = frameN # exact frame index + instruction1Txt.tStart = t # local t and not account for scr refresh + instruction1Txt.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(instruction1Txt, 'tStartRefresh') # time at next scr refresh + instruction1Txt.setAutoDraw(True) + + # *inst1_resp* updates + waitOnFlip = False + if inst1_resp.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + inst1_resp.frameNStart = frameN # exact frame index + inst1_resp.tStart = t # local t and not account for scr refresh + inst1_resp.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(inst1_resp, 'tStartRefresh') # time at next scr refresh + inst1_resp.status = STARTED + # keyboard checking is just starting + waitOnFlip = True + win.callOnFlip(inst1_resp.clock.reset) # t=0 on next screen flip + win.callOnFlip(inst1_resp.clearEvents, eventType='keyboard') # clear events on next screen flip + if inst1_resp.status == STARTED and not waitOnFlip: + theseKeys = inst1_resp.getKeys(keyList=['space'], waitRelease=False) + _inst1_resp_allKeys.extend(theseKeys) + if len(_inst1_resp_allKeys): + inst1_resp.keys = _inst1_resp_allKeys[-1].name # just the last key pressed + inst1_resp.rt = _inst1_resp_allKeys[-1].rt + # a response ends the routine + continueRoutine = False + + # check for quit (typically the Esc key) + if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): + core.quit() + + # check if all components have finished + if not continueRoutine: # a component has requested a forced-end of Routine + break + continueRoutine = False # will revert to True if at least one component still running + for thisComponent in inst1Components: + if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: + continueRoutine = True + break # at least one component has not yet finished + + # refresh the screen + if continueRoutine: # don't flip if this routine is over or we'll get a blank screen + win.flip() + +# -------Ending Routine "inst1"------- +for thisComponent in inst1Components: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) +thisExp.addData('instruction1Txt.started', instruction1Txt.tStartRefresh) +thisExp.addData('instruction1Txt.stopped', instruction1Txt.tStopRefresh) +# check responses +if inst1_resp.keys in ['', [], None]: # No response was made + inst1_resp.keys = None +thisExp.addData('inst1_resp.keys',inst1_resp.keys) +if inst1_resp.keys != None: # we had a response + thisExp.addData('inst1_resp.rt', inst1_resp.rt) +thisExp.addData('inst1_resp.started', inst1_resp.tStartRefresh) +thisExp.addData('inst1_resp.stopped', inst1_resp.tStopRefresh) +thisExp.nextEntry() +# the Routine "inst1" was not non-slip safe, so reset the non-slip timer +routineTimer.reset() + +# ------Prepare to start Routine "calibrationIntro"------- +continueRoutine = True +# update component parameters for each repeat +# setup some python lists for storing info about the calibrationMouse +gotValidClick = False # until a click is received +# keep track of which components have finished +calibrationIntroComponents = [calibrationTxt, calibrationMouse] +for thisComponent in calibrationIntroComponents: + thisComponent.tStart = None + thisComponent.tStop = None + thisComponent.tStartRefresh = None + thisComponent.tStopRefresh = None + if hasattr(thisComponent, 'status'): + thisComponent.status = NOT_STARTED +# reset timers +t = 0 +_timeToFirstFrame = win.getFutureFlipTime(clock="now") +calibrationIntroClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip +frameN = -1 + +# -------Run Routine "calibrationIntro"------- +while continueRoutine: + # get current time + t = calibrationIntroClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=calibrationIntroClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *calibrationTxt* updates + if calibrationTxt.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + calibrationTxt.frameNStart = frameN # exact frame index + calibrationTxt.tStart = t # local t and not account for scr refresh + calibrationTxt.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(calibrationTxt, 'tStartRefresh') # time at next scr refresh + calibrationTxt.setAutoDraw(True) + # *calibrationMouse* updates + if calibrationMouse.status == NOT_STARTED and t >= 0.0-frameTolerance: + # keep track of start time/frame for later + calibrationMouse.frameNStart = frameN # exact frame index + calibrationMouse.tStart = t # local t and not account for scr refresh + calibrationMouse.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(calibrationMouse, 'tStartRefresh') # time at next scr refresh + calibrationMouse.status = STARTED + calibrationMouse.mouseClock.reset() + prevButtonState = calibrationMouse.getPressed() # if button is down already this ISN'T a new click + if calibrationMouse.status == STARTED: # only update if started and not finished! + buttons = calibrationMouse.getPressed() + if buttons != prevButtonState: # button state changed? + prevButtonState = buttons + if sum(buttons) > 0: # state changed to a new click + # abort routine on response + continueRoutine = False + + # check for quit (typically the Esc key) + if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): + core.quit() + + # check if all components have finished + if not continueRoutine: # a component has requested a forced-end of Routine + break + continueRoutine = False # will revert to True if at least one component still running + for thisComponent in calibrationIntroComponents: + if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: + continueRoutine = True + break # at least one component has not yet finished + + # refresh the screen + if continueRoutine: # don't flip if this routine is over or we'll get a blank screen + win.flip() + +# -------Ending Routine "calibrationIntro"------- +for thisComponent in calibrationIntroComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) +thisExp.addData('calibrationTxt.started', calibrationTxt.tStartRefresh) +thisExp.addData('calibrationTxt.stopped', calibrationTxt.tStopRefresh) +# store data for thisExp (ExperimentHandler) +x, y = calibrationMouse.getPos() +buttons = calibrationMouse.getPressed() +thisExp.addData('calibrationMouse.x', x) +thisExp.addData('calibrationMouse.y', y) +thisExp.addData('calibrationMouse.leftButton', buttons[0]) +thisExp.addData('calibrationMouse.midButton', buttons[1]) +thisExp.addData('calibrationMouse.rightButton', buttons[2]) +thisExp.addData('calibrationMouse.started', calibrationMouse.tStart) +thisExp.addData('calibrationMouse.stopped', calibrationMouse.tStop) +thisExp.nextEntry() +# the Routine "calibrationIntro" was not non-slip safe, so reset the non-slip timer +routineTimer.reset() + +# set up handler to look after randomisation of conditions etc +trials = data.TrialHandler(nReps=1, method='random', + extraInfo=expInfo, originPath=-1, + trialList=data.importConditions('calibration_trials.xlsx'), + seed=None, name='trials') +thisExp.addLoop(trials) # add the loop to the experiment +thisTrial = trials.trialList[0] # so we can initialise stimuli with some values +# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb) +if thisTrial != None: + for paramName in thisTrial: + exec('{} = thisTrial[paramName]'.format(paramName)) + +for thisTrial in trials: + currentLoop = trials + # abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb) + if thisTrial != None: + for paramName in thisTrial: + exec('{} = thisTrial[paramName]'.format(paramName)) + + # ------Prepare to start Routine "calibration"------- + continueRoutine = True + routineTimer.add(3.500000) + # update component parameters for each repeat + calibration_square.setPos((calibration_x, calibration_y)) + # setup some python lists for storing info about the calibrationClick + calibrationClick.clicked_name = [] + gotValidClick = False # until a click is received + # keep track of which components have finished + calibrationComponents = [calibration_square, calibrationClick] + for thisComponent in calibrationComponents: + thisComponent.tStart = None + thisComponent.tStop = None + thisComponent.tStartRefresh = None + thisComponent.tStopRefresh = None + if hasattr(thisComponent, 'status'): + thisComponent.status = NOT_STARTED + # reset timers + t = 0 + _timeToFirstFrame = win.getFutureFlipTime(clock="now") + calibrationClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip + frameN = -1 + + # -------Run Routine "calibration"------- + while continueRoutine and routineTimer.getTime() > 0: + # get current time + t = calibrationClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=calibrationClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + + # *calibration_square* updates + if calibration_square.status == NOT_STARTED and tThisFlip >= 0.5-frameTolerance: + # keep track of start time/frame for later + calibration_square.frameNStart = frameN # exact frame index + calibration_square.tStart = t # local t and not account for scr refresh + calibration_square.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(calibration_square, 'tStartRefresh') # time at next scr refresh + calibration_square.setAutoDraw(True) + if calibration_square.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > calibration_square.tStartRefresh + 3-frameTolerance: + # keep track of stop time/frame for later + calibration_square.tStop = t # not accounting for scr refresh + calibration_square.frameNStop = frameN # exact frame index + win.timeOnFlip(calibration_square, 'tStopRefresh') # time at next scr refresh + calibration_square.setAutoDraw(False) + if calibration_square.status == STARTED: # only update if drawing + calibration_square.setFillColor(callib_color) + # *calibrationClick* updates + if calibrationClick.status == NOT_STARTED and t >= 0.5-frameTolerance: + # keep track of start time/frame for later + calibrationClick.frameNStart = frameN # exact frame index + calibrationClick.tStart = t # local t and not account for scr refresh + calibrationClick.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(calibrationClick, 'tStartRefresh') # time at next scr refresh + calibrationClick.status = STARTED + calibrationClick.mouseClock.reset() + prevButtonState = calibrationClick.getPressed() # if button is down already this ISN'T a new click + if calibrationClick.status == STARTED: + # is it time to stop? (based on global clock, using actual start) + if tThisFlipGlobal > calibrationClick.tStartRefresh + 3-frameTolerance: + # keep track of stop time/frame for later + calibrationClick.tStop = t # not accounting for scr refresh + calibrationClick.frameNStop = frameN # exact frame index + win.timeOnFlip(calibrationClick, 'tStopRefresh') # time at next scr refresh + calibrationClick.status = FINISHED + if calibrationClick.status == STARTED: # only update if started and not finished! + buttons = calibrationClick.getPressed() + if buttons != prevButtonState: # button state changed? + prevButtonState = buttons + if sum(buttons) > 0: # state changed to a new click + # check if the mouse was inside our 'clickable' objects + gotValidClick = False + for obj in calibration_square: + if obj.contains(calibrationClick): + gotValidClick = True + calibrationClick.clicked_name.append(obj.name) + # abort routine on response + continueRoutine = False + + # check for quit (typically the Esc key) + if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): + core.quit() + + # check if all components have finished + if not continueRoutine: # a component has requested a forced-end of Routine + break + continueRoutine = False # will revert to True if at least one component still running + for thisComponent in calibrationComponents: + if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: + continueRoutine = True + break # at least one component has not yet finished + + # refresh the screen + if continueRoutine: # don't flip if this routine is over or we'll get a blank screen + win.flip() + + # -------Ending Routine "calibration"------- + for thisComponent in calibrationComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) + trials.addData('calibration_square.started', calibration_square.tStartRefresh) + trials.addData('calibration_square.stopped', calibration_square.tStopRefresh) + # store data for trials (TrialHandler) + x, y = calibrationClick.getPos() + buttons = calibrationClick.getPressed() + if sum(buttons): + # check if the mouse was inside our 'clickable' objects + gotValidClick = False + for obj in calibration_square: + if obj.contains(calibrationClick): + gotValidClick = True + calibrationClick.clicked_name.append(obj.name) + trials.addData('calibrationClick.x', x) + trials.addData('calibrationClick.y', y) + trials.addData('calibrationClick.leftButton', buttons[0]) + trials.addData('calibrationClick.midButton', buttons[1]) + trials.addData('calibrationClick.rightButton', buttons[2]) + if len(calibrationClick.clicked_name): + trials.addData('calibrationClick.clicked_name', calibrationClick.clicked_name[0]) + trials.addData('calibrationClick.started', calibrationClick.tStart) + trials.addData('calibrationClick.stopped', calibrationClick.tStop) + thisExp.nextEntry() + +# completed 1 repeats of 'trials' + + +# ------Prepare to start Routine "trackingTrial"------- +continueRoutine = True +# update component parameters for each repeat +tracking_resp.keys = [] +tracking_resp.rt = [] +_tracking_resp_allKeys = [] +# keep track of which components have finished +trackingTrialComponents = [polygon, tracking_square, trackingTxt, tracking_resp] +for thisComponent in trackingTrialComponents: + thisComponent.tStart = None + thisComponent.tStop = None + thisComponent.tStartRefresh = None + thisComponent.tStopRefresh = None + if hasattr(thisComponent, 'status'): + thisComponent.status = NOT_STARTED +# reset timers +t = 0 +_timeToFirstFrame = win.getFutureFlipTime(clock="now") +trackingTrialClock.reset(-_timeToFirstFrame) # t0 is time of first possible flip +frameN = -1 + +# -------Run Routine "trackingTrial"------- +while continueRoutine: + # get current time + t = trackingTrialClock.getTime() + tThisFlip = win.getFutureFlipTime(clock=trackingTrialClock) + tThisFlipGlobal = win.getFutureFlipTime(clock=None) + frameN = frameN + 1 # number of completed frames (so 0 is the first frame) + # update/draw components on each frame + if polygon.contains(tracking_square): + thisCol = 'red' + else: + thisCol = 'white' + + # *polygon* updates + if polygon.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + polygon.frameNStart = frameN # exact frame index + polygon.tStart = t # local t and not account for scr refresh + polygon.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(polygon, 'tStartRefresh') # time at next scr refresh + polygon.setAutoDraw(True) + if polygon.status == STARTED: # only update if drawing + polygon.setFillColor(thisCol) + + # *tracking_square* updates + if tracking_square.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + tracking_square.frameNStart = frameN # exact frame index + tracking_square.tStart = t # local t and not account for scr refresh + tracking_square.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(tracking_square, 'tStartRefresh') # time at next scr refresh + tracking_square.setAutoDraw(True) + + # *trackingTxt* updates + if trackingTxt.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + trackingTxt.frameNStart = frameN # exact frame index + trackingTxt.tStart = t # local t and not account for scr refresh + trackingTxt.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(trackingTxt, 'tStartRefresh') # time at next scr refresh + trackingTxt.setAutoDraw(True) + + # *tracking_resp* updates + waitOnFlip = False + if tracking_resp.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance: + # keep track of start time/frame for later + tracking_resp.frameNStart = frameN # exact frame index + tracking_resp.tStart = t # local t and not account for scr refresh + tracking_resp.tStartRefresh = tThisFlipGlobal # on global time + win.timeOnFlip(tracking_resp, 'tStartRefresh') # time at next scr refresh + tracking_resp.status = STARTED + # keyboard checking is just starting + waitOnFlip = True + win.callOnFlip(tracking_resp.clock.reset) # t=0 on next screen flip + win.callOnFlip(tracking_resp.clearEvents, eventType='keyboard') # clear events on next screen flip + if tracking_resp.status == STARTED and not waitOnFlip: + theseKeys = tracking_resp.getKeys(keyList=['space'], waitRelease=False) + _tracking_resp_allKeys.extend(theseKeys) + if len(_tracking_resp_allKeys): + tracking_resp.keys = _tracking_resp_allKeys[-1].name # just the last key pressed + tracking_resp.rt = _tracking_resp_allKeys[-1].rt + # a response ends the routine + continueRoutine = False + + # check for quit (typically the Esc key) + if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]): + core.quit() + + # check if all components have finished + if not continueRoutine: # a component has requested a forced-end of Routine + break + continueRoutine = False # will revert to True if at least one component still running + for thisComponent in trackingTrialComponents: + if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: + continueRoutine = True + break # at least one component has not yet finished + + # refresh the screen + if continueRoutine: # don't flip if this routine is over or we'll get a blank screen + win.flip() + +# -------Ending Routine "trackingTrial"------- +for thisComponent in trackingTrialComponents: + if hasattr(thisComponent, "setAutoDraw"): + thisComponent.setAutoDraw(False) +thisExp.addData('polygon.started', polygon.tStartRefresh) +thisExp.addData('polygon.stopped', polygon.tStopRefresh) +thisExp.addData('tracking_square.started', tracking_square.tStartRefresh) +thisExp.addData('tracking_square.stopped', tracking_square.tStopRefresh) +thisExp.addData('trackingTxt.started', trackingTxt.tStartRefresh) +thisExp.addData('trackingTxt.stopped', trackingTxt.tStopRefresh) +# check responses +if tracking_resp.keys in ['', [], None]: # No response was made + tracking_resp.keys = None +thisExp.addData('tracking_resp.keys',tracking_resp.keys) +if tracking_resp.keys != None: # we had a response + thisExp.addData('tracking_resp.rt', tracking_resp.rt) +thisExp.addData('tracking_resp.started', tracking_resp.tStartRefresh) +thisExp.addData('tracking_resp.stopped', tracking_resp.tStopRefresh) +thisExp.nextEntry() +# the Routine "trackingTrial" was not non-slip safe, so reset the non-slip timer +routineTimer.reset() + +# Flip one final time so any remaining win.callOnFlip() +# and win.timeOnFlip() tasks get executed before quitting +win.flip() + +# these shouldn't be strictly necessary (should auto-save) +thisExp.saveAsWideText(filename+'.csv', delim='auto') +thisExp.saveAsPickle(filename) +logging.flush() +# make sure everything is closed down +thisExp.abort() # or data files will save again on exit +win.close() +core.quit() diff --git a/index.html b/index.html index 52e87a647afde66f07a4a0f9e6d3b59c5a1dc074..2e80486095471b7733449c86e81d3760b27dd0d1 100644 --- a/index.html +++ b/index.html @@ -1,23 +1,40 @@ - - - + + demo_eye_tracking2 [PsychoPy] + + + - - - - + + + + +
- - - - + + + + + + + + + + + + + + - + + - - - + + + + + +