Display a random image in multiple locations at once

Hello everyone!

I made an account to reach out about something that has been stumping me. I am a fairly new to Python and PsychoPy, so I am pretty unfamiliar with some functions. I have talked to a couple of my coder friends, and none of them can seem to come up with a solution besides hard coding.

The task: I am trying to randomly choose an image from a list of images, duplicate that image between 3-7 times, and then display all images at different positions on the screen at the same time. I want a new array of images every trial.

I have looked at the following forums:

but neither seem to fully answer what I am trying to get at, or at least, I am not understanding the advice.

First, for context, the images from the list are hardcoded and look like this:

def images(): 
    n1 = visual.ImageStim(win, image = 'B1.jpg', size = (40, 60), units = 'pix')
    n2 = visual.ImageStim(win, image = 'D1.jpg', size = (40, 60), units = 'pix')
    n3 = visual.ImageStim(win, image = 'F1.jpg', size = (40, 60), units = 'pix')
    n4 = visual.ImageStim(win, image = 'H1.jpg', size = (40, 60), units = 'pix')
    h1 = visual.ImageStim(win, image = 'B100.jpg', size = (40, 60), units = 'pix')
    h2 = visual.ImageStim(win, image = 'D100.jpg', size = (40, 60), units = 'pix')
    h3 = visual.ImageStim(win, image = 'F100.jpg', size = (40, 60), units = 'pix')
    h4 = visual.ImageStim(win, image = 'H100.jpg', size = (40, 60), units = 'pix')
    a1 = visual.ImageStim(win, image = 'B150.jpg', size = (40, 60), units = 'pix')
    a2 = visual.ImageStim(win, image = 'D150.jpg', size = (40, 60), units = 'pix')
    a3 = visual.ImageStim(win, image = 'F150.jpg', size = (40, 60), units = 'pix')
    a4 = visual.ImageStim(win, image = 'H150.jpg', size = (40, 60), units = 'pix')
    global imList
    imList = [n1, n2, n3, n4, h1, h2, h3, h4, a1, a2, a3, a4]

I have tried

im = random.choice(imList)
        
      im1 = copy.deepcopy(im)
      im2 = copy.deepcopy(im)
      im3 = copy.deepcopy(im)
      im4 = copy.deepcopy(im)
      im5 = copy.deepcopy(im)
      im6 = copy.deepcopy(im)
      im7 = copy.deepcopy(im) 

but I get an error saying “ctypes objects containing pointers cannot be pickled.”

I have also tried

  im = random.choice(imList)
  nIms = random.randint(3, 7)
  posList = [[-800, 0], [-700, 0], [-600, 0], [-500, 0], [-400, 0], [-300, 0], [-200, 0]]
  for i in range(int(nIms)):
          imList.append(visual.ImageStim(win, image = im, pos = posList[i]))

but I get “AttributeError: Couldn’t make sense of the requested image”.

Most recently, I have just been trying to hard code:

im = random.choice(imList)
nIms = random.randint(3, 7)
if nIms == 3: 
            im1 = visual.ImageStim(win, image = im, pos = [-500, 0]); im2 = visual.ImageStim(win, image = im, pos = [-400, 0]); im3 = visual.ImageStim(win, image = im, pos = [-300, 0])
            im1.pos = [-400, 0]; im2.pos = [-300, 0]; im3.pos = [-200, 0]

but I recieve the same AttributeError.

Does anyone know how to get around this problem? I want to make copies of the randomly chosen image from this list, make a number of copies based on nIms, and then change each image’s position.

Thank you so much!

Hi!

I have a small update, but unfortunately the project is still unsuccessful at the moment. I found

I think this is closer to what I am looking for, however, when I tried to do something similar, I get an ‘invalid operation’ error. Here is my current code:

im = random.choice(imList)
        nIms = random.randint(3, 7)
        

        # positions
        pos1 = [-750, 0]
        pos2 = [-650, 0]
        pos3 = [-550, 0]
        pos4 = [-450, 0]
        pos5 = [-350, 0]
        pos6 = [-250, 0]
        pos7 = [-150, 0]
        
        if nIms == 3: 
            for pos in [pos1, pos2, pos3]: 
                im.pos = pos
        elif nIms == 4: 
            for pos in [pos1, pos2, pos3, pos4]: 
                im.pos = pos
        elif nIms == 5: 
            for pos in [pos1, pos2, pos3, pos4, pos5]: 
                im.pos = pos
        elif nIms == 6: 
            for pos in [pos1, pos2, pos3, pos4, pos5, pos6]: 
                im.pos = pos
        elif nIms == 7: 
            for pos in [pos1, pos2, pos3, pos4, pos5, pos6, pos7]: 
                im.pos = pos

        im.draw(); win.flip(); core.wait(1)

As a reminder, im is a variable that randomly selected a hard coded image from a list. The images on that list have no assigned position yet. I hope to display a random image a random number of times in different coded positions across the screen. I think the forum linked in this update is close to what I want to do, but if anyone spots anything off with my code, please let me know!

Thank you!

You should put im.draw() in each of the “for” loops after setting im.pos. Otherwise I think that’ll work.

Fundamentally I think what you’re trying to do is achievable not by copying the image object itself but just by calling im.draw() multiple times (and changing the im.pos property each time) before calling win.flip().

A relevant metaphor for how PsychoPy presents visual stimuli is that each frame is canvas that you can draw on as much as you like, and then when you call win.flip() the participant actually sees it. In this case, each im.draw() call adds the image to the canvas at whatever location im.pos currently corresponds to, and calling im.draw() multiple times before the win.flip() means you draw the image on to the canvas multiple times before it’s displayed.