OS: macOS Sequoia 15.3.2
PsychoPy version: 2024.2.4 Py 3.10
Standard Standalone Installation? (y/n): y
Do you want it to also run online? (y/n): y
What are you trying to achieve?:
Update on- and offset timing based on click responses within a routine
What did you try to make it work?:
Hi everyone,
I am working on mnemonic discrimination task using image stimuli in a 2-back format. The routine consists of a sequence of 4 images including 2 original and 2 repetitions. For repetitions 1 and 2 participants are supposed to give an old/new answer based on mouse clicks (either on a button āoldā or on the image itself whereupon feedback is shown).
What is a trial?: A trial consists of sequence of four stimuli, 2 original images followed by 2 repetitions of those images. I am showing the original images for 5s each with a 1s break inbetween. The first and second repeated images are either exact repetitions of the first and second original image or are very similar lures. The repetitions are each shown for 15s and involve the participant to respond via a mouse click whether the repetitions is indeed the old stimulus shown before or a similar but new one. If there is no click the events are thus:
OrigImg1(5s) - 1s - OrigImg2(5s) - 1s - RepImg1(15s) - 1s - RepImg2(15s).
However, if a participant makes a response on RepImg1, I donāt want them to wait the full 15s. Upon the response they should see the feedback for 0.75s, have the 1s break and then should already see RepImg2. This means that offset of RepImg1 and onset of RepImg2 have to be updated based on the click time.
One way of achieving this is probably to leave the start/stop tabs in the builder component blank and condition the on and offsets via setAutoDraw to either a response click or elapsed time. However, I was wondering whether it would in principle work to update onsets and offsets where the logic would be something like if click, then offset1 = timeOfClick + 0.75 as was similarly suggested here using keypresses: Variable feedback timing and total trial time question - #6 by jderrfuss
My approach: Define default onsets and offsets in the Begin routine tab and update them in Each frame if a response was made.
Begin routine:
# initialize dynamic onset variables
def_onset_1 = stim_dur*2+2
def_onset_2 = stim_dur*2+3+rep_dur
def_onset_fb1 = stim_dur*2+2+rep_dur
def_onset_fb2 = stim_dur*2+3+rep_dur*2
onset_1 = def_onset_1 # start with defaults
onset_2 = def_onset_2
onset_fb1 = def_onset_fb1
onset_fb2 = def_onset_fb2
# initialize dynamic offset variables
def_offset_1 = stim_dur*2+2+rep_dur+0.75
def_offset_2 = stim_dur*2+3+rep_dur*2+0.75
def_offset_mouse1 = stim_dur*2+2+rep_dur
def_offset_mouse2 = stim_dur*2+2+rep_dur*2
offset_1 = def_offset_1 # start with defaults
offset_2 = def_offset_2
offset_mouse1 = def_offset_mouse1
offset_mouse2 = def_offset_mouse2
# initialize clicks: if no click, use default timings
click1 = def_offset_1
click2 = def_offset_2
Specifically, based on the timing of the first response, I want participants to get feedback right away (for 0.75 s), have a 1-second delay and then immediately present the second repetition (not waiting for the default offset). I was trying this:
Each frame:
if len(mouseRepeat1.clicked_name) > 0:
click1 = mouseRepeat1.getPressed(getTime=True)[0][1]
onset_fb1 = click1
offset_mouse1 = click1
offset_1 = click1 + 0.75
onset_2 = click1 + 1.75
if mouseRepeat1.clicked_name[0] == 'imageButton1':
frameButton1.opacity = 1
feedbackCorrect1.opacity = 1 if repeat1 == stim1 else 0
feedbackIncorrect1.opacity = 1 if repeat1 != stim1 else 0
elif mouseRepeat1.clicked_name[0] == 'imageRepeat1':
imageFrame1.opacity = 1
feedbackCorrect1.opacity = 1 if repeat1 != stim1 else 0
feedbackIncorrect1.opacity = 1 if repeat1 == stim1 else 0
if len(mouseRepeat2.clicked_name) > 0:
click2 = mouseRepeat2.getPressed(getTime=True)[0][1]
onset_fb2 = click2
offset_mouse2 = click2
offset_2 = click2 + 0.75
if mouseRepeat2.clicked_name[0] == 'imageButton2':
frameButton2.opacity = 1
feedbackCorrect2.opacity = 1 if repeat2 == stim2 else 0
feedbackIncorrect2.opacity = 1 if repeat2 != stim2 else 0
elif mouseRepeat2.clicked_name[0] == 'imageRepeat2':
imageFrame2.opacity = 1
feedbackCorrect2.opacity = 1 if repeat2 != stim2 else 0
feedbackIncorrect2.opacity = 1 if repeat2 == stim2 else 0
# make sure mouse cursor is only visible when needed:
if onset_1 <= myClock.getTime() <= click1:
if onset1 == 1:
onset1 = onset1 + 1
mouseRepeat1.setPos([0,0])
win.mouseVisible = True
elif onset_2 < myClock.getTime() <= click2:
if onset1 == 2:
onset1 = onset1 + 1
mouseRepeat2.setPos([0,0])
win.mouseVisible = True
else:
win.mouseVisible = False
What specifically went wrong when you tried that?:
The code works for updating the feedback onsets as they are directly triggered by the timing of the clicks (click1 and click2). However, something like onset_2 = click1 + 1.75 does not result in āwaitingā 1.75 s since click1 but also sets onset_2 to the click1-timepoint. What can I do? Iād be happy for any advice!