Can Psychopy randomly select a certain number of stimuli to display?

1,396 views
Skip to first unread message

katie Smith

unread,
Mar 13, 2014, 10:40:21 AM3/13/14
to psychop...@googlegroups.com
I am trying to create an experiment for my dissertation, in which I have 36 consistant and 36 inconsistant stimuli, but I don't want every participant to see all 72 (because this would take too long.) Is it possible for psychopy to randomly select for example 10 consistant (out of the 36) and 10 inconsistant (out of the 36) stimuli to be used by a participant? (And if so, how?) I have used the Navon demo as a base, and there are currently there are 72 conditions with 3 parameters (stimFile, congruence and corrAns) as each stimuli is treated as a new condition. There should actually be only 2 conditions - previously seen (consistent) and not previously seen (inconsistent) and I would like to show 10 from each of these conditions in the experiment.

Would really appreciate any help on this, I am stuck!

Thanks,

Katie

Michael MacAskill

unread,
Mar 13, 2014, 4:04:33 PM3/13/14
to psychop...@googlegroups.com
Hi Katie,

Google "Terminate a PsychoPy loop early".

In essence, one line of code required:


if yourLoopName.thisN == 10: yourLoopName.finished = True


Regards,

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

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



katie Smith

unread,
Mar 19, 2014, 3:09:54 PM3/19/14
to psychop...@googlegroups.com
Hi Michael,

Thank you for your reply - it was very helpful :)

The problem I have now is that each picture (stimuli file) is being treated as a separate condition, (meaning I have 72 conditions) instead of 2. Do you know how it is possible to rectify this? I currently have an Excel spreadsheet with 3 columns "StimFile" (which has 72 different file names), "congruence" and "corrAns" which means that there are 72 conditions (each row is treated as a condition I think?) 

I am using builder as this is my first experiment (not sure if this is also important). Thank you for taking the time to answer my questions.

Thank you again,
Katie. 

Michael MacAskill

unread,
Mar 19, 2014, 5:42:38 PM3/19/14
to psychop...@googlegroups.com
Hi Katie,

You'll could explain the structure of your trial in more detail. e.g. Step 1: display a picture, step two:,…, step x, get a keyboard response indicating whatever…

i.e. I'm not sure what "congruence" and "corrAns" refers to in your particular task. Are their values unrelated to the particular content in each image on their corresponding row?

If they are not, then perhaps the easiest thing to do would be to separate your picture file names and the other two columns into separate condition files.

If that was the case, what would your non-picture condition file look like? i.e. would it just have ten rows of two columns, to match the intended subset of the number of pictures to be shown?

With that information, we can probably find a way to achieve what you want. This can be done in Builder, but because you are breaking out of its usual structure (one line in a conditions file per loop iteration), we will need to add in some Code components to achieve it.

Regards,

Michael

katie Smith

unread,
Mar 20, 2014, 8:18:31 AM3/20/14
to psychop...@googlegroups.com
Hi Michael,

My trial will be: step 1: display a picture until keyboard response, step 2: keyboard response (was the picture in the original or not - y/n)
my picture stimuli are small cutouts from larger pictures, 36 are from the original and 36 are from a different picture by the same artist. I want to display a random 10 of the 36 original cutouts, and a random 10 of the 36 cutouts from another picture.
Congruence refers to whether they were in the original picture or not (original picture = consistent, other picture = inconsistent) - I only added this because I used the Navon task demo as a base for this experiment, so perhaps in my case it is not needed.
corrAns refers to the key that the participants should press to give a correct answer on whether the picture has already been seen: y for yes, n for no.

The actual conditions of my experiment are eye movement vs no eye movement, and pictures vs words, but as they are between factors, the words condition will be a separate experiment file, and I will probably create the eye movement on another program, as i do not know how to make a moving dot on Psychopy. I think I got confused when I typed the message before - the pictures (stimuli files) are not conditions, all participants will see the pictures and have to response with y/n. 

Sorry for the confusion, I hope this makes sense! 

Thanks,
Katie

Michael MacAskill

unread,
Mar 20, 2014, 5:42:50 PM3/20/14
to psychop...@googlegroups.com
Hi Katie,

> My trial will be: step 1: display a picture until keyboard response, step 2: keyboard response (was the picture in the original or not - y/n)
> my picture stimuli are small cutouts from larger pictures, 36 are from the original and 36 are from a different picture by the same artist. I want to display a random 10 of the 36 original cutouts, and a random 10 of the 36 cutouts from another picture.
> Congruence refers to whether they were in the original picture or not (original picture = consistent, other picture = inconsistent) - I only added this because I used the Navon task demo as a base for this experiment, so perhaps in my case it is not needed.
> corrAns refers to the key that the participants should press to give a correct answer on whether the picture has already been seen: y for yes, n for no.

That is now very clear: we need to sample randomly from your picture filenames but also retain a balance between consistent and inconsistent. In essence, we need a Code component that will run at the start of the experiment. It will do this sampling and balancing, and then write out a new conditions file on every run of the experiment. It is this custom-created conditions file that you will point your loop to.

You should create two separate CSV files, containing the filenames and a consistency value. Each will be 36 rows. Call them, say:

consistentPictures.csv
inconsistentPictures.csv

The first would look like this:

picture,corrAns
1.png,y
2.png,y
etc

And the second like this:

picture,corrAns
36.png,n
37.png,n
etc

Then add a Code component to your trial routine. In the "Begin experiment" tab, paste something like this (NB THIS IS ENTIRELY UNTESTED CODE):


# read in the conditions:
newConditions = [] # define an initially empty list
for fileName in ['consistentPictures.csv', 'inconsistentPictures.csv']:
conditions = data.importConditions(filename) # create a list of dictionaries
shuffle(conditions) # randomise their order
conditions = conditions[0:9] # select just ten of them
newConditions.append(conditions)
# will end up as 20 randomly selected but balanced-for-consistency trials

# write out the conditions for this run of the experiment
header = newConditions[0].keys() # get the header labels
with open('newConditionList.csv','w') as file: # create a new CSV file
output = csv.DictWriter(f, header) # arrange to write our dictionaries to it
output.writeheader()
output.writerows(newConditions)

You should now have a file called newConditionList.csv, containing 20 rows of filenames and corrAns values. Put that filename in your loop, and set it to run randomly.

> The actual conditions of my experiment are eye movement vs no eye movement, and pictures vs words, but as they are between factors, the words condition will be a separate experiment file, and I will probably create the eye movement on another program, as i do not know how to make a moving dot on Psychopy.
That should be straightforward in PsychoPy (it's what I mainly use it for).

Regards,

Michael



katie Smith

unread,
Mar 22, 2014, 2:33:44 PM3/22/14
to psychop...@googlegroups.com

Dear Michael,

Thank you once again for your help. Unfortunately I am not very familiar with PsychoPy at all, so I am struggling to understand how to add the code bits, and what file names need to go where. I can't work out how to add a code component from builder mode/find the "begin experiment" tab.

I'm sorry, I know this is probably very simple but I have no idea what I am doing. I have never had to build an experiment before.

Thanks,
Katie

Michael MacAskill

unread,
Mar 23, 2014, 4:59:37 AM3/23/14
to psychop...@googlegroups.com

On 23/03/2014, at 7:33 AM, katie Smith <kjs...@hotmail.co.uk> wrote:

> Thank you once again for your help. Unfortunately I am not very familiar with PsychoPy at all, so I am struggling to understand how to add the code bits, and what file names need to go where. I can't work out how to add a code component from builder mode/find the "begin experiment" tab.
>
> I'm sorry, I know this is probably very simple but I have no idea what I am doing. I have never had to build an experiment before.

It would be a good idea to work through the online documentation then, e.g:
<http://www.psychopy.org/builder/components/code.html>

Code components can be found in the Builder interface under the "Custom" section of the component panel on the right hand side.

The files should go in the same folder where you have your current conditions file (i.e. the csv or xlsx file currently containing your picture filenames and corrAns values).

Regards,

Michael



Victor Keller

unread,
Oct 7, 2015, 3:09:19 AM10/7/15
to psychopy-users
Hi Michael,

I'm trying to run your code but am having some issues. I would really appreciate it if you could help me out.

I pasted your code with my file names in a code component on the Begin Experiment tab.
Here's what I pasted:

# read in the conditions: 
newConditions = [] # define an initially empty list 
for fileName in ['Blue.csv', 'Yellow.csv']: 
    conditions = data.importConditions(fileName) # create a list of dictionaries 
    shuffle(conditions) # randomise their order 
    conditions = conditions[0:9] # select just ten of them 
    newConditions.append(conditions) 
    # will end up as 20 randomly selected but balanced-for-consistency trials 

# write out the conditions for this run of the experiment 
header = newConditions[0] # get the header labels 
with open('newConditionList.csv','w') as file: # create a new CSV file 
    output = csv.DictWriter(f, header) # arrange to write our dictionaries to it 
    output.writeheader() 
    output.writerows(newConditions)

 I get the following error:
    
    output = csv.DictWriter(f, header) # arrange to write our dictionaries to it 
NameError: name 'csv' is not defined

Well before this error, it also says that there was an unexpected error loading library avbin, but this also happens when I run different experiments, and they seem to work fine, so I'm guessing it's irrelevant for this issue.

I'm running v1.82.01 on a Windows 10

Thanks in advance,
Victor

Michael MacAskill

unread,
Oct 7, 2015, 3:15:49 AM10/7/15
to psychop...@googlegroups.com

> On 7/10/2015, at 17:13, Victor Keller <vnfsk...@gmail.com> wrote:
>
> I get the following error:
>
> output = csv.DictWriter(f, header) # arrange to write our dictionaries to it
> NameError: name 'csv' is not defined

Hi Victor,

Insert this as the first line of the code:

import csv

> Well before this error, it also says that there was an unexpected error loading library avbin, but this also happens when I run different experiments, and they seem to work fine, so I'm guessing it's irrelevant for this issue.
>
> I'm running v1.82.01 on a Windows 10
Yes, you can ignore that. But you should probably update to the very latest version which I think prevents that, as well as providing a few other useful improvements.

Regards,

Michael


Victor Keller

unread,
Oct 7, 2015, 1:39:22 PM10/7/15
to psychopy-users
Hi Michael,

Thank you for the quick response. I inserted import csv as the first line of code and got the following error:

    output = csv.DictWriter(f, header) # arrange to write our dictionaries to it 
NameError: name 'f' is not defined

Shooting in the dark, but I guessed that the file name or the word file would have to be there instead of f.
Here's the error when I insert the file name:

    output = csv.DictWriter('newConditionList.csv', header) # arrange to write our dictionaries to it 
  File "csv.pyc", line 133, in __init__
TypeError: argument 1 must have a "write" method

And here's the error when I insert the word file instead:

    output.writeheader() 
  File "csv.pyc", line 136, in writeheader
TypeError: unhashable type: 'dict'

Thanks again for the help,
Victor

Michael MacAskill

unread,
Oct 7, 2015, 4:38:27 PM10/7/15
to psychop...@googlegroups.com
> I inserted import csv as the first line of code and got the following error:
>
> output = csv.DictWriter(f, header) # arrange to write our dictionaries to it
> NameError: name 'f' is not defined
>
> Shooting in the dark, but I guessed that the file name or the word file would have to be there instead of f.

The latter is correct. As noted at the time, this was untested code…

> And here's the error when I insert the word file instead:
>
> output.writeheader()
> File "csv.pyc", line 136, in writeheader
> TypeError: unhashable type: 'dict'

Try this instead (still untested):

header = newConditions[0].keys() # get the header labels AS A LIST

with open('newConditionList.csv','w') as file: # create a new CSV file
output = csv.DictWriter(file, fieldnames=header) # arrange to write our dictionaries to it
output.writeheader()
output.writerows(newConditions)

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

Richard Höchenberger

unread,
Oct 7, 2015, 4:49:15 PM10/7/15
to psychop...@googlegroups.com
Hey Victor,

On Wed, Oct 7, 2015 at 7:39 PM, Victor Keller <vnfsk...@gmail.com> wrote:
> output = csv.DictWriter(f, header) # arrange to write our dictionaries
> to it
> NameError: name 'f' is not defined
>
> Shooting in the dark, but I guessed that the file name or the word file
> would have to be there instead of f.
> Here's the error when I insert the file name:
>
> output = csv.DictWriter('newConditionList.csv', header) # arrange to
> write our dictionaries to it
> File "csv.pyc", line 133, in __init__
> TypeError: argument 1 must have a "write" method

there was a small mistake in Michaels earlier recommendation. He
stated to do it like this:
--------------------
header = newConditions[0] # get the header labels
with open('newConditionList.csv','w') as file: # create a new CSV file
output = csv.DictWriter(f, header) # arrange to write our dictionaries to it
output.writeheader()
output.writerows(newConditions)
--------------------

Actually, the 3rd line should read:
--------------------
output = csv.DictWriter(file, header) # arrange to write our
dictionaries to it
--------------------

so the 'f' should be replaced with 'file'.
You would still have to include 'import csv' in your script, of course.

Hope that helps.

Richard

Michael MacAskill

unread,
Oct 7, 2015, 4:57:34 PM10/7/15
to psychop...@googlegroups.com

> On 8/10/2015, at 09:48, Richard Höchenberger <richard.ho...@gmail.com> wrote:
>
> there was a small mistake in Michaels earlier recommendation.

Thanks, Richard. Unfortunately, fixing that revealed yet another error further on…

Maybe I should actually try out more of my code before sharing it :-)

Michael

Richard Höchenberger

unread,
Oct 7, 2015, 6:34:22 PM10/7/15
to psychop...@googlegroups.com
On Wed, Oct 7, 2015 at 10:57 PM, Michael MacAskill
<michael....@nzbri.org> wrote:
> Thanks, Richard. Unfortunately, fixing that revealed yet another error further on…
>
> Maybe I should actually try out more of my code before sharing it :-)

Hehe, I noticed your response just as I hit the Send button :) Also I
think that, sometimes, providing "ideas" of (possibly buggy) code can
be a good strategy, as it cuts down the time it takes to draft a reply
... Then, of course, this can come with certain drawbacks ;)

All the best,

Richard

Victor Keller

unread,
Oct 9, 2015, 9:35:46 AM10/9/15
to psychopy-users
Thanks you both for the responses! I really appreciate it.

I'm trying to understand and debug the code myself, but I'm only just learning and can't figure out most problems.

I typed in the code and got this error:

    header = newConditions[0].keys() # get the header labels as a list
AttributeError: 'list' object has no attribute 'keys'

Any ideas on how to solve it?

Thanks!
Victor

Michael MacAskill

unread,
Oct 9, 2015, 5:58:28 PM10/9/15
to psychop...@googlegroups.com

> On 10/10/2015, at 02:35, Victor Keller <vnfsk...@gmail.com> wrote:
>
> header = newConditions[0].keys() # get the header labels as a list
> AttributeError: 'list' object has no attribute 'keys'

Hi Victor,

How many errors could I pack in just a few lines of code? :-/

This problem is likely due to earlier on, with the line:

newConditions.append(conditions)

This should actually be:

newConditions.extend(conditions)

i.e. what the append was doing was making the first (zeroth) entry in newConditions be the entire list 'conditions', rather than adding all of its items individually as dictionaries. Using the 'extend' method should actually do that. Good luck.

Michael


Victor Keller

unread,
Oct 12, 2015, 11:21:38 PM10/12/15
to psychopy-users
It works! ...on a mac, which is where I need it to work :)
On my windows it decided to complain about the avbin library. There seem to be other posts about that issue...

Thank you for the help and taking the time to explain the code, Michael!

Here it is in case someone else needs it:

# read in the conditions: 
import csv
newConditions = [] # define an initially empty list 
for fileName in ['Blue.csv', 'Yellow.csv']: 
    conditions = data.importConditions(fileName) # create a list of dictionaries 
    shuffle(conditions) # randomise their order 
    conditions = conditions[0:10] # select just ten of them 
    newConditions.extend(conditions) 
    # will end up as 20 randomly selected but balanced-for-consistency trials 

# write out the conditions for this run of the experiment 
header = newConditions[0].keys() # get the header labels as a list
with open('newConditionList1.csv','w') as file: # create a new CSV file 
    output = csv.DictWriter(file, fieldnames=header) # arrange to write our dictionaries to it 
    output.writeheader() 
    output.writerows(newConditions)

Comments on the code may be inaccurate

Best,
Victor
Message has been deleted

Danielle Taylor

unread,
Sep 7, 2018, 12:02:54 PM9/7/18
to psychopy-users
Hello All,

I am having a similar problem with an experiment I am trying to design (also for my dissertation).  I have a task in which participants are presented with one image followed by another image. Fairly simple aside from the fact that I have 3 conditions files with these images that I would like to pseudo-randomly select from.

Examples of the 3 conditions files are below with their respective parameters:

threat1.csv
image1.jpg       image2.jpg
image3.jpg       image4.jpg
image5.jpg       image6.jpg

threat2.csv
image1.jpg       image7.jpg
image3.jpg       image8.jpg
image5.jpg       image9.jpg

neutral.csv
image10.jpg     image11.jpg
image12.jpg     image13.jpg
image14.jpg     image15.jpg

The 2 threat files contain 40 images and the neutral condition contains 20 images. In total, the whole neutral file should be used and twenty from each threat file, for a total of 60 trials. These should be presented randomly. In addition, my threat files contain the same image for the first image presentation, but the second image is different in each file. I would like for experiment to not ever have the same initial image presentation, so if image1.jpg is presented from threat1.csv, the program does not select image1.jpg from threat2.csv. I hope this makes sense.

 I have attempted to use and modify the code that Victor used at the bottom of this thread (See my version below) to at least randomly select images to start. However, I received error codes for each of the bottom indentations. For example,
"output = csv.DictWriter (file, fieldnames = header) # arrange to write our dictionaries to it
 ^
IndentationError: unexpected indent"

After removing the indents for the last three lines, I received several other errors, which makes me believe that there is an error with my code. I am hoping that someone may help me 1) get the code to work for a PC using Psychopy v1.83.00 and 2) modify it so that the presentation of threat images do not repeat. I am aware that the version of psychopy is a bit out dated, but we are running a study that was programmed on this version and have decided to not update until that study is complete.

Please let me know if additional information is needed and thank you!
Danielle

# read in the conditions:

import csv

newConditions = [] #define an initially empty list

for fileName in ['Neutral.csv', 'Threat1.csv', 'Threat2.csv']:

    conditions = data.importConditions(fileName) #creat a list of dictionaries

    shuffle(conditions) #randomize their order

    conditions = conditions[0:20] #select just twenty of them

    newConditions.extend(conditions)

    #will end up as 60 randomly selected but balanced for consistency trials

 

#write out the conditions for this run of the experiment

header = newConditions[0].keys() # get the header labels as a list

    output = csv.DictWriter(file, fieldnames = header) #arrange to write our dictionaries to it

    output.writeheader()

    output.writerows(newConditions)

Reply all
Reply to author
Forward
0 new messages