Skip to content

Instantly share code, notes, and snippets.

@jeremygray
Created October 9, 2012 11:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremygray/3858062 to your computer and use it in GitHub Desktop.
Save jeremygray/3858062 to your computer and use it in GitHub Desktop.
run 20,000 trials of PsychoPy, save all data formats
#!/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 jrgray@gmail.com 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