Can't break out of loops using a variable in Pavlovia

URL of experiment: [1 Hour Pilot Link] LINK HERE

Remembering Words and Symbols - Online.psyexp (528.1 KB)

Description of the problem:

I have a divided attention study that has a between-subjects factor of group. In an early code component, I set variable x to be a random integer, 1 or 2. Then, I use 1 or 2 to assign participants to either be in the Symbols group or the Word group. However, I’m having trouble making my experiment only show one set of instructions (by skipping the irrelevant instructions for the non-assigned group). To do so, I’ve set loops around the single-routine instruction screens (loops called ‘SkipToWords1’ and ‘SkipToSymbols1’, see screenshot below). In my in-lab version of the experiment, I had IF statements saying that, for example, IF group is Symbols, then set WordSkipper to 0 and then WordSkipper was the name of the loop around the word instructions, which would then skip that loop because I would set nReps to $WordSkipper. However, when going online and using Pavlovia, I got an error: TypeError: Cannot read property ‘0’ of undefined. So, my alternative solution was to set nReps to 1 and instead use a code component to break out of the loop. The idea being, if group is set to Symbols, then I have a code that breaks out of the Words group instructions screen/loop as soon as it starts, and vice versa.

I’ve now been on forums and have read everything I can get my hands on in terms of breaking out of a loop in Pavlovia using PsychoPy builder and JS code components, including but not limited to using ‘trials.finished’, ‘LOOPNAME.finished’ and ‘currentLoop.finished’, and every variation I can think of. All of this of course has been with Auto → JS turned on, except when needing to specify ‘trials.finished’ on the JS side. This leads me to believe that my IF statement isn’t finding the x variable I set at the start of the study. I’ve been at this for 2 days straight with no progress, so I’m hoping someone can help me out please!

Here are some contextual screenshots and things I’ve tried already:

Experiment flow at the beginning:


Part of my ‘RandomizerScript’ that randomizes people into group by variable x:

An example of code I tried by using a Code Component in the WelcomeSymbols routine, ‘Begin Routine’ tab:

if x == 2: trials.finished = True SkipToWords.finished = True

An example of code from the same routine, but in the ‘Each Frame’ tab:

if x == 2: continueRoutine = False

Thanks everyone in advance! This forum has already been super useful.

Where did you read that? However, you should not include the $ in the nReps variable.

Sorry! I actually misspoke in the original post (edited out now). What I meant to say was, when trying to use variable names in nReps (with and without using $, as I saw on your crib sheet), I got the error TypeError: Cannot read property '0' of undefined. After looking at the error using developer console, it looked like it couldn’t find the value for my nReps variable. Assuming that was the case, I set nReps to 1 and it worked again. However, I then needed a different solution for exiting the loop, which is when I then turned to the code component method outlined in my original post.

When are you setting WordSkipper/ SymbolSkipper?

It needs to be Begin Experiment in a routine that comes before the loops (codeJs or RandomizerScript). If you can’t set it in Begin Experiment you need to set it anyway and then change it.

Those skipper variables were set in RandomizerScript, in the Begin Experiment tab. Here is an example of the setup I had before in a functional locally-run (i.e., Python) version of the experiment:

# randomize variable X so that participants go into Words or Symbols group
x = []
x = random.randint(1,2)

# setup default skipper values
SkipToWords_Skipper = 1
SkipToSymbols_Skipper = 1

# if words are assigned, make skipper equal zero in order to skip to words
if x == 1:
    SkipToSymbols_Skipper = 0

# if symbols are assigned, make skipper equal zero in order to skip to symbols
if x == 2:
    SkipToWords_Skipper = 0

# assign string for Group variable that will be recorded in data file
Group = []
if x == 1:
    Group = "Symbols"
if x == 2:
    Group = "Words"

Then, the SkipToSymbols_Skipper and SkipToWords_Skipper variables were used in the nReps dialog box (with a preceding in the locally-run version, but including/excluding the doesn’t make it work in the Pavlovia version so I figured it was just a function that doesn’t work online).

I know that it can be a variable, so the most likely explanation is a typo. Please could you screenshot your loop definitions and your code component?

Somewhat annoyingly, new users can only post 2 images… So below are two images and the rest is pasted in code.

Here is a screenshot of the overall flow at the beginning of the study:

Here is my getRandomInt function script in JS that is later used to determine variable X:

thisExp=psychoJS.experiment;

win=psychoJS.window;

event=psychoJS.eventManager;

Array.prototype.append = [].push;

shuffle = util.shuffle;


getRandomInt = function(min, maxplusone) {
  return Math.floor(Math.random() * (maxplusone - min) ) + min;
}

function range(start, stop, step) {
    if (typeof stop == 'undefined') {
        // one param defined
        stop = start;
        start = 0;
    }

    if (typeof step == 'undefined') {
        step = 1;
    }

    if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
        return [];
    }

    var result = [];
    for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
        result.push(i);
    }

    return result;
};

Here is my RandomizerScript that randomizes variable X as 1 or 2, then simple IF statements that should make the skipper value equal 0 depending on the group that was assigned (i.e., x = 1 or 2):

Python Version

import random

# randomize variable X so that participants go into Words or Symbols group
x = random.randint(1,2)

# setup blank counter lists and skippers
SkipToWords_Skipper = 1
SkipToSymbols_Skipper = 1
SkipIfFinalBreak_Counter1 = 0
SkipIfFinalBreak_Skipper1 = 1

# if words are assigned, make skipper equal zero in order to skip to words
if x == 1:
    SkipToSymbols_Skipper = 0

# if symbols are assigned, make skipper equal zero in order to skip to symbols
if x == 2:
    SkipToWords_Skipper = 0

# if symbols are assigned, make skipper equal zero to skip words
Group = []
if x == 1:
    Group = "Symbols"
if x == 2:
    Group = "Words"

JS Version

var Group, PID, SkipIfFinalBreak_Counter1, SkipIfFinalBreak_Skipper1, SkipToSymbols_Skipper, SkipToWords_Skipper, SymbolMatch, SymbolMatchSkip2, block_order_baseline, block_order_practise, block_order_symbols, block_order_words, num_items, num_study, num_test, x, y, z;
x = getRandomInt(1, 3);
SkipToWords_Skipper = 1;
SkipToSymbols_Skipper = 1;
SkipIfFinalBreak_Counter1 = 0;
SkipIfFinalBreak_Skipper1 = 1;
if ((x === 1)) {
    SkipToSymbols_Skipper = 0;
}
if ((x === 2)) {
    SkipToWords_Skipper = 0;
}
Group = [];
if ((x === 1)) {
    Group = "Symbols";
}
if ((x === 2)) {
    Group = "Words";
}

Here is the error I get when running this code (apparently the ‘for’ loop on line 3581 is the error):

I’ve attached the experiment (making use of the loop nReps method) here in case it helps:
Remembering Words and Symbols - Online.psyexp (530.2 KB)

This might be the problem. I think you should define variables by saying things like PID=0 or PID= depending on whether its a variable or an array. Defining using var might limit the scope of the variable to that code component.

That was it! Thank you so much. For anyone reading in the future, what I did was removed the x and skipper variables mentioned above from the ‘var’ list on the JS side of the code. Then, I set them all to = 0 at the start of the code. See here:

var Group, PID, SkipIfFinalBreak_Counter1, SkipIfFinalBreak_Skipper1, SymbolMatch, SymbolMatchSkip2, block_order_baseline, block_order_practise, block_order_symbols, block_order_words, num_items, num_study, num_test, y, z;
SkipToWords_Skipper = 0
SkipToSymbols_Skipper = 0
x = 0

@wakecarter while I have you here, I have the same error now but on a later loop variable. For this one, I have two practice blocks that I want the order of randomized. To do so, I have the following setup in the flow:


Here is the nReps text in case you can’t zoom in enough:

First loop:

block_order_practise[0][trials.thisN] 

Second loop:

block_order_practise[1][trials.thisN]

Then, I have Begin Experiment code in my RandomizerScript for two block order arrays in a larger array that are then shuffled and used in the nReps for the loop such that the order of the block is randomized:

Python Version


# specify which of the inner loops will run on each iteration of the outer loop:
block_order_practise = [[1, 0], [0, 1]]

# randomise the order of blocks for this session:
shuffle(block_order_practise)

JS Version

block_order_practise = [[1, 0], [0, 1]];
shuffle(block_order_practise);

I reckon that trials.thisN might not work within the specification of a loop. I’d recommend that you use your own dummy variable for that.

Correct again! Thanks a lot. So I swapped back from trials.thisN to DA_Practise_Loops.thisN which got rid of the error “‘trials’ is not defined”. Then, I set block_order_practise as an empty array (i.e., = ) as I did for the x variable in the original solution above to solve another “TypeError: Cannot read property ‘0’ of undefined” that cropped up.

However, I’m now getting the same “TypeError: Cannot read property ‘0’ of undefined” as before, when running the following nReps setup:


3

Here is where it occurs (line 3686):

So, the program is having the same error but now with the actual overall loop name. This issue persists even when I define the overall loop name early on in the RandomizerScript (i.e., DA_Vis_Practise_Overall_Loop = ). Unless I’m missing something, it seems that a new solution is required for this particular issue now.

Just to provide some context: What should happen (and what does indeed work offline using PsychoPy), is that the list variable block_order_practise = [[1, 0], [0, 1]] is shuffled, and then using this nReps setup, block_order_practise[0][DA_Practise_Loops.thisN], the program selects the first array withing the overall array, and then sets nReps as the value that is in the first or second position of the selected list based on the current repetition of the loop. What this effectively does is randomizes block order.

You can’t use .thisN so you’ll need to have your own variable which you add 1 to each iteration

Right again! That’s three for three now. I’ve implemented what you said using a new code component within a new routine, within each loop, called “Code_add_one_Practise”. See below for the simple increment code I used:


So right now, I have the experiment working so far such that it properly randomizes between Symbols and Words, and then properly randomizes the order of the practise blocks. However, after finishing the second loop of practise blocks, I get the classic error we’ve been running into this entire thread: “TypeError: Cannot read property ‘0’ of undefined”. This is due to line 3726 in the screenshot below.

Any thoughts on this iteration of the error? The outer loop is set to 2 reptitions, so it should simply just end and then move on to the next instructions screen that comes after the practise blocks.

Please show me the definition of that loop and also the Excel/CSV file if it has one. It might be that there’s an issue with the names of the variables, or possibly the position of the cursor in the Excel.

I’m not sure what you meant by the definition of the loop, so I’ve included a lot of information here in the hopes that some of it is what you’re looking for.

Here is the left half of the overall practise phase loop:


Here is the right half of the loop (note it should end and then go to the next instruction screen called “Welcome_Tone_Practise”):

Here is the DA_Vis_Practise_Loop dialog box:
vis prac
And its outer loop that defines the block:
vis prac overall
Similarly, here is the DA_Phon_Practise_Loop dialog box:
phon prac
And its superordinate block-defining loop:
phon prac overall
Both of the actual loops with repeating trails reference “practiseStim.csv”, shown here:
CSV file

I should note that the loops work perfectly fine. That is, they play the mp3 files correctly, go through the correct number of times, and randomize block order. The only problem right now is that after the second loop through the practice blocks, it should go on to “Welcome_Tone_Practise” but instead I get the fateful "TypeError: Cannot read property ‘0’ of undefined” error. And, when opening the developer console, it highlights the error having something to do with the loop called “DA_Vis_Pracise_Overall_Loop”.

I did some troubleshooting and noticed that when reducing the nReps of “DA_Practise_Loops” (the large, overarching, 2 sequential iteration loop that defines the practice phase) from 2 down to 1, the experiment works correctly and proceeds on to “Welcome_Tone_Practise” after one iteration.

Troubleshooting also revealed an effect of practise block order. When “DA_Vis_Practise_Overall_Loop” goes first, and DA_Phon loop goes second, then the error seen in the console is for “DA_Vis_Practise_Overall_Loop”. That is, whichever block happens to be presented first is what the console highlights as an issue after completing the second block.

So the above point in bold, combined with the troubleshooting in the paragraph above it, indicate to me that there is something wrong with updating some value connected to whatever first loop is presented, but only when it goes through twice. When going through only one practise block (i.e., setting nReps of “DA_Practise_Loops” to 1), there is no error.

Fixed by making a custom variable counter to mimic the “.thisN” function, with a code component that adds 1 iteration to a variable (that starts defined as 0) for every loop.

1 Like