Python to Javascript translation to end experiment early

URL of experiment: https://run.pavlovia.org/LisaMarieke/slotmachinetest/

Description of the problem:
Hi,

I have a problem when running my study online - I think my general problem is that I have a few custom code components in my experiment which I tried to translate from python to javascript, unsuccessfully however.

The first code components terminates the experiment when participants do not perform well enough on a quiz. If they score below 80%, then the entire experiment is terminated and they only see the last thank you slide. If they do well enough then they can continue with the experiment.

In the ‘begin experiment’ box I have this python code:

respcorrs = []
minNrPractice = 10  # min number of trials to practice
considerNrTrials = 10  # number of trials to consider for accuracy calculation
minAccuracy = 0.8

and translated that to this javascript code:


respcorrs = [];
minNrPractice = 10;  // min number of trials to practice
considerNrTrials = 10;  // number of trials to consider for accuracy calculation
minAccuracy = 0.8;

In the ‘End Routine’ box I have this python code:

respcorrs.append(QuizzResp.corr) 
if len(respcorrs) >= minNrPractice:

    respcorrsRecent = respcorrs[-considerNrTrials:]
    
    respcorrsSum = sum(respcorrsRecent)  
    accuracy = float(respcorrsSum)/considerNrTrials
    
    if accuracy < minAccuracy:
        print('not good enough')
        RunStop = RunRoutine_3
    else:
        RunStop = RunRoutine_2

which works fine and does what its supposed to do. The variable RunStop is used by the second loop, which may not get executed and ‘RunRoutine’ are column names in an excel table that is used by the outermost loop.

I tried to translate that to Javascript, however it doesn’t work. When I try it out, then the experiment just goes on.

respcorrs.push(QuizzResp.corr);  // assumes your keyboard component is called "resp"

if (respcorrs.length >= minNrPractice){
    accuracy = respcorrs/considerNrTrials;

    if (accuracy < minAccuracy) {
        RunStop = RunRoutine_3;
}    else {
        RunStop = RunRoutine_2;
        }
    }

I have also tried it very similar to the python code, but I have received an for the reduce command as well as parse command.


if (respcorrs.length >= minNrPractice){
    respcorrsRecent = respcorrs[-considerNrTrials];
    respcorrsSum = respcorrsRecent.reduce(respcorrsRecent);  
    accuracy = parse.Float(respcorrsSum)/considerNrTrials;

    if (accuracy < minAccuracy) {
        RunStop = RunRoutine_3;
}    else {
        RunStop = RunRoutine_2;
        }
    }

I have tried my best to come up with the right way to write this in javascript but I just do not seem to get it.

Thank you very, very much already for your help.

Hi I am experiencing this same problem - can anyone help?

Here is my JS code in the Begin Experiment tab:

respcorrs = [];
minNrPractice = 30;
considerNrTrials = 30;
minAccuracy = 0.8;

And in my End Routine Tab:

respcorrs.append(resp.corr);
if ((respcorrs.length >= minNrPractice)) {
    respcorrsRecent = respcorrs.slice((- considerNrTrials));
    respcorrsSum = [respcorrsRecent].reduce( function(x,y) { return x+y; }
);
    accuracy = (Number.parseFloat(respcorrsSum) / considerNrTrials);
    if ((accuracy > minAccuracy)) {
        trials.finished = true;
        continueRoutine = false;
    }
}

The code works perfectly in Psychopy, but the routine does not end when accuracy is reached in Pavlovia. I have also tried moving the elements of code to different tabs, similar to what has been outlined above, but that hasn’t worked either. Any help would be greatly appreciated.

Many thanks,
Ellen

I assume you have a code_JS component to deal with .append.

Try displaying accuracy in a text component or using print/console.log to check whether it is indeed reaching minAccuracy.

Yes I have a JS component at the beginning of my experiment.

In Psychopy if I put a text component with

msg='';

in the begin experiment
and

if accuracy>minaccuracy:
    msg="Accuracy reached!" ;
else:
    msg="Nearly there";

In the each frame tab, it just says accuracy not defined (even though it is in the other code component?).
I’m not sure about the print/console.log method. Do I put that into a code component on builder view?
This is my experiment url:
https://pavlovia.org/run/ellen_howard/1_st_fc_ss/html/

Thanks for your help!

Put accuracy = 0 in Begin Experiment to give it an initial value

No message is displaying when I run it

As per my crib sheet, I avoid having components set to update every frame.

Instead I would set the text component to blank and constant than then have textComponent.text=“Accuracy reached!”;

Additional code is needed to stop it resetting the text every frame, e.g. (in Python)

if accuracy>minAccuracy and accuracyReached=0:
     textComponent.text='Accuracy reached!'
     accuracyReached = 1

However, thinking about it, your situation may be simpler.

Are you trying to set msg every frame of a feedback routine that comes after the trial routine? If so, then you are setting it too late. Set in in End Routine of the trial routine.

I’ve put that code into the end of routine tab, but no message is displaying, and now the accuracy code isn’t working in Psychopy (it was previously just not on Pavlovia).
I guess I do just need a message at the end of routine to see whether Pavlovia is detecting when accuracy is reached? If that’s what you were asking
My lack of coding experience is showing so apologies if I’m missing simple things here

Please could you screenshot your code components. I’m not sure what you have now.

When you say “not working” do you mean nothing is displaying but there is also no error?

No message is displaying and the routine doesn’t end when accuracy threshold is reached (which it was doing before). I tried what I’ve got here in the same and in separate code components in the same routine.

Is your keyboard component called resp?
Is your text component called textComponent?
I’m not sure that slice works as intended in JS but you can come back to that once the Python is working again.

Try adding

else:
     text.Component.text='Accuracy only '+str(accuracy)

to give you an idea of what’s happening.

You could also reduce minNrPractice to 3 so you see it working faster.

I’ve tried as you suggested, I’m not getting a message appear and the routine isn’t ending after 3 correct answers (after changing the minNrPractice to 3) like I would expect

respcorrs.append(resp.corr);

if len(respcorrs) >= minNrPractice:

    respcorrsRecent = respcorrs[-considerNrTrials:]
    
    respcorrsSum = sum(respcorrsRecent)  # only works if error=0 and correct=1
    
    accuracy = float(respcorrsSum)/considerNrTrials
    
    if accuracy > minAccuracy:
        continueRoutine = False
        trials.finished = True
if accuracy > minAccuracy:
     text.Component.text='Accuracy only '+str(accuracy)
     accuracyReached = 1 

If it needs to be ‘else’, where do I put that?

Here is the Python code I’m suggesting.

respcorrs.append(resp.corr)
#.append will only work if you have Array.prototype.append = [].push; in code_JS

if len(respcorrs) >= minNrPractice:

    respcorrsRecent = respcorrs[-considerNrTrials:]
    #I'm not sure if this slice technique will work but it should work offline. You could try respcorrs.slice(-considerNrTrials) instead

    respcorrsSum = sum(respcorrsRecent)  # only works if error=0 and correct=1
    #This will only work if you have sum = (arr) => arr.reduce((a,b)=>a+b) in code_JS

    accuracy = float(respcorrsSum)/considerNrTrials
    
    if accuracy > minAccuracy:
        continueRoutine = False
        trials.finished = True

if accuracy > minAccuracy:
     textComponent.text='Accuracy reached!'
     accuracyReached = 1 
else:
     textComponent.text='Accuracy only '+str(accuracy)
     accuracyReached = 0 

#These will only work if your text component is called textComponent

Thanks so much.

I’ve plugged this in and added what you suggested about sum to the code_JS (already had append in)

I now have text that flashes up with the stimuli saying ‘Accuracy only 0’

Cool. So now we need to work it backwards. Try
textComponent.text='Accuracy only '+str(respcorrsSum)

So I put this in:

else:
     textComponent.text='Accuracy only '+str(respcorrsSum)
     accuracyReached = 0 

it initially said respcorrsSum not defined so I put rescorrsSum=0 in begin experiment tab
I still get the same 'Accuracy only 0’ message flashing simultaneously with the stimuli

The way I dealt with this recently (and didn’t use a slice) used code like:

respcorrs.append(resp.corr)
if len(respcorrs) > considerNrTrials:
     respcorrs,pop(0)
respcorrsSum = sum(respcorrs)

Note my crib sheet for the translation of pop(0)

respcorrs.append(resp.corr)
if len(respcorrs) > considerNrTrials:
     respcorrs,pop(0)
respcorrsSum = sum(respcorrs)
     accuracy = float(respcorrsSum)/considerNrTrials
     
    if accuracy > minAccuracy:
        continueRoutine = False
        trials.finished = True

if accuracy > minAccuracy:
     textComponent.text='Accuracy reached!'
     accuracyReached = 1 
else:
     textComponent.text='Accuracy only '+str(respcorrsSum)
     accuracyReached = 0 

There’s a syntax error with this, I’m assuming I’m missing something really obvious??

There was a comma instead of a full stop and the indents were out

respcorrs.append(resp.corr)
if len(respcorrs) > considerNrTrials:
     respcorrs.pop(0)

respcorrsSum = sum(respcorrs)
accuracy = float(respcorrsSum)/considerNrTrials
     
if accuracy > minAccuracy:
    continueRoutine = False
    trials.finished = True

if accuracy > minAccuracy:
     textComponent.text='Accuracy reached!'
     accuracyReached = 1 
else:
     textComponent.text='Accuracy only '+str(respcorrsSum)
     accuracyReached = 0 

Thank you!
Okay so now it’s saying ‘Accuracy only 1’ but not ending after 3 trials correct