Fixed stimulus duration chosen randomly

I am new to Psychopy, I have a question about inserting a jitter for a fixation point. It is important to note that while the fixation point must be jittered, there are a fixed number of presentation times that must be used. For example, if there are 5 trials in a block, the fixation presentation time would need to be randomly chosen from a list of 5 times (2s, 2.5s, 3s, 3.5s, 4s). These would be exactly the same for each participant, but the order would be random.
In this experiment, each trial looks like this: Fixation (text file) -> Image with a response required -> wait -> Fixation… and so on.
Suppose the Excel file guiding the block of trials looks like this:

Fixation Image CorrectResponse
2.0 A left
2.5 B right
3.0 C left
3.5 D right
4.0 E left

The values in the fixation column are times in seconds. In the Builder view, the duration of the fixation point (which is a text object) is set to $Fixation. Doing this causes problems because Image A will always have a 2 second fixation preceding it, Image B a 2.5 second fixation preceding it, and so on.
I want the routine to randomly choose a value from the Fixation column for each fixation duration, while keeping the Image/Correct Response columns tied to each other (but still chosen independently from the Fixation column). I am certain I will need to do this in Coder view, but am unsure how to do it. Any help would be appreciated. Thank you.

The easiest way to get independent randomisation of that variable is to remove it from your conditions file and handle the randomisation in code instead. i.e. insert a Code Component on the routine with the fixation stimulus and in the “Begin Routine” tab of its window, put something like this:

if your_loop_name.thisN == 0: # only on the first trial
    jitters = [2.0, 2.5, 3.0, 3.5, 4.0] # create the list
    shuffle(jitters) # randomise its order

current_jitter = jitters.pop() # extract one entry on each trial
thisExp.addData('jitter', current_jitter) # record in the data for this trial

Ensure that the code component appears above your fixation stimulus (so that the variable is produced before it needs to be accessed), and then you can simply insert this in its duration field:

$current_jitter

Worked like a charm. Thanks for the help.

I actually have a follow up question. The randomization code works as intended, but I have one more small issue. Between the offset of the random fixation point and the onset of the image, I need a 300ms delay that is just a blank screen. I have an object that does this (a 300ms blank screen), but because each fixation has a random duration, I don’t know how to set the onset of the blank screen to correspond to the offset of each random fixation. Any help would be appreciated. Thank you.

There are several alternatives:

  1. Split the trial into several consecutive routines, then each stimulus can have an onset time of zero, automatically following on from the previous one.
  2. Put the stimuli in the same routine, and explicitly specify their start time as well as the duration. ie the first stimulus has a constant onset of 0 and a duration of current_jitter, so the next stimulus has a variable onset of current_jitter and a constant duration of 0.3 while the last has an onset time of current_jitter + 0.3, and so on.

I have a short follow-up question. I am applying what you wrote above, just with some modifications at the time of the jitters, like this (Begin Routine above the text of the fixation cross):

if trials.thisN == 0: # only on the first trial
    jitters = [4.0, 6.0, 8.0] # create the list
    shuffle(jitters) # randomise its order

current_jitter = jitters.pop() # extract one entry on each trial
thisExp.addData('jitter', current_jitter) # record in the data for this trial

After three trials (one with jitter 4, one with jitter 6 and one with jitter 8, randomly), the experiment crashes and I get the following error:

current_jitter = jitters.pop() # extract one entry on each trial
IndexError: pop from empty list

Did you get some error like this. I am using PsychoPy v1.85.3, if that can help.

The error message and your description tells you what is happening. Your list contains three elements. After the third trial, all elements have been removed from the list (that is what .pop() does).

You simply need to have the length of the list match your number of trials. e.g. if you have 9 trials, you could do this:

jitters = [4.0, 6.0, 8.0] * 3
1 Like

Thank you very much, Michael, I will do it like this.

Also, today, while trying to figure this out, I found another way that seems to work. I kept the Begin Routine as above, but then I added a part of the Begin Routine also to Each Frame, namely this:

jitters = [4, 6, 8] # create the list
shuffle(jitters) # randomise its order

Maybe this could be a solution in those cases in which you don´t know how many trials the participant will perform. However, I am not sure whether there are some bad consequences.

The consequence is that because you are continually re-creating the list of jitters (at typically 60 times per second for code in the “each frame” tab") then you aren’t maintaining any balancing of the jitter values (they are effectively just being randomly selected, with replacement). Maybe that isn’t important to you though.

But also you’re having two pieces of code running on vastly different time scales. i.e. you only need to choose a jitter value once per trial, yet you are re-populating the list they are sampled from at 60 times per second. That kind of disconnect (although probably not intentional) doesn’t make the code easy to predict or understand.

I’d suggest that you specify what your experimental design constraints are with respect to selection of your jitter values, and implement that in code in a planned way, rather than randomly cut and paste snippets of code.

1 Like

Hi, I have just started using psychopy today and was wondering where would this
$current_jitter go?

In this case, the OP was asking for a jittered duration for a fixation point. So $current_jitter would go in the “duration (s)” field of the stimulus being used for the fixation point.

Hi! I have followed your answers here but I am still getting this error:

line 877
    if bool(asarray($current_Soa)):
                    ^
SyntaxError: invalid syntax

This is what I have added in begin routine of the routine containing an image I want to variably display

if G_trial.thisN == 0: # only on the first trial
    soa_durations = [.15, .3, .9]*16 # create the list
    shuffle(soa_durations) # randomise its order

current_Soa = soa_durations.pop() # extract one entry on each trial
thisExp.addData('soa', current_Soa) # record in the data for this trial

It looks like the error there is simply due to having a $ sign before your variable name where perhaps it isn’t needed. If not, we would probably need to see a screenshot of the component where you use $current_Soa to understand its context.