Masked self-paced reading

1,130 views
Skip to first unread message

Paula

unread,
Oct 29, 2015, 10:26:47 AM10/29/15
to psychopy-users
I would like to know if it is possible to create a masked self-paced reading experiment, preferentially, with the Builder.
Thanks in advance.

Michael MacAskill

unread,
Oct 29, 2015, 5:43:55 PM10/29/15
to psychop...@googlegroups.com
Hi ? Paula,

> On 30/10/2015, at 03:26, Paula <paula...@gmail.com> wrote:
>
> I would like to know if it is possible to create a masked self-paced reading experiment, preferentially, with the Builder.

Quite possibly. But this is a pretty wide audience. Don't assume that everyone will be familiar with the implementation details of a particular paradigm just by its name (and you might need an important variation to the standard). Can you describe it more in terms of a detailed account of how the stimuli need to be presented, how the subject responds, and so on?

Regards,

Michael

--
Michael R. MacAskill, PhD 66 Stewart St
Research Director, Christchurch 8011
New Zealand Brain Research Institute NEW ZEALAND

Senior Research Fellow, michael....@nzbri.org
Te Whare Wānanga o Otāgo, Otautahi Ph: +64 3 3786 072
University of Otago, Christchurch http://www.nzbri.org/macaskill

Paula Luegi

unread,
Oct 30, 2015, 9:47:41 AM10/30/15
to psychop...@googlegroups.com

Hi Michael,

 

Sorry, of course, you are right. I was both rude and vague. I really apologize for that.

            

I would like to run an experiment with self-paced reading where the sentence would be presented with a mask (all characters would be replaced by a “x”) and participants would have to press a key (the space bar, for instance) for the words or segments of the sentence to be revealed. Whenever a word/segment is revealed, the previous segment is masked again until the end of the sentence.

 

I could create a list on Excel and create a mask for each word, but I would like the masking process to be automatic.

 

The software LINGER was developed to do just that, but I would like to use PsychoPy instead.

 

Thanks a lot,

 

Paula


--
You received this message because you are subscribed to a topic in the Google Groups "psychopy-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/psychopy-users/sjX7_Oa_WXc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to psychopy-user...@googlegroups.com.
To post to this group, send email to psychop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/psychopy-users/C93A62EB-FE24-4A02-823E-8768A263418C%40nzbri.org.
For more options, visit https://groups.google.com/d/optout.

Michael MacAskill

unread,
Nov 1, 2015, 11:29:54 PM11/1/15
to psychop...@googlegroups.com
Hi Paula,

Thanks for the very clear explanation. I think you've made a good choice: PsychoPy should be able to handle this sort of thing quite well. It isn't a built-in capability though, so you'll need to insert a code component within the Builder interface to do a little magic to manipulate your sentences.

You certainly don't need to create the mask yourself: that is what having access to the Python language vis PsychoPy will allow you to handle automatically. I'm sure other people on this list could provide a much more concise way of achieving this, but I'll give some suggestions below. None of this will be tested, however, so be prepared for some trouble-shooting.

(1) In your Excel file, just have a column (labelled, say "sentence") that contains the sentence for each trial.

(2) Insert a code component within the relevant routine.

(3) In its "begin routine" tab, put some code something like this:

sentenceList = sentence.split()
# this breaks your sentence's single string of characters into a list of individual
# words, e.g. 'The quick brown fox.' becomes ['The', 'quick', 'brown', 'fox.']


# keep track of which word we are up to:
wordNumber = -1 # -1 as we haven't started yet

# now define a function which we can use here and later on to replace letters with 'x':

def replaceWithX(textList, currentWordNumber):

xSentence = ''
for index, word in enumerate(textList): # cycle through the words and their index numbers
if index != currentWordNumber:
xSentence = xSentence + 'x' * len(word) + ' ' # add a string of x characters
else:
xSentence = xSentence + word # except for the current word

return xSentence # yields the manipulated sentence

# now at the very beginning of the trial, we need to run this function for the
# first time. As the current word number is -1, it should make all words 'x'.
# Use the actual name of your Builder text component here:

yourTextComponentName.text = replaceWithX(sentenceList, wordNumber)

# In the Builder interface, specify a "constant" value for the text content, e.g.
# 'test', so it doesn't conflict with our code.


(4) Then in the "Every frame" tab, put in some code like this so that you check the keyboard every time the screen is refreshed (at typically 60 Hz), and alter the text stimulus appropriately:

keypresses = event.getKeys() # returns a list of keypresses

if len(keypresses) > 0: # at least one key was pushed

if 'space' in keypresses:

wordNumber = wordNumber + 1
yourTextComponentName.text = replaceWithX(sentenceList, wordNumber)

elif 'esc' in keypresses:

core.quit() # I think you'll need to handle quitting manually now.


Hope that helps. Come back to us with any problems.

Best wishes,

Michael


> On 31/10/2015, at 02:47, Paula Luegi <paula...@gmail.com> wrote:
>
> I would like to run an experiment with self-paced reading where the sentence would be presented with a mask (all characters would be replaced by a “x”) and participants would have to press a key (the space bar, for instance) for the words or segments of the sentence to be revealed. Whenever a word/segment is revealed, the previous segment is masked again until the end of the sentence.
>
> I could create a list on Excel and create a mask for each word, but I would like the masking process to be automatic.
>
> The software LINGER was developed to do just that, but I would like to use PsychoPy instead.
>
> Thanks a lot,
>
> Paula

Message has been deleted

Paula Luegi

unread,
Nov 5, 2015, 9:35:07 AM11/5/15
to psychop...@googlegroups.com
Hi Michael, 

Thanks a lot!!!

I have tried your suggestion and it works, at least part of it. 

So, one sentence appears first with all letters replaced by "x" and after a "space bar" press each word appears at a time. However, only one sentence appears and after nothing happens. I entered also a "Thanks" trial after the sentence routine but nothing happens.

I had to replace the "ESC" key by "p" because "ESC" was not working. I am not sure if this could be the problem, but I believe that probably not.

I had to make a little change in the code (I'm so proud of me!!!) adding a white space after each word. 

I would like also to register the time spent reading each segment (in this case, each word). How can I add that?

If you want I can send you the experiment I created.

Thanks a lot, again.

Paula

Michael MacAskill

unread,
Nov 5, 2015, 4:01:02 PM11/5/15
to <psychopy-users@googlegroups.com>
Hi Paula,

> I have tried your suggestion and it works, at least part of it.
>
> So, one sentence appears first with all letters replaced by "x" and after a "space bar" press each word appears at a time. However, only one sentence appears and after nothing happens.
> I entered also a "Thanks" trial after the sentence routine but nothing happens.
Not sure exactly what you mean, but maybe that only one trial happens, and then next one doesn't go on? I can see why that would be: we should probably alter the code to go on to the next routine after the last word appears, I guess? e.g.

keypresses = event.getKeys() # returns a list of keypresses

if len(keypresses) > 0: # at least one key was pushed

if 'space' in keypresses:

wordNumber = wordNumber + 1
if wordNumber < len(sentenceList):
yourTextComponentName.text = replaceWithX(sentenceList, wordNumber)
else:
continueRoutine = False # time to go on to the next trial

elif 'escape' in keypresses:

core.quit() # I think you'll need to handle quitting manually now.

> I had to replace the "ESC" key by "p" because "ESC" was not working. I am not sure if this could be the problem, but I believe that probably not.
Oops, I think that should have been 'escape' (as above). Plus lower case is important.

> I had to make a little change in the code (I'm so proud of me!!!) adding a white space after each word.
Well done!

> I would like also to register the time spent reading each segment (in this case, each word). How can I add that?
This can be done easily enough (PsychoPy Builder automatically maintains a variable called 't' that represents the current time in the trial). But bear in mind that the keyboard is only checked once every screen refresh, and that standard keyboards have some inherent timing lags.

The question then becomes how you want to deal with the data at the analysis stage. The options are to create a column for each word's RT (e.g. 'RT_0', 'RT_1', etc) or to bunch them all together in a single column as a list (i.e. a single column called 'RT' that contains values like '[0.5, 0.6, 0.45]', etc.

The latter has the advantage that each cell can contain any number of RTs, whereas in the first, unless each sentence has a fixed number of words, many of the columns will end up with empty values on some trials. But having them in separate columns is probably in general easier to work with in the analysis.

Regards,

Michael



Paula Luegi

unread,
Nov 7, 2015, 6:31:31 PM11/7/15
to psychop...@googlegroups.com
Thank you, Michael!!!

It is working perfectly now!

I would prefer to have a column for each RT, though it is not problematic to have them all together in a cell. How can I do that?

One more thing, is it possible to split the sentence into groups of two words, instead of word-by-word?

Regards,

Paula

--
You received this message because you are subscribed to a topic in the Google Groups "psychopy-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/psychopy-users/sjX7_Oa_WXc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to psychopy-user...@googlegroups.com.
To post to this group, send email to psychop...@googlegroups.com.

Michael MacAskill

unread,
Nov 8, 2015, 3:42:30 AM11/8/15
to <psychopy-users@googlegroups.com>
Hi Paula,

> I would prefer to have a column for each RT, though it is not problematic to have them all together in a cell. How can I do that?

OK (NB all code still untested on my part), the code below extends the previous code to keep track of the response times for each key press:

keypresses = event.getKeys() # returns a list of keypresses

if len(keypresses) > 0: # at least one key was pushed

if 'space' in keypresses:

thisResponseTime = t # the current time in the trial
wordNumber = wordNumber + 1
if wordNumber < len(sentenceList):

if wordNumber == 0: # need to initialise a variable:
timeOfLastResponse = 0

# save the inter response interval for this keypress,
# in variables called IRI_0, IRI_1, etc:
thisExp.addData('IRI_' + str(wordNumber), thisResponseTime - timeOfLastResponse)
timeOfLastResponse = thisResponseTime

# update the text by masking all but the current word
yourTextComponentName.text = replaceWithX(sentenceList, wordNumber)
else:
continueRoutine = False # time to go on to the next trial

elif 'escape' in keypresses:

core.quit() # I think you'll need to handle quitting manually now.

> One more thing, is it possible to split the sentence into groups of two words, instead of word-by-word?
Anything is possible…

Something like this looks a bit cryptic, but should work for sentences with even numbers of words:

pairedList = [sentenceList[i] + ' ' + sentenceList[i+1] for i in range(0, len(sentenceList), 2)]

Regards,

Michael



> On 8/11/2015, at 12:31, Paula Luegi <paula...@gmail.com> wrote:
>
> Thank you, Michael!!!
>
> It is working perfectly now!
>
>
>

Paula Luegi

unread,
Nov 17, 2015, 7:23:25 AM11/17/15
to psychop...@googlegroups.com
Hi Michael, 

Thanks again.

The RTs are being registered! However, I am not sure where should I add the following line of code: 
pairedList = [sentenceList[i] + ' ' + sentenceList[i+1] for i in range(0, len(sentenceList), 2)]

Anyway, since the break of each sentence will be different, in my experiment, since I will divide the sentence not word-by-word, as I thought initially, but phrase-by-phrase (by syntactic constituents), I would like to ask your help for a solution. I thought that it would be possible to identify the split region with a slash and use that information in the code, but, as you imagine, I do not know how to do that.

For instance: "The horse\ raced\ past\ the barn\ fell.". 

Regards,

Paula



--
You received this message because you are subscribed to a topic in the Google Groups "psychopy-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/psychopy-users/sjX7_Oa_WXc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to psychopy-user...@googlegroups.com.
To post to this group, send email to psychop...@googlegroups.com.

Michael MacAskill

unread,
Nov 17, 2015, 4:04:34 PM11/17/15
to <psychopy-users@googlegroups.com>

> On 18/11/2015, at 01:22, Paula Luegi <paula...@gmail.com> wrote:
>
> Anyway, since the break of each sentence will be different, in my experiment, since I will divide the sentence not word-by-word, as I thought initially, but phrase-by-phrase (by syntactic constituents), I would like to ask your help for a solution. I thought that it would be possible to identify the split region with a slash and use that information in the code, but, as you imagine, I do not know how to do that.
>
> For instance: "The horse\ raced\ past\ the barn\ fell.".

Hi Paula,

You have the right idea, but by amazing coincidence the backslash '\' is one of the few characters you can't use for this purpose, as it has special meaning to Python.

You could, however, use the forward slash '/' or pretty much anything else though.

In the "begin routine" tab, change your code to something like this, where you specify the delimiter character to the split function:

sentenceList = sentence.split('/')

which would work if the sentence was this:

> "The horse/ raced/ past/ the barn/ fell."

but beware that spaces will be treated like any other character now, so depending on your needs, you might have to eliminate some to avoid extra spaces at the end of phrases, e.g.:

> "The horse/raced/past/the barn/fell."

Regards,

Michael


Paula Luegi

unread,
Nov 23, 2015, 8:33:58 AM11/23/15
to psychop...@googlegroups.com
Thanks a lot, Michael. Everything is working now!

The slash works just fine and I was almost sure that I would have to use another symbol (instead of backslash), but I used it just as an example. I am getting used to these nuances! That is probably one of the two things I know about programming. :) 

I think I don't have more question, for now...

Thanks a lot, again for your precious help!

Regards,

Paula



--
You received this message because you are subscribed to a topic in the Google Groups "psychopy-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/psychopy-users/sjX7_Oa_WXc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to psychopy-user...@googlegroups.com.
To post to this group, send email to psychop...@googlegroups.com.
Message has been deleted

Michael MacAskill

unread,
Feb 22, 2016, 3:28:09 PM2/22/16
to psychop...@googlegroups.com

> On 23/02/2016, at 00:19, Paula Luegi <paula...@gmail.com> wrote:
>
> Hi Michael,
>
> I am finally implementing the self-paced reading experiment.
>
> However, since some sentences are (very) long, there are some problems with line breaks that I believe are due to the spaces between words. Spaces are not preserved and are as any other character, replaced by "x". Is there a way to open an exception for spaces?

Dear Paula,

Not sure I really understand the issue but you might need to modify the replaceWithX function to cycle through replacing individual characters rather than words with 'x':


def replaceWithX(textList, currentWordNumber):

xSentence = ''
for index, word in enumerate(textList): # cycle through the words and their index numbers
if index != currentWordNumber:
for character in word: # new code
if character == ' ':
xSentence = xSentence + ' '
else:
xSentence = xSentence + 'x'
else:
xSentence = xSentence + word # except for the current word

return xSentence # yields the manipulated sentence


Matheus Almeida

unread,
Jun 13, 2016, 3:13:39 PM6/13/16
to psychopy-users
Hello,
I was going through the topics to see if this had been discussed before, and I am glad it has.
I am trying to do the exact same thing in my experiment, but for some reason I cannot locate these tabs mentioned.

I am using Psychopy 1.83.04 in a Windows 8. Is this a matter of software version, or am I simply looking for these tabs in the wrong place?

Please, help me!
Thnaks in advance.
Matheus

Michael MacAskill

unread,
Jun 13, 2016, 4:40:22 PM6/13/16
to psychop...@googlegroups.com
Dear Matheus,

I was going through the topics to see if this had been discussed before
Excellent.

I am trying to do the exact same thing in my experiment, but for some reason I cannot locate these tabs mentioned.

I am using Psychopy 1.83.04 in a Windows 8. Is this a matter of software version, or am I simply looking for these tabs in the wrong place?

To add custom code in PsychoPy's Builder interface, you need to add a "Code Component", which has separate tabs for code to be executed at the beginning or end of the experiment, the routine, etc. In the "Components" pane, where you see all the standard stimulus components, click the "Custom" label to reveal the icon for the code component. You'll see the relevant tabs when you click that icon.

Matheus Almeida

unread,
Jun 15, 2016, 3:35:37 PM6/15/16
to psychopy-users
Thank you for your answer, Michael.

I have managed to do what you told, also, follow the instructions above and my experiment is working almost perfectly.
There are just two things that are not working perfectly, and if you could help me, I'd be very thankful.

First thing is that, when it records the reaction time in the data file, it never records the RT for the last segment. For instance, my sentences contain each 14 segments. In the data file, the RT part, it starts in IRI_0, when there are only Xs on the screen, and goes on every time I press the space bar, until the before last segment, IR_13. The very last one is not being recorded.

Second thing, every time the RT is above 1 second, it does not add the "dot" to the number (my supposition here). So, if the RT is, say 1.5 seconds, it only shows 15 (again, my suposition here). This is a particular problem to my experiment because sometimes the reaction time is above 1 second. So, I was wondering if there is a way of it showing the RT properly.

In order to show you how everything is on the data file, I'm attaching a screen capture. In green, you see that only the RTs of the segments up to the before last one (in my case, the 13th) are being recorded, and in yellow, you see the RTs that I'm supposing are above 1 second.

Again, thank you for your help.


On Thursday, October 29, 2015 at 11:26:47 AM UTC-3, Paula wrote:
Datafilescreen.jpg
Reply all
Reply to author
Forward
0 new messages