Load and randomly select images based on condition (block)

Hello,
I’m new in Psychopy and would appreciate your help in solving the following problem:

Background: I’m using a version of the additional singleton task where participants search for a known-shape (pentagon) and an irrelevant (singleton) distractor is presented on 50% of the trials, usually in a different color.

My experiment: Instead of colors, we’re manipulating emotion distractors (4 blocks: angry, happy, sad, neutral; counterbalanced). We have 3 images per emotion condition (3img x 4blocks) from which one image should be randomly selected if singletonPresence == True.

  • Note that the selected image should specifically replace the (non-target) circle item.
  • Also note that I’m using a Psychopy script and the images are stored in a local path

The issue: I’m using costume code to preload and specify under which conditions these images should be presented, but I get an indexing error.

  • The images are loaded in a costume code rather than condition files because I use these to choose practice/main blocks and specify the singletonPresence manipulation.

So:

[begin experiment]

emotion_dist = []

#store images path in lists
angry_stim = ['stimuli/angry1.jpg', 
            'stimuli/angry2.jpg', 
            'stimuli/angry3.jpg']
happy_stim = ['stimuli/happy1.jpg', 
            'stimuli/happy2.jpg', 
            'stimuli/happy3.jpg']
sad_stim =   ['stimuli/sad1.jpg',
            'stimuli/sad2.jpg',
            'stimuli/sad3.jpg']
neutral_stim =  ['stimuli/neutral1.jpg', 
            'stimuli/neutral2.jpg',
            'stimuli/neutral3.jpg']

#set a dictionary of image lists, nested in block keys
conditionBlock_d = {'angry':[angry_stim], 'happy':[happy_stim],
        'sad':[sad_stim], 'neutral':[neutral_stim]}

#counterbalance blocks
conditionBlock_k = list(conditionBlock_d.keys()) #convert to list
shuffle(conditionBlock_k) #randomized blocks across participants

Now, I’m trying to use random.choice() to select only one image per trial from the appropriate key list (the emotion condition, or block). Then, I want to store it in a list so I could call the last item in this list when distPresence == True

[begin routine] 

#randomly choose images based on emotion block
for emotion_img in emotion_dist:
    for block in conditionBlock_k:
        if conditionBlock_k =="angry":
            emotion_img = random.choice(angry_stim)
        elif conditionBlock_k == "happy":
            emotion_img = random.choice(happy_stim)
        elif conditionBlock_k == "sad":
            emotion_img = random.choice(sad_stim)
        elif conditionBlock_k == "neutral":
            emotion_img = random.choice(neutral_stim)
    emotion_dist.append(emotion_img)

In another routine (i.e., search), I use an if statement to set the image’s opacity to 1 in singleton present trials, and zero in singleton absent trials. Then, I store the last item in emotion_dist list as a variable to draw in each frame.

[begin routine]
this_singleton = emotion_dist[-1] #set last item as the singleton in trial[i]

#present emotion singletons
if distPresence == "present":
    this_singleton = visual.ImageStim(win, image=this_singleton)
    this_singleton.setOpacity(1.0)
    singleton_name.append('this_singleton')
else:
    this_singleton.setOpacity(0)
    singleton_name.append("absent");

[each frame]

this_singleton.draw()
this_singleton.setPos([placeholder_size, placeholder_size])
this_singleton.setSize([placeholder_side, placeholder_side])

win.flip()
core.wait(2)

My experiment crashes because of an indexing error that I can’t figure out how to fix -

this_singleton = emotion_dist[-1] #set last item as the singleton in trial[i]
IndexError: list index out of range

I’m completely stuck with how to program thus experiment and would be grateful for your help!

emojiExp.psyexp (60.5 KB)
emojiExp.py (54.2 KB)

Hello Tair,

Please enclose your code in triple `. This will format it correctly. Is this PsychoPy or PsychoJS code? Some of your lines end in a semicolon, which is not Python, but your if-elif constructions look like Python.

Best wishes Jens

Hi Jens, thanks for your response!

I use a Psychopy code and all images are stored in a local foler (/stimuli) in the experiment’s folder.

Would love to know what way would be best to (1) load stimuli and assign them to different lists for each emotion condition, and (2) how to fix this error message?

Thanks again!

Hello,

I am not quite sure. You define emotion_dist as a list in Begin experiment. Then you loop through emotion_dist in Begin routine. But according to the code we see emotion_dist does not have any elements yet. So, there is nothing to loop over.

You can check the content of emotion_dist by printing its contents to the console
ˋˋˋ
print(emotion_dist)
ˋˋˋ

Best wishes Jens
BTW, there is still a semicolon in your code.

Thank you so much!

I changed the code and the images loading part is alright now, however - I get an attribution error message corresponding to the line this_singleton = visual.ImageStim(win, image=emotion_img).
The error message:
AttributeError: Couldn't make sense of requested image.

The code:

# all images from dictionary (key:value == block_name:block_stim]
conditionBlock_v = list(conditionBlock_d.values())

singleton_name = []
for emotion_img in conditionBlock_v:
    #randomly choose the singleton according to emotion condition
    for Block in conditionBlock_k:
        if conditionBlock_k =="angry":
            emotion_img = random.choice(angry_stim)
        elif conditionBlock_k == "happy":
            emotion_img = random.choice(happy_stim)
        elif conditionBlock_k == "sad":
            emotion_img = random.choice(sad_stim)
        elif conditionBlock_k == "neutral":
            emotion_img = random.choice(neutral_stim)
#    draw singleton in distractor present trials
    if distPresence == "present":
        this_singleton = visual.ImageStim(win, image=emotion_img)
        this_singleton.setAutoDraw(True)
        this_singleton.setOpacity(1.0)
        this_singleton.setPos([placeholder_size, placeholder_size])
        this_singleton.setSize([placeholder_side, placeholder_side])
        win.flip()
        core.wait(2.0)
        singleton_name.append(this_singleton)
    else:
        singleton_name.append("absent")

Now, I’m not sure if this error comes from that the images are not read as image objects, or because of the random selection of one image out of 3 images based on which block it is.

Hello Tair

are you using the Builder to program your experiment or are coding everything yourself using the Coder?

Best wishes Jens

I’m using builder to program this experiment but incorporating a lot of cusom code. As for right now, the experiment works but the images are not presented, but with no error message.

In addition to the separate stimuli lists for each emotion condition (block) I showed earlier, I created a list of all images:

[begin experient]
stimuli_path = 'C:/Users/Dell/Documents/PsychoPy_Scripts/EmotionExp'
emotions = []
for file in os.listdir(stimuli_path):
    if file.lower().endswith(".jpg"):
        emotions.append(file)

And here is the updated code from earlier

[begin routine]
singleton_name = []
for emotion_img in emotions:
    #randomly choose the singleton according to emotion block 
    for Block in conditionBlock_k: #key = block name (emotion condition)
        if conditionBlock_k =="angry":
            r = random.choice(angry_stim)
            emotion_img = os.path.join(stimuli_path, r)
        elif conditionBlock_k == "happy":
            r = random.choice(happy_stim)
            emotion_img = os.path.join(stimuli_path, r)
        elif conditionBlock_k == "sad":
            r = random.choice(sad_stim)
            emotion_img = os.path.join(stimuli_path, r)
        elif conditionBlock_k == "neutral":
            r = random.choice(neutral_stim)
            emotion_img = os.path.join(stimuli_path, r)

    #set the selected stimulus as image object
    this_singleton= visual.ImageStim(win, image=emotion_img)
    this_singleton.setAutoDraw(True)
    
    #draw singleton only in distractor present trials
    if distPresence == "present":
        dist1_circle.setOpacity(0)
        this_singleton.setOpacity(1)
        this_singleton.setPos([placeholder_size, placeholder_size])
        this_singleton.setSize([placeholder_side, placeholder_side])
        win.flip()
        core.wait(2.0)
        singleton_name.append(this_singleton)
    else:
        this_singleton.setAutoDraw(False)
        dist1_circle.setOpacity(1)
        this_singleton.setOpacity(0)
        singleton_name.append("absent")

Now I need to figure out why the images are not presented.
Note that distPresence is set by a condition file (attached to this post). I already used this file to program a similar experiement but with simpler stimuli - and it worked. So, if you have any idea of the reason the images are not presented and/or how to fix this, it would be extremely helpful!

Thanks again for your help :slight_smile:
searchTrials.xlsx (8.3 KB)

Hello,

I mainly use the Builder to do most of the stuff, so for reading in stimuli I’d use the Builder. I might not be of much help for you. Anyway, my preferred way for checking is to print the values of the relevant variables to the console. So, I guess I’ would print out the values for emotions, block, emotion_img.

BTW, when mixing code written by the Builder and code written by you, you need to be careful. So adding

win.flip()
core.wait(2)

will affect your timing and are not recommended to be use when using the Builder to program the experiment.