Created
October 9, 2012 11:20
-
-
Save jeremygray/3858062 to your computer and use it in GitHub Desktop.
run 20,000 trials of PsychoPy, save all data formats
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
""" | |
This script allows you to test whether your computer can run 20,000 trials using PsychoPy. | |
It attempts to run 20 repetitions of 1000 trials, and will save a .psydat files in ./data/ | |
for each loop, plus a single .dlm, .csv, .xlsx, and .log files. | |
INSTRUCTIONS: | |
Just run the script from within the coder window (or from the command line) and let it run. | |
Don't press any keys or change the window focus. | |
When the script runs, you'll see a small window with the current trial number (e.g., 0020, | |
19436). There should be 10 trials done per second (done using automatic "key-presses" | |
simulating user responses). | |
EXPECTED behavior (= good): | |
If all goes well, you should see the numbers scroll by smoothly. After 2,000 seconds (at | |
10 trials / sec), you'll have all the data files. The .dlm file should have 20,020 lines. | |
Other files should look sensible, too, but .dlm is the easiest one to check. | |
Okay behavior: | |
If the visual display is jumpy (rather than smooth), try setting `trialLen` to be longer. | |
Its possible that some of the automatic key-presses will be missed, and the program will | |
appear to be stuck on a 999 trial (such as 4999). If this happens, just press 'n' until | |
it starts again. | |
It may also become slow between blocks of 1000 trials--just give it some time then, it may | |
take several seconds on a 999 trial, that is normal. | |
<escape> should work, but you may need to press it several times before it will quit the | |
program. | |
UNEXPECTED behavior (= bad): | |
If there are any errors or the program crashes, that is a bad sign. If it stops at any other trial number (non-999), try running again but with a longer value of `trialLen`, perhaps 0.2 or 0.3. If it still does not run all the way through, its a bad sign. | |
QUESTIONS? | |
Email [email protected] and describe your situation. I'll do what I can but can't promise to | |
fix everything. | |
---------------------- | |
This experiment was created using PsychoPy2 Experiment Builder (v1.74.03), and then tweaked. | |
If you publish work using this script please cite the relevant PsychoPy publications | |
Peirce, JW (2007) PsychoPy - Psychophysics software in Python. Journal of Neuroscience Methods, 162(1-2), 8-13. | |
Peirce, JW (2009) Generating stimuli for neuroscience using PsychoPy. Frontiers in Neuroinformatics, 2:10. doi: 10.3389/neuro.11.010.2008 | |
""" | |
from __future__ import division # so that 1/3=0.333 instead of 1/3=0 | |
from psychopy import visual, core, data, event, logging, gui | |
from psychopy.constants import * # things like STARTED, FINISHED | |
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 | |
import os # handy system and path functions | |
# Store info about the experiment session | |
expName = 'None' # from the Builder filename that created this script | |
expInfo = {u'session': u'001', u'participant': u'test_20K'} | |
expInfo['date'] = data.getDateStr() # add a simple timestamp | |
expInfo['expName'] = expName | |
# Setup files for saving | |
if not os.path.isdir('data'): | |
os.makedirs('data') # if this fails (e.g. permissions) we will get error | |
filename = 'data' + os.path.sep + '%s_%s' %(expInfo['participant'], expInfo['date']) | |
logFile = logging.LogFile(filename+'.log', level=logging.EXP) | |
logging.console.setLevel(logging.WARNING) # this outputs to the screen, not a file | |
# An ExperimentHandler isn't essential but helps with data saving | |
thisExp = data.ExperimentHandler(name=expName, version='', | |
extraInfo=expInfo, runtimeInfo=None, | |
originPath=None, | |
savePickle=True, saveWideText=True, | |
dataFileName=filename) | |
# Setup the Window | |
win = visual.Window(size=[80, 60], fullscr=False, screen=0, allowGUI=True, allowStencil=False, | |
monitor=u'testMonitor', color=[0,0,0], colorSpace=u'rgb') | |
# Initialize components for Routine "trial" | |
trialClock = core.Clock() | |
text = visual.TextStim(win=win, ori=0, name='text', | |
text='nonsense', | |
font='Arial', | |
pos=[0, 0], height=0.6, wrapWidth=None, | |
color='white', colorSpace='rgb', opacity=1, | |
depth=0.0) | |
from psychopy.hardware.emulator import ResponseEmulator | |
extra = 5 | |
n = 1000 + extra # extra just in case a couple get dropped | |
trialLen = 0.1 | |
offset = 0.1 | |
t = linspace(offset, offset + trialLen * n, n) # times | |
r = ['y'] * n # responses | |
sim = zip(t,r) # pair them up | |
# 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 | |
# set up handler to look after randomisation of conditions etc | |
trials_2 = data.TrialHandler(nReps=20, method=u'random', | |
extraInfo=expInfo, originPath=None, | |
trialList=[None], | |
seed=None, name='trials_2') | |
thisExp.addLoop(trials_2) # add the loop to the experiment | |
thisTrial_2 = trials_2.trialList[0] # so we can initialise stimuli with some values | |
# abbreviate parameter names if possible (e.g. rgb=thisTrial_2.rgb) | |
if thisTrial_2 != None: | |
for paramName in thisTrial_2.keys(): | |
exec(paramName + '= thisTrial_2.' + paramName) | |
for thisTrial_2 in trials_2: | |
currentLoop = trials_2 | |
# abbreviate parameter names if possible (e.g. rgb = thisTrial_2.rgb) | |
if thisTrial_2 != None: | |
for paramName in thisTrial_2.keys(): | |
exec(paramName + '= thisTrial_2.' + paramName) | |
# set up handler to look after randomisation of conditions etc | |
trials = data.TrialHandler(nReps=(n - extra), method='random', | |
extraInfo=expInfo, originPath=None, | |
trialList=[None], | |
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.keys(): | |
exec(paramName + '= thisTrial.' + paramName) | |
responder = ResponseEmulator(sim) | |
responder.start() | |
core.runningThreads.append(responder) | |
for thisTrial in trials: | |
currentLoop = trials | |
# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb) | |
if thisTrial != None: | |
for paramName in thisTrial.keys(): | |
exec(paramName + '= thisTrial.' + paramName) | |
#------Prepare to start Routine"trial"------- | |
t = 0 | |
trialClock.reset() # clock | |
frameN = -1 | |
# update component parameters for each repeat | |
text.setText(str(trials_2.thisN) + str(trials.thisN).zfill(3)) | |
key_resp = event.BuilderKeyResponse() # create an object of type KeyResponse | |
key_resp.status = NOT_STARTED | |
# keep track of which components have finished | |
trialComponents = [] | |
trialComponents.append(text) | |
trialComponents.append(key_resp) | |
for thisComponent in trialComponents: | |
if hasattr(thisComponent, 'status'): | |
thisComponent.status = NOT_STARTED | |
#-------Start Routine "trial"------- | |
continueRoutine = True | |
while continueRoutine: | |
# get current time | |
t = trialClock.getTime() | |
frameN = frameN + 1 # number of completed frames (so 0 is the first frame) | |
# update/draw components on each frame | |
# *text* updates | |
if t >= 0.0 and text.status == NOT_STARTED: | |
# keep track of start time/frame for later | |
text.tStart = t # underestimates by a little under one frame | |
text.frameNStart = frameN # exact frame index | |
text.setAutoDraw(True) | |
# *key_resp* updates | |
if t >= 0.0 and key_resp.status == NOT_STARTED: | |
# keep track of start time/frame for later | |
key_resp.tStart = t # underestimates by a little under one frame | |
key_resp.frameNStart = frameN # exact frame index | |
key_resp.status = STARTED | |
# keyboard checking is just starting | |
key_resp.clock.reset() # now t=0 | |
event.clearEvents() | |
if key_resp.status == STARTED: # only update if being drawn | |
theseKeys = event.getKeys(keyList=['y', 'n']) | |
if len(theseKeys) > 0: # at least one key was pressed | |
key_resp.keys = theseKeys[-1] # just the last key pressed | |
key_resp.rt = key_resp.clock.getTime() | |
# was this 'correct'? | |
if (key_resp.keys == str("'y'")): key_resp.corr = 1 | |
else: key_resp.corr=0 | |
# abort routine on response | |
continueRoutine = False | |
# check if all components have finished | |
if not continueRoutine: # a component has requested that we end | |
routineTimer.reset() # this is the new t0 for non-slip Routines | |
break | |
continueRoutine = False # will revert to True if at least one component still running | |
for thisComponent in trialComponents: | |
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED: | |
continueRoutine = True | |
break # at least one component has not yet finished | |
# check for quit (the [Esc] key) | |
if event.getKeys(["escape"]): | |
core.quit() | |
# refresh the screen | |
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen | |
win.flip() | |
#-------Ending Routine "trial"------- | |
for thisComponent in trialComponents: | |
if hasattr(thisComponent, "setAutoDraw"): | |
thisComponent.setAutoDraw(False) | |
# check responses | |
if len(key_resp.keys) == 0: # No response was made | |
key_resp.keys=None | |
# was no response the correct answer?! | |
if str("'y'").lower() == 'none': key_resp.corr = 1 # correct non-response | |
else: key_resp.corr = 0 # failed to respond (incorrectly) | |
# store data for trials (TrialHandler) | |
trials.addData('key_resp.keys',key_resp.keys) | |
trials.addData('key_resp.corr', key_resp.corr) | |
if key_resp.keys != None: # we had a response | |
trials.addData('key_resp.rt', key_resp.rt) | |
thisExp.nextEntry() | |
# completed n repeats of 'trials' | |
# get names of stimulus parameters | |
if trials.trialList in ([], [None], None): params = [] | |
else: params = trials.trialList[0].keys() | |
# save data for this loop | |
trials.saveAsPickle(filename + 'trials', fileCollisionMethod='rename') | |
trials.saveAsExcel(filename + '.xlsx', sheetName='trials', | |
stimOut=params, | |
dataOut=['n','all_mean','all_std', 'all_raw']) | |
trials.saveAsText(filename + 'trials.csv', delim=',', | |
stimOut=params, | |
dataOut=['n','all_mean','all_std', 'all_raw']) | |
thisExp.nextEntry() | |
# completed 100 repeats of 'trials_2' | |
# get names of stimulus parameters | |
if trials_2.trialList in ([], [None], None): params = [] | |
else: params = trials_2.trialList[0].keys() | |
# save data for this loop | |
trials_2.saveAsPickle(filename + 'trials_2', fileCollisionMethod='rename') | |
trials_2.saveAsExcel(filename + '.xlsx', sheetName='trials_2', | |
stimOut=params, | |
dataOut=['n','all_mean','all_std', 'all_raw']) | |
trials_2.saveAsText(filename + 'trials_2.csv', delim=',', | |
stimOut=params, | |
dataOut=['n','all_mean','all_std', 'all_raw']) | |
# Shutting down: | |
win.close() | |
core.quit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment