Implementing "conditional routines"

I have a task where the participant is shown different stimuli in a loop of 80 trials. 8 of those trials should be followed by a question about the stimulus (“Was the object in the image an animal or a vehicle?”). The 8 trials that are to be followed by a question are to be picked randomly - I can set that up using functionality from Python’s random module.

What I’m wondering is what the best way is to insert a “conditional routine” the way I’m describing here. In pseudocode, what I want is

if current_trial_should_be_followed_by_question:
    do the 'question' routine

In the Builder, I can of course insert a ‘question routine’ in the trial loop and add a code snippet that, at the beginning of each routine iteration, checks if the ‘run question routine’ variable is set to False. If the variable is set to False, the snippet would assign continueRoutine = False, otherwise it would proceed with code for asking the question and fetching the participant response. But I don’t know if this leads to issues with e. g. timing. If I assign continueRoutine = False at “Begin Routine”, would a frame have to pass before the routine is ended? In that case I’m guessing there’s a better solution, but I haven’t been able to think of one.

I’d greatly appreciate any help with this.

Update for anyone who stumbles upon this thread in the future:

So after looking around more I found this previous thread on a similar subject. There, Michael linked to a closed issue on PsychoPy’s github project. As far as I understand, the method I described above is actually recommended (though it seemed like a hack to me). One has to make sure to have one of the most recent versions of PsychoPy though, because of differences in previous versions regarding at what point the default continueRoutine value is set.

What I ended up doing was:

### 'Begin Experiment'

# import function for randomly determining when to pose post-trial
# question
from random import shuffle

# generate list of boolean values which specify if a post-trial
# question should be posed ("Was there an animal in the picture?")
post_trial_bools = [False] * 40 + [True] * 40
# initialize counter for going through post_trial_bools values
post_trial_counter = 0
### Begin Routine

# check if post-trial question should be posed, and otherwise
# skip it
post_trial_bool = post_trial_bools[post_trial_counter]
if not post_trial_bool:
    continueRoutine = False

### End Routine
post_trial_counter += 1

I don’t recommend using that method: (continueRoutine=False) The reason for it: it can fail if you have a video in the conditional routine, and it is a really bad kind of hack.

I often had the error that was related to opening and closing video in the same frame (OpenGL OSError). Besides it is a hack, since Routine code and even Frame code runs once instead of not running on a conditional routine, which should be the preferred logic. (If something is not to be run, then code associated with it should not be running as well, except for whole experiment code).

I had to use a secondary hack to work without the session collapsing, which was to use ‘continue’ (next loop iteration, because it was in a loop) instead of 'continueRoutine=False`, however, this you can only use if the conditional routine is within a loop AND it is the last routine in the loop you want to see or not. This however avoided the video collapse, because video load came after this.

The other problem I faced, that in version 2020.1 this only worked if continueRoutine=False was put into “every frame” slot, but in 2020.2 it was (correctly) needed to be put into “every routine” slot. So it is not stable.

The correct and most clean way is to use a loop around the conditional routine. This way you can put the conditional directly into the number of loops and surround it with an int conversion. Like this: $int(myConditional)) . This routine will be running when myConditional is True and not run when myConditional is False. This is not a hack, because this really prevents the whole routine with the code to execute.

1 Like

I posted about this subject just an hour ago and am so happy I found your response! This was a great help and I can now stop spending hours on this one issue. Thanks!