Dynamically reference the current loop

Hello!

I am developing an experiment into Builder and using some Code components to handle calculations, feedback, loops, etc. It has a complex workflow and I would like to make my routines as reusable as possible. I am also using a datasheet with thousands of stimuli and picking just a random subset of them.

That said, I would like to retrieve the current loop to stop it after i.e. 30 repeats. For each single loop I have achieved that with this code:

namu_t_counter += 1
if namu_t_counter >= 30:
    namu_loop.finished = True

However, I would have to duplicate the routine where this code is located at least 9 times (making it 10 almost identical routines) if I just copy them and adapt. So I would like to make a code to dynamically retrieve the current trial loop and handle it individually with the same code, so I can just insert the same routine several times in the Flow.

I’d appreciate any ideas on how to do that code (in both Python and JS) or what to look for, like hints on internal variables accessible through code, docs describing it (I have goodled, but found nothing so far with my keywords), etc.

Some information from the topic template that I think might help:
OS: Win10
PsychoPy version: 2020.2.10

Thanks for the prompt to look into a solution for this, as I was just pondering the same thing in response to someone else’s problem in another thread.

Builder creates a variable called currentLoop, which is an alias to whatever the immediately enclosing loop is for a given routine. So to make your routine re-usable (:white_check_mark: an excellent thing to strive for), simply use:

currentLoop.finished = True

This doesn’t help if you want to refer to a loop that encloses the innermost loop. e.g. With a blocks loop that surrounds an inner trials loop, currentLoop allows you to refer to the trials loop, but there doesn’t currently seem to be a shorthand to refer to the blocks loop that surrounds it – it needs to be referred to with its own name, unless you provide an alias for it yourself.

Also note that you don’t need to maintain your own trial counter: PsychoPy loops maintain their own counter, so you could simply do this:

if currentLoop.thisN == 29: # NB counts from zero.
    currentLoop.finished = True

Under the hood, a loop is called a TrialHandler object, and you can see in this documentation page the variety of counter attributes that a TrialHandler maintains (e.g. .nTotal, .nRemaining, etc):

Lastly, note that there is an alternative way to achieve what you are after anyway. Rather than setting the loop to be random and then exiting it after 30 iterations, an alternative is to randomly select 30 rows from the file in the first place, via the “Selected rows” field of the loop dialog. That way, you don’t need any custom code to end the loop – it will be set to have 30 iterations from the beginning. Put something like this in the “Selected rows” field of your loop:

$np.random.choice(1000, size = 30, replace = False)

Instead of 1000, specify whatever the actual number of rows in your conditions file is.

Unfortunately, I think .thisN is still broken for online use and the original poster asked for a solution that would work for both. currentLoop should work but random subsets of rows are trickier.

Thanks, I missed the reference to PsychoJS as well as Python.

So I guess the OP’s original approach would be best but using currentLoop? I’m not that familiar with PsychoJS – I recall something about all loops being referred to as trials – is that still a thing?

No – that’s been fixed.

1 Like

Hi Michael,

I used this method on a task I’m working on, the task runs fine standalone on my local computer but I get errors when trying to upload to Pavlovia. I get this warning:
image
Do you think that this might be causing my issues when I try to upload to Pavlovia, or is this ok?
Thanks
Rob

That will fail for two reasons:

  1. You can’t use numpy online
  2. You can’t put detailed code into anything other than a code component. You need to set a variable in a code component (I often use shuffle and then pick list item 0 for a random choice) and then use the variable in the Selected Rows field. For selected rows it needs to be of the form “0:10” = first 10 rows.
1 Like

Thanks Wakefield. I haven’t had chance to learn Python yet, and was hoping that this task could be built just by using the builder. Do you know where I can find an example of something like this I can look at?

What do you want to happen? If you want the loop to stop after 20 trials then remove everything from Selected Rows and then put the following in the End Routine tab of an auto translated code component in the final routine in your loop.

nLoops+=1
if nLoops==20:
     currentLoop.finished=True

You will also need to put nLoops=0 in the Begin Experiment tab.

1 Like

That’s excellent, thank you. :slightly_smiling_face: Much appreciated.

Earlier on in thread I saw that you’d said that “thisn” doesn’t work for online, I didn’t realise that numpy was also not for online studies. I’m hoping to attend some Psychopy training this year and also learn Python too.

Thanks again!

Have a look at my crib sheet (see pinned post in online) for more information about what works and doesn’t in Pavlovia.

1 Like

Thanks! :slight_smile: I’ve kind of been thrown in at the deep end a bit with this.