Problems with running experiment online

URL of experiment: https://gitlab.pavlovia.org/CPouw/spr

Hi all,

I have put together a self-paced reading experiment (which works perfectly from Builder) and I would like to put this online, so that participants can run it from their own computer.

I am now piloting it, but I ran into some problems:

  1. The welcome text/instructions show up bigger when I’m running it online than when I’m running it from Builder. Therefore, it doesn’t fit on the screen.
  2. After the instructions, a fixation cross (+) appears on the screen and participants have to press the space bar to read the first word. However, this is not possible online, the experiment just seems to freeze…

I am very new to this, so any help is very welcome!

After browsing this forum for a bit, I found that the problem might be the code components that are still coded in Python. They should be converted to JavaScript. I unfortunately do not know how to do this… Can anybody help me with that?

These are my code components for the trials:

Begin Routine:

word_list = Sentence.split()
word_list.reverse() # switch the order
rtList = []
event.clearEvents()

Each Frame:

while continueRoutine:
    kb = event.getKeys(timeStamped=True)
    if len(kb) > 0:
        if 'space' in kb[0]:
            try:
                # This is the trial onset.
                nextWord = word_list.pop()
                text.setText(nextWord)
            except IndexError:
                continueRoutine = False
                rtList.append(kb[0][1])
                break
        rtList.append(kb[0][1])
        if 'q' in kb[0]:
            core.quit()
    win.flip()

End Routine:

rtList = np.ediff1d(rtList)
try: 
    # study phase
    trials.addData('senLen', len(rtList))
    for rts in range(len(rtList)):
        trials.addData('word_{}'.format(rts), rtList[rts])
except NameError:
    # practice phase
    practice_trials.addData('senLen', len(rtList))
    for rts in range(len(rtList)):
        practice_trials.addData('word_{}'.format(rts), rtList[rts])

Make sure you have the latest version of PsychoPy (2020.1.3), and then in the builder, in each code component, make sure code type is Auto->JS, that should auto-convert your code components to javascript. I am unsure whether all of this will translate correctly (try/except in particular I am uncertain about) but I would start there.

Hi Jonathan, thanks for your reply! I changed the cody type into JS and uploaded the experiment to Pavlovia again, but the same problem occurs :frowning: Even though the experiment works perfectly in Builder.

I was wondering, when you change the code type, is it right that the code disappears? Because if I change the code in the code components from Python to JS, the boxes become empty. This does not seem to be a problem in Builder though, the experiment keeps working fine…

This is my experiment file:

thesis_spr.psyexp (34.4 KB)

You need to change it to “Auto->JS” specifically, which is only available in PsychoPy 2020.1.0 and later. What that should give you is a code window with two panes, Python on the left and Javascript on the right, and it should automatically convert from the Python to the Javascript, or at least attempt to. If you just set it to JS, it’s just showing you the JS code, but it won’t do the automatic conversion.

Thank you, I did that! Indeed, the “End Routine” code is not directly convertible into JS. Do you maybe have suggestion how I could fix it? I tried the following for example (I removed try/except), because it is not very necessary to store the data from the practice phase:

rtList = np.ediff1d(rtList)
trials.addData('senLen', len(rtList))
for rts in range(len(rtList)):
    trials.addData('word_{}'.format(rts), rtList[rts])

That still gives me the following error though:

/* Syntax Error: Fix Python code */

OK, there’s the error message and then there’s something else that’s unrelated and will make this not work, so let’s try to tackle both at once.

The error message I played around with, it’s coming from ‘word_{}’.format(). I think that the javascript translator doesn’t know how to handle the string.format function. Happily, you can work around it pretty easily:

    trials.addData('word_'+str(rts), rtList[rts])

It should stop giving you the error at that point and produce some javascript, but I can tell you now it won’t work if you tried to run it online. ediff1d is a numpy function, but you don’t import numpy, and you will not be able to import numpy when you convert the code to javascript (import statements don’t work in javascript, and numpy is python-specific). So you’ll need to fix that as well.

Looking at what ediff1d does, I think your best bet may be to manually recreate what the function is doing. In python that would look like this:

rtList2 = [] # Creating a new list to take the results
for x in range(len(rtList)-1): 
    # This cycles through the array without getting an out-of-range error on the last one.
    rtList2.append(rtList[x+1] - rtList[x]) 

rtList = rtList2
trials.addData('senLen', len(rtList))
for rts in range(len(rtList)):
    trials.addData('word_'+str(rts), rtList[rts])

That should convert to javascript, and hopefully it will work when you try to run it as well.

Thank you so much for your help! I made the changes, but now I got this error:

Unfortunately we encountered the following error:

  • TypeError: Cannot read property ‘clearEvents’ of undefined

Try to run the experiment again. If the error persists, contact the experiment designer.

In the JavaScript part of the code, replace “event” with “psychoJS.eventManager” wherever it occurs. That means both on the clearEvents line and wherever event.getKeys() is called. The error is just saying it doesn’t know what “event” is, which makes sense, it’s not called “event” in JavaScript.

Thanks again for your help! Unfortunately, another error occurred which undoubtedly has to do with the code conversion again:

ReferenceError: win is not defined

Oh, you have a win.flip() call in your every frame code. You should get rid of that altogether if you can, both for Python and JS. It shouldn’t be needed (it should flip automatically on every frame) and it causes timing issues as I recall.

If you absolutely must have it, replace “win” with “psychoJS.window” in the javascript side of the code component, but again, generally you want to avoid calling win.flip() in a code component altogether.

Unfortunately, I apparently really need win.flip(), because if I remove it, the window does not flip anymore… Also, when replacing “win” with “psychoJS.window”, I get the following error:

TypeError: psychoJS.window.flip is not a function

OK, so I changed it to “psychoJS.window.callOnFlip()”, but now, the screen just freezes after the instructions :frowning:

Oh, I see what’s happening now. It’s the while loop. I didn’t even notice the whole thing was in a while loop, but that’s actually the root problem. Get rid of that and the window flipping stuff and it should all work.

“while continueRoutine” in an “Every frame” code component is basically redundant. PsychoPy will keep automatically showing frames until the routine ends, without any further instruction. Without the while loop, you won’t need to manually flip the screen, it will just flip automatically. Basically you put a whole separate routine control system inside the existing routine control system, which you can kind of do in Python (though I do not recommend it) but you really can’t do in JS. You can trust PsychoPy to take care of the basics for you and just tell it what to do on each frame, and it will figure out how to get to the next frame on its own.

Separately, the reason “callOnFlip” doesn’t work is that it doesn’t actually flip the screen, it just does something when the flip happens. It’s freezing because that function needs arguments and you’re not getting any. The code to make the screen flip in JS is not something I would want to put in a code component, I am virtually certain it would break the whole trial.

Thank you so much! Once again, I changed it, but now I keep getting errors of variables not being defined:

ReferenceError: frameDur is not defined

I know that in JS, variables need to be declared (like var frameDur; right?) first, but for some reason, that does not automatically happen. In fact, none of the variables are declared. Anything I can do about this? Sorry to keep asking questions by the way, your help is much appreciated!!

Ah, that message is actually a kind of red herring. See here: frameDur is not defined error

Basically you might be best off saving a copy of the experiment, and then re-uploading a fresh repository to Pavlovia, which should re-generate the JS code and hopefully fix this issue. If that doesn’t work, what we’ll probably need to do is a little manual editing of the JS file itself, which is a bridge we can cross if we need to but not before.

Re-oploading unfortunately did not fix the issue… The new repository is called:

CPouw/thesis_experiment_new

Unfortunately, I cannot upload the JS file on here directly.

I can see it. Yeah, it’s just completely failing to put in any of the variable declarations at all. This is a bug with PsychoPy’s code translation, if there’s something in the code it can’t handle it just fails spectacularly.

We’re going to have to narrow down which part of the code in particular is causing this failure. Let’s start by getting rid of core.quit(), which may or may not be the source of the issue but almost certainly won’t work. Then what you may need to do is try removing code elements one at a time, re-syncing after each one, and checking whether the js file has a bunch of “var” declarations near the top, until we figure out which one is causing it to trip.

Thank you so much, I figured it out! I had to remove “break” from the Each Frame tab, that caused the error. The vars are back now :slight_smile:

But of course, there is another error:

ReferenceError: IndexError is not defined

Huh, today I learned JavaScript doesn’t call that an IndexError. It’s not clear what error code it has for that, weirdly enough. Maybe just delete the nested “if” inside the catch statement, that way if it catches any error it will do that behavior.