You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi! With the new TrialHandler2 trials.nRemaining is no longer updated while experiment is running
Expected Behaviour
nRemaining should be up-to-date at each trial within the loop (or at least removed from the docs I guess!)
Steps to Reproduce
Since I cannot attach a .psyexp file here, you could save the code below as a .py file and run it in Psychopy Standalone 2024.2.1
"""This experiment was created using PsychoPy3 Experiment Builder (v2024.2.1), on September 15, 2024, at 13:09If 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"""# --- Import packages ---frompsychopyimportlocale_setupfrompsychopyimportprefsfrompsychopyimportpluginsplugins.activatePlugins()
prefs.hardware['audioLib'] ='ptb'prefs.hardware['audioLatencyMode'] ='3'frompsychopyimportsound, gui, visual, core, data, event, logging, clock, colors, layout, hardwarefrompsychopy.toolsimportenvironmenttoolsfrompsychopy.constantsimport (NOT_STARTED, STARTED, PLAYING, PAUSED,
STOPPED, FINISHED, PRESSED, RELEASED, FOREVER, priority)
importnumpyasnp# whole numpy lib is available, prepend 'np.'fromnumpyimport (sin, cos, tan, log, log10, pi, average,
sqrt, std, deg2rad, rad2deg, linspace, asarray)
fromnumpy.randomimportrandom, randint, normal, shuffle, choiceasrandchoiceimportos# handy system and path functionsimportsys# to get file system encodingimportpsychopy.iohubasiofrompsychopy.hardwareimportkeyboard# --- Setup global variables (available in all functions) ---# create a device manager to handle hardware (keyboards, mice, mirophones, speakers, etc.)deviceManager=hardware.DeviceManager()
# ensure that relative paths start from the same directory as this script_thisDir=os.path.dirname(os.path.abspath(__file__))
# store info about the experiment sessionpsychopyVersion='2024.2.1'expName='nRemaining_BUG_demo'# from the Builder filename that created this script# information about this experimentexpInfo= {
'participant': f"{randint(0, 999999):06.0f}",
'session': '001',
'date|hid': data.getDateStr(),
'expName|hid': expName,
'psychopyVersion|hid': psychopyVersion,
}
# --- Define some variables which will change depending on pilot mode ---'''To run in pilot mode, either use the run/pilot toggle in Builder, Coder and Runner, or run the experiment with `--pilot` as an argument. To change what pilot #mode does, check out the 'Pilot mode' tab in preferences.'''# work out from system args whether we are running in pilot modePILOTING=core.setPilotModeFromArgs()
# start off with values from experiment settings_fullScr=True_winSize= [1920, 1080]
# if in pilot mode, apply overrides according to preferencesifPILOTING:
# force windowed modeifprefs.piloting['forceWindowed']:
_fullScr=False# set window size_winSize=prefs.piloting['forcedWindowSize']
defshowExpInfoDlg(expInfo):
""" Show participant info dialog. Parameters ========== expInfo : dict Information about this experiment. Returns ========== dict Information about this experiment. """# show participant info dialogdlg=gui.DlgFromDict(
dictionary=expInfo, sortKeys=False, title=expName, alwaysOnTop=True
)
ifdlg.OK==False:
core.quit() # user pressed cancel# return expInforeturnexpInfodefsetupData(expInfo, dataDir=None):
""" Make an ExperimentHandler to handle trials and saving. Parameters ========== expInfo : dict Information about this experiment, created by the `setupExpInfo` function. dataDir : Path, str or None Folder to save the data to, leave as None to create a folder in the current directory. Returns ========== psychopy.data.ExperimentHandler Handler object for this experiment, contains the data to save and information about where to save it to. """# remove dialog-specific syntax from expInfoforkey, valinexpInfo.copy().items():
newKey, _=data.utils.parsePipeSyntax(key)
expInfo[newKey] =expInfo.pop(key)
# data file name stem = absolute path + name; later add .psyexp, .csv, .log, etcifdataDirisNone:
dataDir=_thisDirfilename=u'data/%s_%s_%s'% (expInfo['participant'], expName, expInfo['date'])
# make sure filename is relative to dataDirifos.path.isabs(filename):
dataDir=os.path.commonprefix([dataDir, filename])
filename=os.path.relpath(filename, dataDir)
# an ExperimentHandler isn't essential but helps with data savingthisExp=data.ExperimentHandler(
name=expName, version='',
extraInfo=expInfo, runtimeInfo=None,
originPath='C:\\Users\\Giulia\\Documents\\PFI_NYULH\\nRemaining_BUG_demo.py',
savePickle=True, saveWideText=True,
dataFileName=dataDir+os.sep+filename, sortColumns='time'
)
thisExp.setPriority('thisRow.t', priority.CRITICAL)
thisExp.setPriority('expName', priority.LOW)
# return experiment handlerreturnthisExpdefsetupLogging(filename):
""" Setup a log file and tell it what level to log at. Parameters ========== filename : str or pathlib.Path Filename to save log file and data files as, doesn't need an extension. Returns ========== psychopy.logging.LogFile Text stream to receive inputs from the logging system. """# set how much information should be printed to the console / appifPILOTING:
logging.console.setLevel(
prefs.piloting['pilotConsoleLoggingLevel']
)
else:
logging.console.setLevel('warning')
# save a log file for detail verbose infologFile=logging.LogFile(filename+'.log')
ifPILOTING:
logFile.setLevel(
prefs.piloting['pilotLoggingLevel']
)
else:
logFile.setLevel(
logging.getLevel('info')
)
returnlogFiledefsetupWindow(expInfo=None, win=None):
""" Setup the Window Parameters ========== expInfo : dict Information about this experiment, created by the `setupExpInfo` function. win : psychopy.visual.Window Window to setup - leave as None to create a new window. Returns ========== psychopy.visual.Window Window in which to run this experiment. """ifPILOTING:
logging.debug('Fullscreen settings ignored as running in pilot mode.')
ifwinisNone:
# if not given a window to setup, make onewin=visual.Window(
size=_winSize, fullscr=_fullScr, screen=0,
winType='pyglet', allowStencil=False,
monitor='testMonitor', color=[0,0,0], colorSpace='rgb',
backgroundImage='', backgroundFit='none',
blendMode='avg', useFBO=True,
units='height',
checkTiming=False# we're going to do this ourselves in a moment
)
else:
# if we have a window, just set the attributes which are safe to setwin.color= [0,0,0]
win.colorSpace='rgb'win.backgroundImage=''win.backgroundFit='none'win.units='height'ifexpInfoisnotNone:
# get/measure frame rate if not already in expInfoifwin._monitorFrameRateisNone:
win._monitorFrameRate=win.getActualFrameRate(infoMsg='Attempting to measure frame rate of screen, please wait...')
expInfo['frameRate'] =win._monitorFrameRatewin.mouseVisible=Falsewin.hideMessage()
# show a visual indicator if we're in piloting modeifPILOTINGandprefs.piloting['showPilotingIndicator']:
win.showPilotingIndicator()
returnwindefsetupDevices(expInfo, thisExp, win):
""" Setup whatever devices are available (mouse, keyboard, speaker, eyetracker, etc.) and add them to the device manager (deviceManager) Parameters ========== expInfo : dict Information about this experiment, created by the `setupExpInfo` function. thisExp : psychopy.data.ExperimentHandler Handler object for this experiment, contains the data to save and information about where to save it to. win : psychopy.visual.Window Window in which to run this experiment. Returns ========== bool True if completed successfully. """# --- Setup input devices ---ioConfig= {}
# Setup iohub keyboardioConfig['Keyboard'] =dict(use_keymap='psychopy')
# Setup iohub experimentioConfig['Experiment'] =dict(filename=thisExp.dataFileName)
# Start ioHub serverioServer=io.launchHubServer(window=win, **ioConfig)
# store ioServer object in the device managerdeviceManager.ioServer=ioServer# create a default keyboard (e.g. to check for escape)ifdeviceManager.getDevice('defaultKeyboard') isNone:
deviceManager.addDevice(
deviceClass='keyboard', deviceName='defaultKeyboard', backend='iohub'
)
# return True if completed successfullyreturnTruedefpauseExperiment(thisExp, win=None, timers=[], playbackComponents=[]):
""" Pause this experiment, preventing the flow from advancing to the next routine until resumed. Parameters ========== thisExp : psychopy.data.ExperimentHandler Handler object for this experiment, contains the data to save and information about where to save it to. win : psychopy.visual.Window Window for this experiment. timers : list, tuple List of timers to reset once pausing is finished. playbackComponents : list, tuple List of any components with a `pause` method which need to be paused. """# if we are not paused, do nothingifthisExp.status!=PAUSED:
return# start a timer to figure out how long we're paused forpauseTimer=core.Clock()
# pause any playback componentsforcompinplaybackComponents:
comp.pause()
# make sure we have a keyboarddefaultKeyboard=deviceManager.getDevice('defaultKeyboard')
ifdefaultKeyboardisNone:
defaultKeyboard=deviceManager.addKeyboard(
deviceClass='keyboard',
deviceName='defaultKeyboard',
backend='ioHub',
)
# run a while loop while we wait to unpausewhilethisExp.status==PAUSED:
# check for quit (typically the Esc key)ifdefaultKeyboard.getKeys(keyList=['escape']):
endExperiment(thisExp, win=win)
# sleep 1ms so other threads can executeclock.time.sleep(0.001)
# if stop was requested while paused, quitifthisExp.status==FINISHED:
endExperiment(thisExp, win=win)
# resume any playback componentsforcompinplaybackComponents:
comp.play()
# reset any timersfortimerintimers:
timer.addTime(-pauseTimer.getTime())
defrun(expInfo, thisExp, win, globalClock=None, thisSession=None):
""" Run the experiment flow. Parameters ========== expInfo : dict Information about this experiment, created by the `setupExpInfo` function. thisExp : psychopy.data.ExperimentHandler Handler object for this experiment, contains the data to save and information about where to save it to. psychopy.visual.Window Window in which to run this experiment. globalClock : psychopy.core.clock.Clock or None Clock to get global time from - supply None to make a new one. thisSession : psychopy.session.Session or None Handle of the Session object this experiment is being run from, if any. """# mark experiment as startedthisExp.status=STARTED# make sure variables created by exec are available globallyexec=environmenttools.setExecEnvironment(globals())
# get device handles from dict of input devicesioServer=deviceManager.ioServer# get/create a default keyboard (e.g. to check for escape)defaultKeyboard=deviceManager.getDevice('defaultKeyboard')
ifdefaultKeyboardisNone:
deviceManager.addDevice(
deviceClass='keyboard', deviceName='defaultKeyboard', backend='ioHub'
)
eyetracker=deviceManager.getDevice('eyetracker')
# make sure we're running in the directory for this experimentos.chdir(_thisDir)
# get filename from ExperimentHandler for conveniencefilename=thisExp.dataFileNameframeTolerance=0.001# how close to onset before 'same' frameendExpNow=False# flag for 'escape' or other condition => quit the exp# get frame duration from frame rate in expInfoif'frameRate'inexpInfoandexpInfo['frameRate'] isnotNone:
frameDur=1.0/round(expInfo['frameRate'])
else:
frameDur=1.0/60.0# could not measure, so guess# Start Code - component code to be run after the window creation# --- Initialize components for Routine "trial" ---text=visual.TextStim(win=win, name='text',
text='',
font='Arial',
pos=(0, 0), draggable=False, height=0.05, wrapWidth=None, ori=0.0,
color='white', colorSpace='rgb', opacity=None,
languageStyle='LTR',
depth=0.0);
# create some handy timers# global clock to track the time since experiment startedifglobalClockisNone:
# create a clock if not given oneglobalClock=core.Clock()
ifisinstance(globalClock, str):
# if given a string, make a clock accoridng to itifglobalClock=='float':
# get timestamps as a simple valueglobalClock=core.Clock(format='float')
elifglobalClock=='iso':
# get timestamps in ISO formatglobalClock=core.Clock(format='%Y-%m-%d_%H:%M:%S.%f%z')
else:
# get timestamps in a custom formatglobalClock=core.Clock(format=globalClock)
ifioServerisnotNone:
ioServer.syncClock(globalClock)
logging.setDefaultClock(globalClock)
# routine timer to track time remaining of each (possibly non-slip) routineroutineTimer=core.Clock()
win.flip() # flip window to reset last flip timer# store the exact time the global clock startedexpInfo['expStart'] =data.getDateStr(
format='%Y-%m-%d %Hh%M.%S.%f %z', fractionalSecondDigits=6
)
# set up handler to look after randomisation of conditions etcreps=data.TrialHandler2(
name='reps',
nReps=10.0,
method='sequential',
extraInfo=expInfo,
originPath=-1,
trialList=[None],
seed=None,
)
thisExp.addLoop(reps) # add the loop to the experimentthisRep=reps.trialList[0] # so we can initialise stimuli with some values# abbreviate parameter names if possible (e.g. rgb = thisRep.rgb)ifthisRep!=None:
forparamNameinthisRep:
globals()[paramName] =thisRep[paramName]
ifthisSessionisnotNone:
# if running in a Session with a Liaison client, send data up to nowthisSession.sendExperimentData()
forthisRepinreps:
currentLoop=repsthisExp.timestampOnFlip(win, 'thisRow.t', format=globalClock.format)
ifthisSessionisnotNone:
# if running in a Session with a Liaison client, send data up to nowthisSession.sendExperimentData()
# abbreviate parameter names if possible (e.g. rgb = thisRep.rgb)ifthisRep!=None:
forparamNameinthisRep:
globals()[paramName] =thisRep[paramName]
# --- Prepare to start Routine "trial" ---# create an object to store info about Routine trialtrial=data.Routine(
name='trial',
components=[text],
)
trial.status=NOT_STARTEDcontinueRoutine=True# update component parameters for each repeattext.setText("TRIAL COUNT (OUT OF 10): "+str(reps.thisN)+"\n\nnRemaining: "+str(reps.nRemaining))
# store start times for trialtrial.tStartRefresh=win.getFutureFlipTime(clock=globalClock)
trial.tStart=globalClock.getTime(format='float')
trial.status=STARTEDthisExp.addData('trial.started', trial.tStart)
trial.maxDuration=None# keep track of which components have finishedtrialComponents=trial.componentsforthisComponentintrial.components:
thisComponent.tStart=NonethisComponent.tStop=NonethisComponent.tStartRefresh=NonethisComponent.tStopRefresh=Noneifhasattr(thisComponent, 'status'):
thisComponent.status=NOT_STARTED# reset timerst=0_timeToFirstFrame=win.getFutureFlipTime(clock="now")
frameN=-1# --- Run Routine "trial" ---# if trial has changed, end Routine nowifisinstance(reps, data.TrialHandler2) andthisRep.thisN!=reps.thisTrial.thisN:
continueRoutine=Falsetrial.forceEnded=routineForceEnded=notcontinueRoutinewhilecontinueRoutineandroutineTimer.getTime() <1.0:
# get current timet=routineTimer.getTime()
tThisFlip=win.getFutureFlipTime(clock=routineTimer)
tThisFlipGlobal=win.getFutureFlipTime(clock=None)
frameN=frameN+1# number of completed frames (so 0 is the first frame)# update/draw components on each frame# *text* updates# if text is starting this frame...iftext.status==NOT_STARTEDandtThisFlip>=0.0-frameTolerance:
# keep track of start time/frame for latertext.frameNStart=frameN# exact frame indextext.tStart=t# local t and not account for scr refreshtext.tStartRefresh=tThisFlipGlobal# on global timewin.timeOnFlip(text, 'tStartRefresh') # time at next scr refresh# add timestamp to datafilethisExp.timestampOnFlip(win, 'text.started')
# update statustext.status=STARTEDtext.setAutoDraw(True)
# if text is active this frame...iftext.status==STARTED:
# update paramspass# if text is stopping this frame...iftext.status==STARTED:
# is it time to stop? (based on global clock, using actual start)iftThisFlipGlobal>text.tStartRefresh+1.0-frameTolerance:
# keep track of stop time/frame for latertext.tStop=t# not accounting for scr refreshtext.tStopRefresh=tThisFlipGlobal# on global timetext.frameNStop=frameN# exact frame index# add timestamp to datafilethisExp.timestampOnFlip(win, 'text.stopped')
# update statustext.status=FINISHEDtext.setAutoDraw(False)
# check for quit (typically the Esc key)ifdefaultKeyboard.getKeys(keyList=["escape"]):
thisExp.status=FINISHEDifthisExp.status==FINISHEDorendExpNow:
endExperiment(thisExp, win=win)
return# pause experiment here if requestedifthisExp.status==PAUSED:
pauseExperiment(
thisExp=thisExp,
win=win,
timers=[routineTimer],
playbackComponents=[]
)
# skip the frame we paused oncontinue# check if all components have finishedifnotcontinueRoutine: # a component has requested a forced-end of Routinetrial.forceEnded=routineForceEnded=TruebreakcontinueRoutine=False# will revert to True if at least one component still runningforthisComponentintrial.components:
ifhasattr(thisComponent, "status") andthisComponent.status!=FINISHED:
continueRoutine=Truebreak# at least one component has not yet finished# refresh the screenifcontinueRoutine: # don't flip if this routine is over or we'll get a blank screenwin.flip()
# --- Ending Routine "trial" ---forthisComponentintrial.components:
ifhasattr(thisComponent, "setAutoDraw"):
thisComponent.setAutoDraw(False)
# store stop times for trialtrial.tStop=globalClock.getTime(format='float')
trial.tStopRefresh=tThisFlipGlobalthisExp.addData('trial.stopped', trial.tStop)
# using non-slip timing so subtract the expected duration of this Routine (unless ended on request)iftrial.maxDurationReached:
routineTimer.addTime(-trial.maxDuration)
eliftrial.forceEnded:
routineTimer.reset()
else:
routineTimer.addTime(-1.000000)
thisExp.nextEntry()
# completed 10.0 repeats of 'reps'ifthisSessionisnotNone:
# if running in a Session with a Liaison client, send data up to nowthisSession.sendExperimentData()
# mark experiment as finishedendExperiment(thisExp, win=win)
defsaveData(thisExp):
""" Save data from this experiment Parameters ========== thisExp : psychopy.data.ExperimentHandler Handler object for this experiment, contains the data to save and information about where to save it to. """filename=thisExp.dataFileName# these shouldn't be strictly necessary (should auto-save)thisExp.saveAsWideText(filename+'.csv', delim='auto')
thisExp.saveAsPickle(filename)
defendExperiment(thisExp, win=None):
""" End this experiment, performing final shut down operations. This function does NOT close the window or end the Python process - use `quit` for this. Parameters ========== thisExp : psychopy.data.ExperimentHandler Handler object for this experiment, contains the data to save and information about where to save it to. win : psychopy.visual.Window Window for this experiment. """ifwinisnotNone:
# remove autodraw from all current componentswin.clearAutoDraw()
# Flip one final time so any remaining win.callOnFlip() # and win.timeOnFlip() tasks get executedwin.flip()
# return console logger level to WARNINGlogging.console.setLevel(logging.WARNING)
# mark experiment handler as finishedthisExp.status=FINISHEDlogging.flush()
defquit(thisExp, win=None, thisSession=None):
""" Fully quit, closing the window and ending the Python process. Parameters ========== win : psychopy.visual.Window Window to close. thisSession : psychopy.session.Session or None Handle of the Session object this experiment is being run from, if any. """thisExp.abort() # or data files will save again on exit# make sure everything is closed downifwinisnotNone:
# Flip one final time so any remaining win.callOnFlip() # and win.timeOnFlip() tasks get executed before quittingwin.flip()
win.close()
logging.flush()
ifthisSessionisnotNone:
thisSession.stop()
# terminate Python processcore.quit()
# if running this experiment as a script...if__name__=='__main__':
# call all functions in orderexpInfo=showExpInfoDlg(expInfo=expInfo)
thisExp=setupData(expInfo=expInfo)
logFile=setupLogging(filename=thisExp.dataFileName)
win=setupWindow(expInfo=expInfo)
setupDevices(expInfo=expInfo, thisExp=thisExp, win=win)
run(
expInfo=expInfo,
thisExp=thisExp,
win=win,
globalClock='float'
)
saveData(thisExp=thisExp)
quit(thisExp=thisExp, win=win)
```python### Additional context_Noresponse_
The text was updated successfully, but these errors were encountered:
PsychoPy Version
2024.2.1
What OS are your PsychoPy running on?
Windows 11
Bug Description
Hi! With the new TrialHandler2 trials.nRemaining is no longer updated while experiment is running
Expected Behaviour
nRemaining should be up-to-date at each trial within the loop (or at least removed from the docs I guess!)
Steps to Reproduce
Since I cannot attach a .psyexp file here, you could save the code below as a .py file and run it in Psychopy Standalone 2024.2.1
The text was updated successfully, but these errors were encountered: