I am try to create a matrix of squares and draw them onto a window in PsychoPy. I have accomplished drawing the grid using the visual.Rect and saving the window onto a visual.BufferedImage, then drawing that. I want to now change the colors of the tiles in the grid to simulate stimuli results. I know that this can be done using visual.GratingStim, but I cannot find any examples of either how to create a grid like structure using GratingStim or examples of GratingStim working with BufferedImage. If anyone has an experience of resources please let me know!
To make a grid, I like to use the
visual.ElementArrayStim, I feel I get more flexibility. Below is an example of how I do that. You can set the colors and the position of the grid by editing the
colors or the
from psychopy import visual import numpy as np win = visual.Window(units='pix') num_check = 50 check_size = [10, 10] location = [0, 0] # generate loc array loc = np.array(location) + np.array(check_size) // 2 # array of rgbs for each element (2D) colors = np.random.random((num_check ** 2, 3)) # array of coordinates for each element xys =  # populate xys low, high = num_check // -2, num_check // 2 for y in range(low, high): for x in range(low, high): xys.append((check_size * x, check_size * y)) stim = visual.ElementArrayStim(win, xys=xys, fieldPos=loc, colors=colors, nElements=num_check**2, elementMask=None, elementTex=None, sizes=(check_size, check_size)) stim.size = (check_size * num_check, check_size * num_check) for i in range(60): stim.draw() win.flip()
Thank you so much! This was very helpful! Do you know if this is compatible if i want to use a timestamp when changing the colors of the tiles while the GUI is open?
And if I want the tiles to all be colored in a gray scale, how should I do that instead of using the random that is there?
I’m not familiar with the GUI unfortunately, I only use the coder side of Psychopy. To make a grayscale checkerboard, you can try replacing
color with something like this:
colors = np.stack((np.random.random(num_check ** 2),)*3, -1)
Instead of randomizing the RGB values for each tile, this just picks a single value for each tile and then “stacks” them to replicate the value into the RGB values.
Also what is num_check and check_size, do I adjust these to make the squares smaller/larger?
Exactly! The 4 parameters you can adjust are
colors. That should change, respectively, the number of checks in a side of the grid, the size of the checks, where the grid is positioned, and the colors of each check.
Also, if you want to ensure that your random grayscale grid is repeatable, you should seed the random generator. You can do this by adding the following before the
np.random.seed(0), or any other number of your choice.
I am trying to make the grid a 3X6 so I set num_check to be equal to 18 and check_size to 10,10 and I am getting a large amount of squares in a small grid. Do you have any solution to this? Also thank you so much for your help!
To do different number of checks along each axis, it requires a few changes.
num_check needs to be an iterable. I’ve made the changes in the code below.
from psychopy import visual import numpy as np win = visual.Window(units='pix') # x, y coordinates num_check = [3, 6] check_size = [50, 50] location = [0, 0] # generate loc array loc = np.array(location) + np.array(check_size) // 2 # array of rgbs for each element (2D) colors = np.stack((np.random.random(num_check * num_check),)*3, -1) # array of sizes for each element xys =  # populate xys low_x, high_x = num_check // -2, num_check // 2 low_y, high_y = num_check // -2, num_check // 2 for y in range(low_y, high_y): for x in range(low_x, high_x): xys.append((check_size * x, check_size * y)) stim = visual.ElementArrayStim(win, xys=xys, fieldPos=loc, colors=colors, nElements=num_check * num_check, elementMask=None, elementTex=None, sizes=(check_size, check_size)) stim.size = (check_size * num_check, check_size * num_check) for i in range(120): stim.draw() win.flip()
Hi, may I ask what decides the number in the range()?
for i in range(120): stim.draw() win.flip()
I tried to figure it out, but failed. I used the code and the array is not drawn in the center, I’m trying to debug it and wonder this could be the cause?
Thank you a lot!
The number in range just determines for how many frames the stimulus will be drawn. In the case, on a 60 hz monitor, 120 frames will mean the stimulus is drawn for 2 seconds.
Thank you so much