psychopy.org | Reference | Downloads | Github

Multiple conditions needed for running a loop

Experiment flow for reference:

The Popup_Loop is a conditional loop (it only runs if a variable equals 1 on a trial) and everything about it works fine. On the “Email” routine, I have a keyboard response after an image is shown, and then a code component that evaluates if the Popup_Loop should run. This is what that code looks like currently:

I need to add to that code additional conditions for running the Popup_Loop. What I need to happen is that on trials where Popup_Presence=1, if participants hit a key to respond to the picture, or if 2 seconds passes with no response, the Popup_Loop needs to be skipped.
On trials where Popup_Presence=0, participants need to be able to hit a key at any time to end the routine.

Basically what I’m trying to achieve is the following:

  1. If Popup_Presence=1 and a key is hit within 2 seconds, don’t run Popup_Loop
  2. If Popup_Presence=1 and 2 seconds passes with no response, run Popup_Loop immediately
  3. If Popup_Presence=0, skip Popup_Loop and allow response at any time (response will then end the routine)

I don’t know the proper Python “terms” to make this code component
Any help is greatly appreciated!

Update:
I have been working on this, and so far no luck still. This is the most recent thing I’ve tried:

I have a feeling I’m using the wrong thing for my keyboard variable. My keyboard response is called ‘Email_Response’. I also don’t know if “None” is the proper term for no response.

I also don’t know if I’m doing the time check correctly.

With this level of complexity I’d advise starting with pseudo-code! I think you have ifs and elifs contradicting one another; if ‘Popup_presence’ is 1, then the elif won’t run, so having Popup_presence == 1 as a condition for the elif means it’ll never run.

With regard to checking whether there has been a response, a cool aspect of Python is that if you supply a non-boolean argument to an if loop, it will convert to boolean based on whether or not it is empty. So if Email_response.keys is essentially the same as if Email_response.keys == [] or if len(Email_response.keys) == 0. If there’s not been a response, then Email_response.keys will be empty.

Based on what you wrote, you’d want something like this in Each Frame:

if Popup_Presence==1 and t >= 2 and not Email_response.keys: # If Popup_Presence is 1 and 2 seconds pass with no response...
    # Run Popup_Loop immediately
elif Popup_Presence==1 and Email_response.keys: # If Popup_Presence is 1 and a key is hit within 2 seconds...
    # Don't run Popup_Loop
elif Popup_Presence==0 # If Popup_Presence is 0...
    # Skip Popup_Loop...
    if Email_response.keys # ...and allow response at any time, a response will then...
        # End the routine

So filling in the loops with actions now, you seem to already have most of what you need. Like in your example, you could do:

if Popup_Presence==1 and t >= 2 and not Email_response.keys: # If Popup_Presence is 1 and 2 seconds pass with no response...
    nRepsPopupLoop = 1 # Run Popup_Loop... 
    continueRoutine = False # ...immediately
elif Popup_Presence==1 and Email_response.keys: # If Popup_Presence is 1 and a key is hit within 2 seconds...
    nRepsPopupLoop = 0 # Don't run Popup_Loop
elif Popup_Presence==0 # If Popup_Presence is 0...
    nRepsPopupLoop = 0 # Skip Popup_Loop...
    if Email_response.keys # ...and allow response at any time, a response will then...
        continueRoutine = False # End the routine

Is this pretty much what you want it to do? Jon pointed out something else helpful this morning - anything which involves crashing out of a loop may not work directly in JavaScript just due to differences in the languages. Rather than having it set to Auto-JS you may be better off coding in both and then making alterations to the JS script. I’m mostly involved with the Python side of things but I think @apitiot has added a JS function which can end a loop safely.

Thank you so much!! With 0 coding experience, I was thinking I was somewhere on the right track, but had no idea how to get to where I needed to go. I think what you detailed is exactly what I need to happen. I assume this needs to be in the ‘each frame’ section since it deals with time, is that correct?

I will test this online and see if it needs to be written in JS as well, thank you for the suggestion! If it needs to be coded in both, do I use the ‘Both’ code type and write one below the other in the same code space?

Great, glad I could help! Yes, it needs to go in Each Frame - as it will then be continuously checking for a response rather than checking once at the end of the routine. And yep, Both is the option you want - that way you can have different JS and Python code in each side, one won’t override the other.

Perfect, thank you so much!!