Images not displaying in self-paced reading experiment

URL of experiment: Sign in · GitLab

Description of the problem:
I’m trying to create a self-paced reading experiment through PsychoPy which I can run online. Participants would read a sentence one word at a time, and then choose one of two images which best represents the sentence they previously read. Since I’m a linguistics student with little coding knowledge, I’m using the builder.

For the self-paced reading routine, I’ve been through the very helpful PsychoPy Python to Javascript Crib Sheet to help me debug parts of the reading_code component which weren’t translating from Python to JS.

When I run the experiment on PsychoPy it works great, but when I run it through Pavlovia, the image which should appear after the first sentence does not display. A blank screen appears and I have to press ‘esc’ to end the experiment. Before I added the reading_code component to make the sentences appear one word at a time, the pictures displayed normally, so I don’t think this is an issue of where I’ve stored the image files. I’ve also pasted the JS from the reading_code component here:

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);
var _kb;
kb = event.getKeys({"timeStamped": true});
if ((kb.length > 0)) {
    if (_pj.in_es6("space", kb[0])) {
        try {
            nextWord = word_list.shift();
            text.text = nextWord;
        } catch(e) {
            continueRoutine = false;
            rtList.append(kb[0][1]);
            return;
        }
    }
    rtList.append(kb[0][1]);
}


For reference, here is a screenshot of the image routine.


I’ve been through the forums and cribsheet, but if anyone has suggestions, they would be appreciated!

Thanks!

Is image_key waiting for a space?

The space being used to end the previous routine is still down when this routine starts. You need to clear the keyboard buffer, for example in End Routine of your code component.emphasized text

Thanks for responding!

I don’t think image_key is waiting for a space. Participants are supposed to see two pictures labelled A & B side by side (in a single image= stim_image), so image_key corresponds with the picture they choose, ‘A’ or ‘B’. I tried putting the event.clearEvents() function in the End Routine tab of my code component, but nothing seems to change.

In Pavlovia, I turned on the option to receive incomplete results to see whether that would tell me anything useful. When I checked the Excel file, it was blank. So, I think this means that the “word” routine is not ending.

Do you have any other suggestions that I could try?

Thank you again!

Okay, I think I’ve narrowed down what the problem is. In the previous code, I did not have a way to end the Word routine, so after the words appeared on the screen, the screen stayed blank.

I looked at related forum posts and attempted to add the last few lines of code to the “Word” routine code component.

kb = event.getKeys({"timeStamped": true});
if ((kb.length > 0)) {
    if (_pj.in_es6("space", kb[0])) {
        try {
            nextWord = word_list.pop();
            text.setText(nextWord);
        } catch(e) {
            if ((e instanceof IndexError)) {
                rtList.append(kb[0][1]);
                break;
            } else {
                throw e;
            }
        }
    }
    rtList.append(kb[0][1]);
}
if ((kb.length >= 0)) {
    continueRoutine = false;
}

When I run that, the “Word” routine is skipped completely, continuing to the next routine and through to the end of the experiment. :rofl:

Any suggestions on how I should amend the last lines of code?

I’m not very good at interpreting the JS so please could you show the Python side? It might be that you should use a simpler getKeys. I’m not sure you can use it for the reaction time.

Sorry about that! Yes, here is the complete Python side:

kb = event.getKeys(timeStamped=True)

if len(kb) > 0:
        if 'space' in kb[0]:
            try:
                nextWord = word_list.pop()
                text.setText(nextWord)
            except IndexError:
                rtList.append(kb[0][1])
                break
        rtList.append(kb[0][1])

if len(kb) >= 0:
    continueRoutine = False

Isn’t this always going to be true and therefore end the routine on the first frame?

Ah, yes you are right, which is why it was ending the routine on the first frame!

However, if I edit it to if len(kb) < 0 doesn’t work and changing it to = 0 tells me there’s syntax error.

I know that I basically need the code to say “when there are no words to display, end the routine”, but I’m not sure how to do that. :slight_smile:

Isn’t that the length of word_list ? Use == to test for equality

Yes, sorry. Perhaps it would help if I included the code from the Begin Routine tab as well.

word_list = sentence.split()
nextWord = word_list.pop()
text.setText(nextWord)
text.setAutoDraw(True)
rtList = []
event.clearEvents()
clock = util.Clock()

I assumed that len(kb) represented the number of words in each sentence, as word_list= the sentence split into individual words. Because participants must press the spacebar to advance to the next word, I assumed that if I set the function as if len(kb) == 0, that would mean that when word list is depleted, the routine would end. But, clearly I am off!

Your code has kb = getKeys so it’s the current key being pressed.

word_list is an array of the words so len(word_list) is the number of words.

pop removes the final item so you might want pop(0) in Python which I think is shift in JS (check my crib sheet for confirmation on this)

Thanks for your guidance on this! I changed the code to the following, and it worked!

if len(word_list) == 0:
    continueRoutine = False

However, I now have one more issue related to the .pop and .shift functions.

I changed .pop to .shift as the crib sheet suggests, but it still removes the final item from the list. I’ve seen on similar forums that it might have to do with the throw statement in the Javascript translation.

kb = event.getKeys({"timeStamped": true});
if ((kb.length > 0)) {
    if (_pj.in_es6("space", kb[0])) {
        try {
            nextWord = word_list.pop();
            text.setText(nextWord);
        } catch(e) {
            if ((e instanceof IndexError)) {
                rtList.append(kb[0][1]);
                break;
            } else {
                throw e;
            }
        }
    }
    rtList.append(kb[0][1]);
}
if ((word_list.length == 0)) {
    continueRoutine = false;
}

I know you previously said you are not as adept at interpreting JS, but any thoughts on this?

Thank you again for all of your help!

So here you have pop in the JS side.

When you said you tried shift, what did that code look like. To work both locally and online in the same way you need a Both component with .pop(0) in Python and .shift() in JS. However, I have no idea what throw means, nor when you need the try/catch since you could just check the length of word_list first.

Here is what is looks like on the Python side:

kb = event.getKeys(timeStamped=True)

if len(kb) > 0:
        if 'space' in kb[0]:
            try:
                nextWord = word_list.pop(0)
                text.setText(nextWord)
            except IndexError:
                rtList.append(kb[0][1])
                break
        rtList.append(kb[0][1])

if len(word_list) == 0:
    continueRoutine = False

and here is the JS:

kb = event.getKeys({"timeStamped": true});
if ((kb.length > 0)) {
    if (_pj.in_es6("space", kb[0])) {
        try {
            nextWord = word_list.shift();
            text.text = nextWord;
        } catch(e) {
            if ((e instanceof IndexError)) {
                rtList.append(kb[0][1]);
            } else {
                throw e;
            }
        }
    }
    rtList.append(kb[0][1]);
}
if ((word_list.length == 0)) {
    continueRoutine = false;
}

To be honest, I’m also not sure why the try/catch statements are in there; they were a part of the pre-written code that I found to enable the words to appear one at a time. I can try to take them out and see what happens.

Hi again,

Taking out the try and catch statements in the JS didn’t change anything, and the last item still won’t appear. Should I repost this question under a different topic?

Thank you again for all of your help!

Since you’ve marked this one as solved then it might be worth starting a new topic. I try to use the error message as the title.

Gotcha. I’ll do that, thanks!