How to make polygons change color when pressed

Hi! I am new to Psychopy. I am creating an updating task in which participants have to click with the mouse on polygons. I want them to change color when pressed. How can I do it by using the Builder view? Thank you so much:)

Hi There,

You want to use a code component. In the begin routine tab list your polygons:

polygons = [polygon, polygon_1]

then on every frame check if the mouse is pressed in the polygon:


for thisPolygon in polygons:
    if mouse.isPressedIn(thisPolygon):
        thisPolygon.color = 'red'

Here is a demo file. polyChangeCol.psyexp (10.9 KB)

Hope this helps,
Becca

PS. I don’t know if you want to take that online, but just incase, it will need a slight edit in the code component (change code type to ‘both’, on the right hand side change color to fillColor, since ‘color’ is ‘fillColor’ in psychoJS JSDoc: Class: Polygon)

Thank you so much, it works!

And if I want to let participants press againg on the polygon to make it return to the previous color? Is it possible?

Sure, you just need to add another “if” statement (beware on indentation!), for example:

for thisPolygon in polygons:
    if mouse.isPressedIn(thisPolygon):
		if thisPolygon.color == 'red':
			thisPolygon.color = 'blue'
		else:
			thisPolygon.color = 'red'
1 Like

It doesn’t work…

Hi There,

I think the initial reason this wouldn’t work is because the first ‘if’ statement would need a double == to test for equality (rather than assign a variable). (i.e. if thisPolygon.color == white: )

However, this is a little tricker because the ‘isPressedIn’ method will check for mouse presses every time your screen refreshes (16.66 ms on a 60Hz monitor). So, if the participant continues to hold the mouse the polygon will appear to flicker (as it transitions from one colour to the other very quickly).

A work around for this it to add a time window in which you will register ‘new’ clicks.

So, in your ‘begin routine’ you would use something like:


polygons = [polygon, polygon_2]

bufferTime=.2
clickClock=core.Clock()
lastClickTime = 0

Then in your each frame you would use something like:


for thisPolygon in polygons:
    if mouse.isPressedIn(thisPolygon):
        thisClickTime = clickClock.getTime()
        if (thisClickTime - lastClickTime) > bufferTime:
            if thisPolygon.fillColor =='red':
                thisPolygon.fillColor = 'white'
            else:
                thisPolygon.fillColor = 'red'
        lastClickTime = thisClickTime

This will only register clicks seperated by 200ms as ‘new’ clicks, and avoid the flicker effect. Here is an updated demo file polyChangeCol.psyexp (12.1 KB)

Hope this helps,
Becca

PS. I noticed that the color attribute has actually been changed to fillColor in the recent release (probably to be consistent with PsychoJS - so updated accordingly)

2 Likes

It works perfectly! Thank you so much:)

Hi Becca! This Code works perfectly in Psychopy but not in Pavlovia.
Polygons don’t change color on click and they don’t return to the previous color if I double click them.
Moreover, it is written that I have to define thisClickTime.

Any advise?

Hi Rachele,

For this ‘thisClickTime’ error you will just need to add that to the begin tab to initialize the variable on the JS side, e.g.:

thisClickTime=0

There are a few extra tweaks needed to get this online. So here is the demo I sent functioning online https://pavlovia.org/lpxrh6/change-color-on-click.

The main principles of this are as follows, change code type to ‘both’ and then make the following changes to the right hand side of the code:

  1. core.clock must be util.clock
  2. instead of thisPolygon.fillColor ==='red' use thisPolygon.fillColor['_rgb'][2] === 0 this is fetching the rgb values of the color to check if the blue channel is ‘1’ or ‘0’ (white = [1, 1, 1] red = [1, 0, 0]
  3. when assigning a new color, use thisPolygon.fillColor = new util.Color("white") instead of thisPolygon.fillColor = 'white'

Hope this helps,

Becca

1 Like

I don’t know why it doesn’t work. I put the same codes as in the demo… :frowning:

what error do you get?

Hi Becca,
I think this is a silly question but somehow I can’t figure out how to exhange the color red with blue in this code:

if ((thisPolygon.fillColor[’_rgb’][2] === 0)) {
thisPolygon.fillColor = new util.Color(‘white’);
} else {
thisPolygon.fillColor = new util.Color(‘red’);
}

So I would like the polygon to change to blue (now red) when clicked and back to white when clicked again.

Thank you!!

Hi There, did you figure this out? it would just be replacing the ‘red’ like this:


if ((thisPolygon.fillColor[’_rgb’][2] === 0)) {
thisPolygon.fillColor = new util.Color(‘white’);
} else {
thisPolygon.fillColor = new util.Color(‘blue’);
}

My problem is very similar to this one. I cannot make the thing work though. Would you look at it and tell me what you think? Thank you very much.
https://discourse.psychopy.org/t/make-image-appear-and-disappear-on-click/23007/1

Hi everyone,

I used the above mentioned code for a similar study that I am programming.
I was just wondering, using the above created code, is there a way to store the two colors of the Polygons displayed in the datafile as well, a column that contains the two colors of the left and right polygon (polygon and polygon_2) such as [white, black]?

Thanks,
Caro

Yes! You can use myLoopName.addData() in a :code: Code component to store data, the data to store would be:

[myPolygon1.fillColor, myPolygon2.fillColor]

Although, this will store it in whatever colour space you’re using. So, for example, "black" might be [-1, -1, -1] if your colour space is rgb. To get it specifically as named colours, assuming all the colours used have names, you can do:

[myPolygon1._fillColor.named, myPolygon2._fillColor.named]

Hi everyone,
even though these messages are old, I want to continue this old conversation.
I used the code that was posted here in this thread for an experiment, where observers had to change colours of polygons and it worked smoothly. I ran this on PsychoPy 2020.2.4 on various computer with both, OSX and Windows.

However, none of that code works on newer PsychoPy versions.
In the 2021.2.3 version, the colours change after the first click, but never again when clicking to return to the previous colour.
In the 2022.1.4 version, PsychoPy immediately crashes when running the code.
Note, that I did the with my own experiment code, but also with Becca’s code that she posted, that was accepted as a solution.

What has changed in the 2022.1.4 that even this simple demo code cause PsychoPy to crash? And even in the 2021.2.3 version it does not change the colour back to its original colour, even though Becca added that to the code.

Cheers, Caro

Was there any error message in the Runner window when the experiment crashed? Or, if you were running online, was there any error message which popped up?

Hello all,

The solutions posted above did not work for me. I’m running Psychopy v2022.2.2. My original code was the following:

for thisPolygon in clickables:
    if mouse_response.isPressedIn(thisPolygon):
        if thisPolygon.fillColor == 'white':
            thisPolygon.fillColor = 'blue'
        else:
            thisPolygon.fillColor = 'white'

For some reason, psychopy failed to enter the second if statement with this code. As a result, none of my polygons would turn blue when I clicked them.

I found this solution from NatYeung. Nat replaced the second if statement with an equality check on the RGB values. Since my polygons are originally white, I checked whether the first RGB value is 1. This solution, as presented below, works for me. Note I didn’t incorporate Becca’s solution to the flickering issue yet. I’m not totally sure why the first solution doesn’t work, but hope this helps anyone who runs into a similar issue.

for thisPolygon in clickables:
    if mouse_response.isPressedIn(thisPolygon):
        if thisPolygon.fillColor[0] == 1.0:
            thisPolygon.fillColor = 'blue'
        else:
            thisPolygon.fillColor = 'white'