URL of experiment: Pavlovia
Description of the problem: Image coordinates / size variables updating smoothly offline with PsychoPy, but seem to be refreshing slowly, in a jittery manner, and inconsistently across items online on Pavlovia.
More detail: In one of my routines, I have variables for the position coordinates, size, and opacity of certain image components that update on the basis of the “Each Frame” view of a code snippet. The code snippet checks whether a certain keyboard component has been pressed yet, and if it has, on each new frame, adds or multiplies the previous value of those variables by a set amount to animate various paths (e.g. moving in a straight line, moving in a parabola while shrinking).
Offline, the Python version runs smoothly, and these animations work smoothly.
On Pavlovia, however, the animations are very jittery. It seems to me (since the timing of shrinking and movement are still correctly synchronized with each other) that the frame refresh rate is slower and/or inconsistent. I’m particularly bemused because an earlier pilot version did not seem to have these jitter / frame refresh rate issues. I can’t find any changes that I would have made that would have changed this. Moreover, I have similar animations in a different routine with a very similar code snippet that are jitterier than the offline version, but still smoother than this particular routine.
Is there something that might be affecting online frame refresh rates? Or is there something in PsychoJS (either my code snippet) or something about image drawing that might be causing this?
The offending routine, if you are taking a look at my experiment, is training_display. I provide the (different) PsychoPy and PsychoJS code snippets below as well, for reference. The image components that get updated depend on which loop the routine is in, but I give screenshots of two representative affected image components.
Image component that relies on beamX and beamY variables:
Image component that relies on rightFruitX, rightFruitY, rightFruitSizeX, rightFruitSizeY, rightFruitOpacity variables:
The PsychoPy code snippet (works smoothly offline):
if routine == "training2":
if len(choose_button.keys) > 0:
if corrAns == "left":
if beamX > -0.44:
beamX -= 0.004
beamY -= 0.004
if beamX < -0.42:
choose_button_manual = "FINISHED"
else:
if beamX < 0.44:
beamX += 0.004
beamY -= 0.004
if beamX > 0.42:
choose_button_manual = "FINISHED"
else:
beamX = 0
beamY = 0.32
elif routine == "training4":
if corrAns == "left":
if len(choose_button.keys) > 0:
if verbID == "beamup":
if (leftFruitX < 0) & (frameN % 2):
leftFruitX += 0.02
leftFruitY = (leftFruitY + 0.004) * 1.1 #test
leftFruitSizeX *= 0.95
leftFruitSizeY *= 0.95
if leftFruitX >=0:
leftFruitOpacity = 0
choose_button_manual = "FINISHED"
else:
if (leftFruitX < 0) & (frameN % 2):
leftFruitX -= 0.012
leftFruitY = (leftFruitY - 0.004) * 1.1 #test
leftFruitSizeX *= 0.95
leftFruitSizeY *= 0.95
if leftFruitX <-0.76:
leftFruitOpacity = 0
choose_button_manual = "FINISHED"
else:
leftFruitX = -0.44
leftFruitY = 0
leftFruitSizeX = 0.84
leftFruitSizeY = 0.6
leftFruitOpacity = 1
else: #i.e. if corrAns == "right"
if len(choose_button.keys) > 0:
if verbID == "beamup":
if (rightFruitX > 0) & (frameN % 2):
rightFruitX -= 0.02
rightFruitY = (rightFruitY + 0.004) * 1.1 #test
rightFruitSizeX *= 0.95
rightFruitSizeY *= 0.95
if rightFruitX <= 0:
rightFruitOpacity = 0
choose_button_manual = "FINISHED"
else:
if (rightFruitX > 0) & (frameN % 2):
rightFruitX += 0.012
rightFruitY = (rightFruitY - 0.004) * 1.1 #test
rightFruitSizeX *= 0.95
rightFruitSizeY *= 0.95
if rightFruitX > 0.76:
rightFruitOpacity = 0
choose_button_manual = "FINISHED"
else:
rightFruitX = 0.44
rightFruitY = 0
rightFruitSizeX = 0.84
rightFruitSizeY = 0.6
rightFruitOpacity = 1
elif routine == "validation":
if len(choose_button.keys) > 0:
choose_button_manual = "FINISHED"
choose_button.getKeys()
onward_button.getKeys()
The PsychoJS code snippet (works weirdly online):
if ((routine === "training2")) {
if ((typeof choose_button.keys!== 'undefined')) {
if ((corrAns === "left")) {
if ((beamX > (- 0.44))) {
beamX -= 0.004;
beamY -= 0.004;
}
if ((beamX < (- 0.42))) {
choose_button_manual = "FINISHED";
}
} else {
if ((beamX < 0.44)) {
beamX += 0.004;
beamY -= 0.004;
}
if ((beamX > 0.42)) {
choose_button_manual = "FINISHED";
}
}
} else {
beamX = 0;
beamY = 0.32;
}
} else {
if ((routine === "training4")) {
if ((corrAns === "left")) {
if ((typeof choose_button.keys !== 'undefined')) {
if ((verbID === "beamup")) {
if (((leftFruitX < 0) & (frameN % 2))) {
leftFruitX += 0.02;
leftFruitY = ((leftFruitY + 0.004) * 1.1);
leftFruitSizeX *= 0.95;
leftFruitSizeY *= 0.95;
}
if ((leftFruitX >= 0)) {
leftFruitOpacity = 0;
choose_button_manual = "FINISHED";
}
} else {
if (((leftFruitX < 0) & (frameN % 2))) {
leftFruitX -= 0.012;
leftFruitY = ((leftFruitY - 0.004) * 1.1);
leftFruitSizeX *= 0.95;
leftFruitSizeY *= 0.95;
}
if ((leftFruitX < (- 0.76))) {
leftFruitOpacity = 0;
choose_button_manual = "FINISHED";
}
}
} else {
leftFruitX = (- 0.44);
leftFruitY = 0;
leftFruitSizeX = 0.84;
leftFruitSizeY = 0.6;
leftFruitOpacity = 1;
}
} else {
if ((typeof choose_button.keys !== 'undefined')) {
if ((verbID === "beamup")) {
if (((rightFruitX > 0) & (frameN % 2))) {
rightFruitX -= 0.02;
rightFruitY = ((rightFruitY + 0.004) * 1.1);
rightFruitSizeX *= 0.95;
rightFruitSizeY *= 0.95;
}
if ((rightFruitX <= 0)) {
rightFruitOpacity = 0;
choose_button_manual = "FINISHED";
}
} else {
if (((rightFruitX > 0) & (frameN % 2))) {
rightFruitX += 0.012;
rightFruitY = ((rightFruitY - 0.004) * 1.1);
rightFruitSizeX *= 0.95;
rightFruitSizeY *= 0.95;
}
if ((rightFruitX > 0.76)) {
rightFruitOpacity = 0;
choose_button_manual = "FINISHED";
}
}
} else {
rightFruitX = 0.44;
rightFruitY = 0;
rightFruitSizeX = 0.84;
rightFruitSizeY = 0.6;
rightFruitOpacity = 1;
}
}
} else {
if ((routine === "validation")) {
if ((typeof choose_button.keys !== 'undefined')) {
choose_button_manual = "FINISHED";
}
}
}
}