Loop.finished=true No longer working

URL of experiment: https://pavlovia.org/bobbyTUCI/sandwich2020

Description of the problem:
My experiment involves two places where I break a loop using a conditional such as
Iter.finished=True, or Iter.finished=true (for JS).
This was working perfectly fine both on my computer and on Pavlovia until the most recent update to PsychoPy. Now whenever I get to the spots in the study that use this code, even if the specified condition is true (in my case whether they pressed a certain key), the study just stays on that page and they are not progressed to the next part of the study.
Just wondering if this was intentional, and if so how I can rewrite the code to still break my loops when the conditions are met.

I solved this problem for my current study by reverting back to version 3.2, but this seems like something that should be looked into and flagged for the newest PsychoPy update.

@Bobby_Thomas, there a slight change to how you end loops in the latest version of PsychoPy/JS. To end a loop, use the following. In this example, we end the loop on the 2nd repetition of that current loop:

if (currentLoop.thisRepN == 2) 
  {
    trials.finished = true;  // to end any loop, use 'trials'
  }
4 Likes

Hi @dvbridges also @jon This problem has been creeping up all over the forums recently so I wanted to confirm it on my experiment. I tried implementing the solution you gave here, and it no longer works. Instead, using PsychoPy v2020 I can only get the termination of a loop when I now use the loop name.finished instead of trials.finished.
Has anything changed since this solution was posted that would have caused this? Because I can confirm Iter.finished=True (Iter is the loop) was not working when I originally tried running this experiment (late Feb/early March) with PsychoPy 2020

The updated code using Iter.finished=True and more recent versions is linked below:
Pavlovia site: https://pavlovia.org/bobbyTUCI/sandwich2020
Github site: https://gitlab.pavlovia.org/bobbyTUCI/sandwich2020/tree/master

I think we need @apitiot here now

Hi,

Are you saying above that you managed to get it working using the loopname.finished command in 2020.1?

I’ve tried it both ways in 2020.1 and not had any luck - I see that Jon has tagged in aptiot to look into it - should I just sit back and wait and see what he says?

Best wishes,
Tom

Good morning @TomH and @Bobby_Thomas,

I will be looking into it in a couple of hours. I’ll let you know as soon as the situation has been clarified.

Alain

Excellent news!

Here’s a minimal version of my study which should end in 20 correct trials (twenty clicks within the polygon) if this helps you test it (works in psychopy, not in pavlovia).

cheers,
Tom

Hello again @TomH,

I have had a look at the matter. The main issue with your code is in trialRoutineBegin:

a. You want to test whether obs_dict is empty. You cannot do that using a comparison with {} in JavaScript. You would have to do:

if ((Object.keys(obs_dict).length === 0))

As a consequence, your dictionary is never initialised and so obs_dict[image] is always NaN and so it will never be equal to 2 and so you will never call trials.finished = true

When I artificially set trials.finished = true I can confirm that the routine ends.
You can give it a try by adding the following code in trialRoutineBegin:

if (object === 'p2.bmp') { trials.finished = true; skipThisTrial = true; continueRoutine = false; }

b. You want to build you dictionary using trials.trialList but trialList is not exposed in PsychoJS and, consequently, is undefined.
You could instead use the getTrial method of the TrialHandler: you can pass it an integer that is the index in the trialList:

getTrial(index = 0) { if (index < 0 || index > this.nTotal) return undefined; return this.trialList[index]; }

Does that make sense?

@Bobby_Thomas: I will have a look at your experiment now.

Cheers,

Alain

1 Like

@Bobby_Thomas: I am not sure I understand what you are saying.

The 3.2 approach is rather different from the 2020 approach. Are you saying that you used the same code you generated with 3.2 but changed the import to data-2020.1.js? That would indeed create some problems…

Thank you very much Alain for looking into it - that sounds excellent but i’m a little confused by it.

Could I please bother you for a small step-by-step list to get my study running as i’m a bit overwhelmed?

Very much appreciated,
Tom

@apitiot First off my study is already completed and finished (without issue) so if the problem ends up being unique to my study we can ignore it.
To get my experiment to work a few weeks ago, I simply used PsychoPy version 3.2 and ended my loop (Iter is the loop name) with this code in the End Routine panel:

if (Decision.keys[0]=='a' or Decision.keys[0] == 'l'):
    Iter.finished=True

and had translated it to JS code without issue.

But after the experiment was finished I wanted to update the code to work with the most recent version of PsychoPy (so it can be an updated template for any future studies)
After changing the version to ‘latest’ in experimental settings I tried changing the code segment above to:

if (Decision.keys[0]=='a' or Decision.keys[0] == 'l'):
    trials.finished=True

or

trials.finished=true

for JS.

But after resyncing with Pavlovia again (with this new code, and the version set to ‘latest’, the loop would not actually terminate given this condition.
I then left the PsychoPy version the same (looking at the code it is 2020.1.1), and then changed the code above back to the original:

if (Decision.keys[0]=='a' or Decision.keys[0] == 'l'):
    Iter.finished=True

And this worked when piloting on Pavlovia.
The problem is that when I originally posted this problem, on February 25th, this combination of PsychoPy v2020 and using Iter.finished=True is what was originally causing problems and the proposed solution was to use an older PsychoPy version or to use

trials.finished=True

but when I tried it for this second post (March 27th), it appears that the combination of Iter.finished=True and PsychoPy v 2020 now works, while trials.finished=True does not work.
I was looking into this again recently because other people on the forums have been having similar issues, and I have been pushing trials.finished=True as being the solution, but it no longer seems to actually be a viable solution.

@apitiot I appreciate your help but i’ve been trying for two days to make sense of it and haven’t been able to - I don’t have the java skills to implement what you have said.

Best wishes,
Tom

Hello @TomH,

I am afraid I am fully occupied today. I will get back to you before the end of the week.
Cheers,

Alain

thank you very much I appreciate it.

Best wishes,
Tom

Hello Alain,

Hope all is well. Is now a better time to have a look at my project?

Best Wishes,
Tom

Hello @TomH,

With my apologies for the delay (busy days!), these are the edits I would suggest (marked with // AP):

  • in trialRoutineBegin:
if ((Object.keys(obs_dict).length === 0)) { // AP
    // if ((obs_dict === {})) {
        for (let _pj_c = 0; _pj_c < trials.nStim; ++_pj_c) { // AP
        // for (var image, _pj_c = 0, _pj_a = trials.trialList, _pj_b = _pj_a.length; (_pj_c < _pj_b); _pj_c += 1) {
        //     image = _pj_a[_pj_c];
          const trial = trials.getTrial(_pj_c); // AP
          const image = trial["object"]; // AP
          obs_dict[image] = 1;
        }
    }
if ((obs_dict[image] === 2)) {
        if (! _pj.in_es6(0, Object.values(obs_dict)) && (! _pj.in_es6(1, Object.values(obs_dict)))) { // AP
        // if (((! _pj.in_es6(0, obs_dict.values())) && (! _pj.in_es6(1, obs_dict.values())))) {
            trials.finished = true;
            skipThisTrial = true;
            continueRoutine = false;
        }
    } else {
        skipThisTrial = false;
    }

With those modifications, your code runs on my end. I cannot vouch for its operational correctness, but it does run.
Have a go and let me know how you get on!

Cheers,

Alain

1 Like

Hi Alain,

Thanks for taking the time.

The loop is not behaving as it is supposed to online and is behaving very strangely.

To remind you of the way the loop is supposed to work:
(1) object is correct if within 150 pixels (i.e., inside the polygon i’ve included for easy testing)
(2) if an object is answered correctly twice in a row , (i.e., on two consecutive occasions that item, e.g., cow is attempted) it drops from the loop (i.e., its value goes from 0>1>2; if it is answered incorrectly, its value in the dict drops to 0 - the values for the other objects should stay the same here and they should still be skipped if their value reaches 2)
(3) loop terminates when all objects placed in correct location twice in a row (i.e., all objects values are 2 in dict).

EDIT: The java script is behaving in the following undesirable way:
(1) if an object is answered incorrectly it seems to reset to 0 as desired
(2) it will then finish all the objects in the that round of the loop
(3) it will then demand two new full loops in which I answer the original incorrect trial correctly (i.e., it is not skipping)
(4) then it will start a final round of the loop and terminate only once it reaches the object I originally answered incorrectly

note* currently I have all values of objects in dict set to 1 for quicker testing.
note* works fine in psychopy builder

do you know whats going wrong?

Cheers,
Tom

Hi Tom, I had a similar problem and posted my solution here: Cannot exit loop in online Pavlovia (Using JS code component)
Hope it helps!

Thanks Amy - it was useful to have a play around with the effect of putting certain code components in different windows (end routine,each frame etc) but it didn’t fix my problem, nor did the other growing list of threads on conditional loops in the forum. Not sure where to go next.

Cheers,
Tom