psychopy.org | Reference | Downloads | Github

Changing Colors of tiles in a grid PsychoPy Help!


#1

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!


#2

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 location variables.

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[0] * x,
                    check_size[1] * y))

stim = visual.ElementArrayStim(win,
                               xys=xys,
                               fieldPos=loc,
                               colors=colors,
                               nElements=num_check**2,
                               elementMask=None,
                               elementTex=None,
                               sizes=(check_size[0],
                                      check_size[1]))

stim.size = (check_size[0] * num_check,
             check_size[1] * num_check)

for i in range(60):
    stim.draw()
    win.flip()

#3

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?


#4

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?


#5

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.


#6

Thank you so much for the help! This my grid currently which is exactly what I wanted!


#7

Also what is num_check and check_size, do I adjust these to make the squares smaller/larger?


#8

Exactly! The 4 parameters you can adjust are num_check, check_size, location, and 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 colors line:

np.random.seed(0), or any other number of your choice.


#9

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!


#10

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[0] * num_check[1]),)*3, -1)

# array of sizes for each element
xys = []
# populate xys
low_x, high_x = num_check[0] // -2, num_check[0] // 2
low_y, high_y = num_check[1] // -2, num_check[1] // 2

for y in range(low_y, high_y):
    for x in range(low_x, high_x):
        xys.append((check_size[0] * x,
                    check_size[1] * y))

stim = visual.ElementArrayStim(win,
                               xys=xys,
                               fieldPos=loc,
                               colors=colors,
                               nElements=num_check[0] * num_check[1],
                               elementMask=None,
                               elementTex=None,
                               sizes=(check_size[0],
                                      check_size[1]))

stim.size = (check_size[0] * num_check[0],
             check_size[1] * num_check[1])

for i in range(120):
    stim.draw()
    win.flip()