Stimuli updating out of sync of each other

Hello all,
I’m running into a somewhat baffling problem regarding the timing of stimuli. I have a list of stimuli called streams (len(streams) is from 1-6) that are each presented accordingly (please note this is only the most relevant code to the problem, not the entirety of the experiment):

 # Iterate over the letters in each stream and display them appropriately
        for letters, T_nearby in trial.stream:
            T_in_stream = "T" in letters
            streams = reposition(streams, len(letters))  # Reposition each stimuli to the correct place                
            
            # Take every letter and assign it to a stimuli in streams.  Then display the stimulus
            for j in range(len(letters)):
                stream = streams[j]
                stream.text = letters[j]
                
                if stream.status == NOT_STARTED and tThisFlipGlobal >= heads_up.tStopRefresh - frame_tolerance:
                    stream.status = STARTED
                    stream.tStartRefresh = tThisFlipGlobal
                    win.timeOnFlip(stream, "tStartRefresh")
                    stream.setAutoDraw(True)
                if stream.status == STARTED:
                    if tThisFlipGlobal > stream.tStartRefresh + .4 - frame_tolerance: # 24 frames = 400 ms
                        stream.status = FINISHED
                        win.timeOnFlip(stream, "tStopRefresh")
                        stream.setAutoDraw(False)

            if continueRoutine:
                core.wait(0.4)
                win.flip()

And here is a video of a few trials of the experiment being run:

I have several questions about the discrepancy between expected behavior from this code and actual behavior:

  1. On some of these flips, the letters are not in sync when they change. How is this even possible, since they all should be drawn and redrawn on the same flip?

  2. Similarly to 1, at the beginning of each stream only one letter shows at a time, then it eventually corrects to showing all letters. I have confirmed that the list of letters letters contains the appropriate amount of letters to be displayed each time, so I’m not sure why it only works some of the time

  3. Currently, the only reason the streams flip at .4s intervals is because of the core.wait(0.4). The conditional after if stream.status == STARTED seems to have no effect on the times that the streams change. Why is this?

If needed, I can provide more context in both the code and what I am trying to achieve. I’m just not sure what all else is needed. Thanks in advance!

I’ve just made a rudimentary example in the builder to see how psychopy’s code compares to mine, and discovered that psychopy is also displaying these stimuli out of sync, despite them being updated at 0.4s intervals. Is this a problem with my monitor’s refresh?

  1. On some of these flips, the letters are not in sync when they change. How is this even possible, since they all should be drawn and redrawn on the same flip?

Not having access to the full code, my guess is simply that upon occasion you are displaying the same letter twice in succession at the same location. This would make it look like there has been a pause or stutter in one location, when in fact the drawing is happening as scheduled, but just results in no visible change.

I’ve done this myself before. If this is the case here, you would need to introduce a constraint in your randomisation to not allow consecutive letters at the same location, or introduce a blank period between letters.

We don’t know how your stream object works. But you could be printing the text on each change and then verify afterwards if it matches what you think it should be.

Your code seems to have a mix of frame-specific timing, but then also a brute force pause for 0.4 s via core.wait(). If you want precise timing, then you should attempt to draw in every screen refresh, rather than pause your code in a way that breaks any synchronisation with the screen update cycle.

“PsychoPy” is only doing what it’s told - the issue will lie in the specific code used to select characters to display on screen, which is under your control. We can’t debug that given only the partial code shown here (e.g. we don’t know what streams is, or what the distinctions are meant to be between trial.stream, stream, and streams).

No. The entire screen is updated at the same time.

Not having access to the full code, my guess is simply that upon occasion you are displaying the same letter twice in succession at the same location.

This was the problem. I implemented the constraint as suggested and it worked. Thanks for that :slight_smile:

If you want precise timing, then you should attempt to draw in every screen refresh, rather than pause your code in a way that breaks any synchronisation with the screen update cycle.

I understand this. What I’m saying though is that the conditional where I “properly” (as in use precise timing) handle when the stimuli should change (e.g. if stream.status == STARTED: if tThisFlipGlobal > stream.tStartRefresh + 0.4 - frame_tolerance:) seems to not affect when it actually refreshes. I’m using core.wait(0.4) as a proxy for the proper behavior so I can debug other aspects of the code. Currently, without the core.wait(0.4), the letters are simply not shown at all and it jumps immediately to the next prompt screen.

Here’s all the code responsible for the timing and refreshing of each stimulus: Catyre's Code - Pastebin.com

As well as an explanation for the not-so-obvious variables:

"""
Some variables explained
------------------------
    streams : List[visual.TextStim]
        The list of stimuli to be displayed in this trial.  len(streams) is 6, but only some of the streams get updated
            depending on the level.

    trial.stream : list
        List of letters, {stream_length} long, where each letter is actually a list containing
            the chosen letter and a flag denoting the letter's proximity to a "T"
        (e.x. [[['T', 'N'], 1], [['H', 'X'], 1], [['I', 'S'], 1], [['F', 'V'], -1], [['V', 'S'], -1]])

    stream : visual.TextStim
        The stream to be displayed in this trial.

    trial.rsvp_stream_count : int
        A count of how many letters there are per streambit (group of letters) in this trial
        
"""

The issue will lie in the specific code used to select characters to display on screen, which is under your control.

I had unwittingly put repeat characters into the stream for it to read, not thinking that that would cause my problem :sweat_smile: