I wonder what’s the best way to display multiple images on the screen simultaneously. (Preferably with only one image component)
I have 100 small images to display at the same time, with their file names in a condition file. The image position varies, and is calculated/randomized in a code component.
My guess is that some custom codes are needed so that the screen flips only after all images are placed on the screen, instead of flipping 100 times.
If you added 100 image Components, I believe it would only flip the screen once, as the flip command happens at the end of the frame loop rather than after each component. I can see why you wouldn’t want to add all those components though…
What you could do is have all the file names in an excel cell separated by a delimeter (such as a comma), then use a Variable component to split them apart into a list. For example, if your excel sheet looked like this:
You could create a Variable component with the value:
$ImageFile.split(",")
This means the Variable, let’s call it imlist, will be a list of all the filenames there, as it splits the cell value at every comma.
The challenge then is creating all the Image components - but you could create one in Builder, then in a Code component you could make 100 copies using .copy() and set the image value of each to the corresponding image file, then store them in a list, something like:
for i in range(100):
images[i] = MyImage.copy()
images[i].image = imlist[i]
You’d then have to add code to draw each image rather than just draw the original, but if you give this first bit a go and let me know how you get on I can then help you further.
I got a bit lost starting at copying the component 100 times. What is MyImage in your example? I also wasn’t sure how you would use images[i] when you actually draw them. Some elaboration would be very helpful.
Thanks.
MyImage in this case is your placeholder Image component in Builder view, so when you say MyImage.copy() what you’re saying is “I’ve made this blank Image component in Builder, now make a copy of it”.
images will therefore be a list of Image objects, so you can do anything to images[i] that you would do to MyImage, if that makes sense? I think drawing it should be as simple as adding to the Each Frame tab:
for i in range(100):
images[i].draw()
As you’re essentially saying “for each image in images, perform it’s draw command”
Oops, my mistake! Some objects in Python have a copy method, I thought ImageStim did too… So instead you’ll need to add:
import copy
to the Begin Experiment tab, then rather than MyImage.copy() use copy.copy(MyImage) - so essentially you’re importing a method to copy it rather than using its own method. Does the same thing though!
Ok, it makes sense. Now there’s one last issue, I believe. When we copy the image component, we are copying an “ImageStim” object in PsychoPy. It seems though the indexing is having a problem -
for i in range(3):
images[i] = copy.copy(imageSample)
images[i].image = imList[i]
IndexError: list assignment index out of range
Another similar error - 'ImageStim' object does not support indexing
When I tried this method with only one image (so no indexing), it worked fine.
Oh yes, of course I should do it this way. Silly question.
Now the images are drawn on screen properly. Glad that I don’t need to create 100 components in the builder.
Is this in norm/height units? If the image is 0.9x0.9 and there’s a gap of 0.1 between it and the next one, the next one would likely be off the screen
No, the spatial units are from the exp settings and I can actually see the images for a very short time and then it ends with only showing the last image. My impression is that for every frame it changes which images is shown but it is not showing all images. I am not really sure if that is possible and how to change that.
Hi, this is the current version of my experiment. What I actaully want to archieve is to have a 5x5 grid of grey images and change them on a mouse click.
I think the problem is probably with using copy - copy.copy is only a surface level copy, so it probably still keeps the same stuff underneath, meaning when you set the position it sets it for all copies. Instead I’d recommend just initialising a new image with the relevant parameters: