psychopy.org | Reference | Downloads | Github

Builder to pavlovia code issue

Hello,

When running the python code component in the builder it behaves perfectly, when syncing to pavlovia issues arose. First (thanks to @jonathan.kominsky ) i inserted psychoJS.eventManager.getKeys() into the JS generated code as originally it used event.getKeys() which doesn’t exist in JS.

However the issue i have is that when n is pressed, it functions as would expect, however when y is pressed it functions the same as n, it is meant to end the whole loop and move on to next routine. I do not get any errors when syncing the experiment, or when running it. How do i get the y press to behave as it did in the builder?

code component snippet below.

Any help will be greatly appreciated.

Thank you

Try replacing MoveYN.finished with trials.finished. In PsychoJS, trials.finished is a proxy for “the current loop”.finished and tends to be more reliable than using the name of the loop.

1 Like

Brilliant, will give that a try. Thank you :slight_smile:

I am having a similar problem as my conditional statement doesn’t behave in the same way online as locally. It probably has something to do with ‘every frame’. I have two scales, with a red dot that moves depending on buttons pressed. The red dot should be inside the white circles on the scales, but for some reason when online, it simply doesn’t go to the right location. The locations are specified in a code component. Any suggestions of how to approach this are much appreciated. Thank you! https://gitlab.pavlovia.org/PhiliastidesLab/main_two_scales

have you got the code component code to share? And what it shows when it converts Auto>JS please?

Might be a units issue. It looks like the units for the images (image_3 and image_6 are the ones involved, yes?) are getting their units from experiment settings. What units are you using? Norm units, height units, or something else? You may want to set the units of those specific components in the component itself just to be sure it’s consistent between python and online.

Looking at how it behaves online, it seems like it has something to do with the update of the red dot location on every frame. It moves the right distance, but doesn’t start from the correct place.

This is the starting point both locally and online:
Screenshot 2020-05-22 at 15.57.09

Locally, when I press left it goes to the correct place:
Screenshot 2020-05-22 at 15.56.14

On Pavlovia, it goes to the middle and then when pressing left or right, it moves the right amount left or right from the middle for milliseconds, and then starts back from the middle (rather than being kept to the last location):
Screenshot 2020-05-22 at 15.57.17

JS at Begin routine:

event.clearEvents("keyboard");
x = 0.15;
y = 0.15;

Auto>JS for Each frame (I only manually added keys = psychoJS.eventManager.getKeys();):

var _pj;
function _pj_snippets(container) {
    function in_es6(left, right) {
        if (((right instanceof Array) || ((typeof right) === "string"))) {
            return (right.indexOf(left) > (- 1));
        } else {
            if (((right instanceof Map) || (right instanceof Set) || (right instanceof WeakMap) || (right instanceof WeakSet))) {
                return right.has(left);
            } else {
                return (left in right);
            }
        }
    }
    container["in_es6"] = in_es6;
    return container;
}
_pj = {};
_pj_snippets(_pj);
keys = psychoJS.eventManager.getKeys();
pos = [x, y];
maxp = 0.15;
minp = (- 0.15);
change = 0.1;
if (keys.length) {
    if (_pj.in_es6("left", keys)) {
        pos = [maxp, 0.15];
        x = (x - change);
        pos = [x, y];
        x = Math.round(x, 2);
        msg = x.toString();
        if ((x < (- 0.17))) {
            x = maxp;
            pos = [x, y];
            x = Math.round(x, 2);
            msg = x.toString();
        }
    } else {
        if (_pj.in_es6("right", keys)) {
            pos = [minp, 0.15];
            x = (x + change);
            pos = [x, y];
            x = Math.round(x, 2);
            msg = x.toString();
            if ((x > 0.17)) {
                x = minp;
                pos = [x, y];
                x = Math.round(x, 2);
                msg = x.toString();
            }
        }
    }
}
if (_pj.in_es6("space", keys)) {
    continueRoutine = false;
}

Now that I’ve looked more closely I think I see the issue. Math.round doesn’t work like Python’s rounding function. It will round to a whole number every time, you can’t specify the decimal points, so was always rounding to 0, then it was updating on each frame because you had pos=[x,y] running at the start of each frame, which you also didn’t need. You also don’t need to do any rounding, or you shouldn’t.

Here’s some modified code, I’ve commented where I changed stuff.

var _pj;
function _pj_snippets(container) {
    function in_es6(left, right) {
        if (((right instanceof Array) || ((typeof right) === "string"))) {
            return (right.indexOf(left) > (- 1));
        } else {
            if (((right instanceof Map) || (right instanceof Set) || (right instanceof WeakMap) || (right instanceof WeakSet))) {
                return right.has(left);
            } else {
                return (left in right);
            }
        }
    }
    container["in_es6"] = in_es6;
    return container;
}
_pj = {};
_pj_snippets(_pj);
keys = psychoJS.eventManager.getKeys();
// you should set the initial value of pos in "begin routine", and only update it when needed.
maxp = 0.15;
minp = (- 0.15);
change = 0.1;
if (keys.length) {
    if (_pj.in_es6("left", keys)) {
        // got rid of a line here. don't need to set pos to max for any reason.
        x = (x - change);
        pos = [x, y];
        // you don't need to round anything.
        msg = x.toString();
        if ((x < (- 0.17))) {
            x = maxp;
            // same here.
            pos = [x, y];
            msg = x.toString();
        }
    } else {
        if (_pj.in_es6("right", keys)) {
            // again, ditched a line here.
            x = (x + change);
            // got rid of rounding.
            pos = [x, y];
            msg = x.toString();
            if ((x > 0.17)) {
                x = minp;
                // got rid of rounding.
                pos = [x, y];
                msg = x.toString();
            }
        }
    }
}
if (_pj.in_es6("space", keys)) {
    continueRoutine = false;
}

That will probably work better. Also, if you find for whatever reason you need to do that rounding, then you want to do it like so:

Math.round(x*100)/100;
1 Like

That worked perfectly, thank you ever so much for your help.

I have some routines and trials that i do not wish to capture any data for in the output csv files, is this another instance of inserting code in the code component or is there a setting somewhere in the builder i am missing? The data i wish to not capture has a loop but it is not set to trials…

Not really possible, I’m afraid. PsychoPy wants to make really damn sure it doesn’t fail to collect data when you expect it to (for good reason), so it doesn’t really give you a way to selectively fail to collect data for anything in the builder.

Hi Jon,

My crib sheet now contains a function for round with decimal places courtesy of @dvbridges

Best wishes

Wakefield

is it possible to do so when the experiment is in pavlovia? Inserting a code component maybe?

Not as far as I know.

ok, thank you. I will just edit the outputs.

Thank you so much! This worked for the first scale, the second one still doesn’t work as expected but I will look more closely into it first. Rounding was used because I was getting funny locations initially, but I guess I didn’t really need it.