psychopy.org | Reference | Downloads | Github

Conditional stimulus timing

OS (e.g. Win10): 10.14.6
PsychoPy version (e.g. 1.84.x): 3.1.5

I have a very simple requirement whereby I need a trial where the subject looks at a fixation cross and presses a key (‘p’) when they feel like it.
This will immediately present one visual stimulus (called GO) , and 500ms later a different visual stimulus (called TARGET) and a beep

The way I thought I could do this is to have a code component at every frame

if event.getKeys(['p']):
    if press == False:
        press = True
        outcomeTimer = t+.05

and have as start for GO a conditional on press and as start for the TARGET stimuli a conditional

press and t>= outcomeT

However, this does produce poor timing: both GO and both TARGETs are displayed concurrently pretty much at the time of the press. increasing outcomeTimer to t+.1 separates the two.

Tried to upload a zip file with all of the stuff but cannot

many thanks for any suggestions on how to solve this

Hi Marc,

This can all be done without any code. Simply split your trial across two routines. The first shows the fixation cross, with an indefinite duration, and a keyboard component set to “force end of routine”. The second starts with your visual stimulus at time 0, the second at time 0.5, etc.

i.e. the keypress ending the first routine automatically and immediately brings up the stimuli in the second routine.

1 Like

Hello Michael,
thanks for this suggestion, which solves a lot of my problems.

There is one further issue, which probably has a similarly easy solution, that I cannot seem to crack in Builder:

I also need to have a keyboard event that serves as an anticipation response:
i.e. I need the keyboard to listen for a keypress, which may happen BEFORE or AFTER the target, and the trial should end when the target finished AND the keypress was registered.

at the moment I have a keypress event with condition (empty) and a piece of code for each frame that says

if target.status == -1 and BaselineAnticipation.getKeys(keyList=['space']) != []:
    continueRoutine = False

but that does not work.
Debugging suggest that BaselineAnticipation.getKeys(keyList=[‘space’] remains as [] even when SPACE has been pressed

BaselineAnticipation is the keyboard event, which starts at 0 and ends on condition (empty), with force end routine unchecked , but store last key

Any pointers?

hmmm. Seemed to have solved it myself by replacing

if target.status == -1 and BaselineAnticipation.getKeys(keyList=[‘space’]) != []:
    continueRoutine = False

with

if target.status == -1 and BaselineAnticipation.keys != []:
    continueRoutine = False

But really puzzled as to WHY this works?
BaselineAnticipation.keys is defined only further down in the code, and the check above, which happens every frame thus should have something undefined in the conditional?

It is good to adopt that skeptical approach, rather than just accept that it works, because otherwise you might get tripped up by unexpected behaviours.

The answer is that when you create a Keyboard object, it comes with a batch of properties and methods defined for it:

>>> from psychopy.hardware import keyboard
>>> k = keyboard.Keyboard()
>>> k.keys
[]

i.e. .keys is initialised as an empty list. If a Keyboard object didn’t already have a .keys attribute defined, then we would get an error when trying to assign to it.

When in doubt, if you want to know what attributes an object has, use the dir() function:

>>> dir(k)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', 
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'__weakref__', '_buffers', '_devs', '_ids', 'clearEvents', 'clock', 
'corr', 'getKeys', 'keys', 'rt', 'start', 'status', 'stop', 'time', 
'waitKeys']

many of the “dunder” ones (ones with double underscores) can be ignored as they are generally generic things Python needs. The ones that are likely of most interest to you are at the end of the list.

Lastly, for clarity, please do this for posting code (have edited the posts above):

1 Like