Defining specific colours for RadialStim and GratingStim

Hi there,

I would actually like to define the colour of the abovementioned visual. functions. But currently, the ‘color’ setting for these functions can only be applied to one of the rings/gratings and the color of the other, the direct opposite. Is there a way that I can specifically control the colour of the second ring/grating?

(ie. If I were to set the color as red, the default opponent color is blue. I would like to make it say, red and green instead.)

Edit: I’ve found the solution for a non-radial stimulus at Creating a grating with a only one color. However, the psychopy.filters.makeGrating function hasn’t got a ‘tex’ setting where I could change it away from the default sin texture. Secondly, I’m still not quite sure how to do the same to a circular radial stimulus?

The gratType parameter has a few options to generate non-sin textures.

You can get an idea of how it works with a radial stimulus by replacing GratingStim with RadialStim in the linked demo code.

blue_radial_grating

For example, try using ori=90 in makeGrating.

Thanks @djmannion . That worked for a squarish grating, which is one thing that I needed. However for the radial stimulus, is filter.makeGrating able to come out with something like this instead?

Yes, just set ori=90 when making the texture that is drawn by a RadialStim.

Or you can get that just with a RadialStim by setting angularCycles=0 and radialCycles=8 (for example) with tex="sqrXsqr".

Oh yes, thanks, I managed to get it to work now!

One last question, from the linked demo code:

replace the blue channel with the grating

blue_grating[…, -1] = grating

I was trying to wrap my head around the massive number of lists within ‘blue_grating’ here and can’t quite figure out how this actually makes the grating blue. If I want to make this red, green or even maroon, what variable here do I have to manipulate to get it to change to the respective colours?

The blue_grating variable is a 256x256x3 array, where the last dimension indexes the red, green, and blue colour channels. The line blue_grating[…, -1] = grating is setting the blue channel (the -1 indexes the last channel) to vary its intensity according to the grating.

To make it be different colours, the RGB space might not be easiest. Instead, you can define your stimulus in HSV space (with the grating in the V channel) and then convert it into RGB. That way, you only need to change the H channel to vary the hue (though other aspects change with hue also).

For example:

import numpy as np

import psychopy.visual
import psychopy.event
import psychopy.colors

win = psychopy.visual.Window()

grating_res = 256

grating = psychopy.visual.filters.makeGrating(res=grating_res, cycles=5.0)

hsv_tex = np.ones((grating_res, grating_res, 3))
# set the value channel to the grating
hsv_tex[..., 2] = (grating + 1) / 2.0

stim = psychopy.visual.RadialStim(
    win=win,
    units="pix",
    size=(grating_res, grating_res)
)

# loop over hues
for angle in range(0, 360, 10):

    hsv_tex[..., 0] = angle

    stim.tex = psychopy.colors.hsv2rgb(hsv_tex)

    stim.draw()

    win.flip()

    psychopy.event.waitKeys()

win.close()

I see, thanks for all these. It seems though, that the colour is dependent on having a black background. Does it have to be that way? (Ie. I can’t have a non-black colour pair like yellow and brown?)

No, it doesn’t have to be that way. You can make the value channel not go all the way to 0 to get yellow-brown. I’d suggest experimenting with the different ways of manipulating hsv_tex - you can make it look pretty much however you want.

import numpy as np

import psychopy.visual
import psychopy.event
import psychopy.colors

win = psychopy.visual.Window()

grating_res = 256

grating = psychopy.visual.filters.makeGrating(res=grating_res, cycles=5.0)

hsv_tex = np.ones((grating_res, grating_res, 3))
hsv_tex[..., 0] = 50.0
hsv_tex[..., 2] = (grating + 1) / 2.0 * 0.5 + 0.5

stim = psychopy.visual.RadialStim(
    win=win,
    units="pix",
    size=(grating_res, grating_res)
)

stim.tex = psychopy.colors.hsv2rgb(hsv_tex)

stim.draw()

win.flip()

psychopy.event.waitKeys()

win.close()

This last solution has to be upgraded for psychopy 3 as follows:

stim.tex = psychopy.tools.colorspacetools.hsv2rgb(hsv_tex)

Else it wont work.

1 Like

Hello,

I am trying to create a custom grating, using a similar method.

However, I am having trouble creating a grating with two colors, e.g., red-green as the post initially mentions. Right now, my patch is red-black.

Here is a snippet from my code (inspired by the solutions here):

import numpy as np

import psychopy.visual
import psychopy.filters
import psychopy.event
import psychopy.colors

from psychopy import core
from psychopy.visual import filters

grating_res = 256

grating1 = psychopy.visual.filters.makeGrating(res=grating_res, gratType = ‘sqr’,phase=0, cycles=2.0)

blue_grating1 = np.ones((grating_res, grating_res, 3))* -1.0 # initialise a ‘black’ texture
blue_grating1[…, 0] = grating1 # replace the red channel with the grating

stim1 = psychopy.visual.GratingStim(
win=win,
tex=blue_grating1,
mask=“circle”,
phase=0,
size=(5, 5)
)

Conversely, could I overlay two gabor patches and make one of the colors transparent, but this seems trickier. As soon as I make one color transparent, for example setting the opacity to 0, the entire patch unsurprisingly disappears. (reference: https://groups.google.com/g/psychopy-users/c/IlhiS-7XMNg).

Please advise, thank you so much!

Hello, how did you determine these values?

I have successfully recreated a grating stimulus with the colors you use, but I don’t understand how to manipulate them to what I need (red-green and blue-yellow).

Ultimately, I hope to keep red (or yellow) a constant luminance and ask the participant to modulate green (or blue) luminance to achieve perceptual isoluminance, but I think I can do this once I know how to manipulate colors using the numpy array.

Thank you so much!

I’m editing this to post my actual code:

import numpy as np
import psychopy.visual
import psychopy.filters
import psychopy.event
import psychopy.colors

from psychopy import core
from psychopy.visual import filters

pres_timer = core.Clock() #define a clock
grating_res = 256

grating1 = psychopy.visual.filters.makeGrating(res=grating_res, gratType = ‘sqr’,phase=0, cycles=2.0,contr=0.0)

#initialise a ‘black’ texture
blue_grating1 = np.ones((grating_res,grating_res,3))
#replace the blue channel with the grating -->actually make grating yellow-brown here.
blue_grating1[…, 0] = 50.0
blue_grating1[…, 2] = (grating1 + 1) / 2.0 * 0.5 + 0.5

stim1 = psychopy.visual.GratingStim(
win=win,
tex=blue_grating1,
mask=“circle”,
phase=0,
size=(5, 5)
)

stim1.tex = psychopy.tools.colorspacetools.hsv2rgb(blue_grating1)