Make image appear and disappear on click

OS : Win10
PsychoPy version : Standalone PsychoPy 2021.1.4 for 64bit Windows (using Python3.6)
Standard Standalone? (y/n) yes

What are you trying to achieve?:
The task needs a number of bars to appear on click (i.e. becoming visible, changing from background none colour to white) and disappear (from white to none color), as many times as the subject wants. All the bars are actually based on a single png image of a white bar used repeatedly.
I could easily code the initial transition from none to white color (the bar appearing); I cannot make the switch-back transition happen, from white to none color (the bar disappearing).

What did you try to make it work?:
I am aware that there are multiple previous instances of the same request here on the forum. They are all pretty similar and similarly solved. I tried to adapt every single solution reported in those cases: none of them works for me. I tried working with polygons rather than an image, and it still doesn’t work.
I have set the appearance parameters such as Foreground Color of the image to constant in order to not interfere with the coded commands. I have tried setting the initial color to $‘none’ or leaving it unspecified (it doesn’t seem to have any effect).

What specifically went wrong when you tried that?:
The bars appear (turn from none to white) but never switch back to none (disappear) upon following clicks. Also, I always get the following warning after closing the task:
FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
if clicked_bar.color == ‘white’:

Here’s an example of my adaptation from:
https://discourse.psychopy.org/t/how-to-make-polygons-change-color-when-pressed/19282

Begin routine

bars = [bar_1, bar_2, bar_3, bar_4, bar_5, bar_6, bar_7, bar_8]

Each Frame

for clicked_bar in bars:
    if mouse.isPressedIn(clicked_bar):
        if clicked_bar.color  == 'white':
            clicked_bar.color = 'none'
        else:
            clicked_bar.color  = 'white'

What am I doing wrong?

Thank you for your help

Try referring to None with a capital N and no quotes.

Thank you for the suggestion. It still doesn’t work properly.
I am convinced that the problem is with the elementwise comparison failing, since it successfully interprets

else:
            clicked_bar.color  = 'white'

and makes the bars appear in white at the first click. It has problems with checking for identity in the first line of:

if clicked_bar.color  == 'white':
            clicked_bar.color = 'none'

and does not make the transition from white to none. It must be something related to the format of the color coding. If I try defining colors with the rgb code arrays instead ([0,0,0]; [1,1,1]) the output is:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Can you use a different comparison? How do you know which element is going to be white?

They all start on background (none) color, therefore invisible to the subject. At first click the item should appear, turning to white (which happens perfectly well). However, I would like the subject to be able to change his mind and “turn off” any item by clicking on it again (reversing to none color, thus disappearing, which I cannot make happen). In other words, each image should cycle between appearing and disappearing at following clicks.
I tried using is as comparison method instead of ==; still doesn’t work. I tried phrasing it differently to work around possible issues with color definition and changing to None instead of ‘none’.
Begin routine:

bars = [bar_1, bar_2, bar_3, bar_4, bar_5, bar_6, bar_7, bar_8]
clicked = False 

Each frame:

for clicked_bar in bars:
    if mouse.isPressedIn(clicked_bar) and clicked is False:
        clicked_bar.color = 'white'
        clicked = True
    if mouse.isPressedIn(clicked_bar) and clicked is True:
        clicked_bar.color = None
        clicked = False

End routine:

clicked = False 

It now behaves even weirder, in that the items appear sporadically at click, only a small number of times, if I keep clicking throughout the routine. When they do, they remain perfectly visible and stable and even disappear at the next click.

I really don’t know what’s going on anymore.

Personally I would use the opacity rather than the colour to make something appear and disappear.

…or set .setAutoDraw(False)

…or move the position to off screen.

The ultimate goal would be to put the task on Pavlovia. I went with the color method from the beginning because I read reports from different users having issues with the opacity method in the online version. I haven’t tried the move off screen method

I think that the opacity issue online is related to text stimuli.

1 Like

Hi there,

I tend to add “clicked” as an attribute to the clickable object rather than as a single boolean value e.g.

for clicked_bar in bars:
    if mouse.isPressedIn(clicked_bar) and not clicked_bar.clicked:
        clicked_bar.pos = [-1000, 0]# position offscreen if the goal is to disappear
       clicked_bar.clicked = True

in the end routine you would need:

for bar in bars:
    bar.clicked = False

Also I would recommend using position if you want to make something disappear as you are correct that there was an issue relating to opacity of polygons online (although that should be fixed in more recent versions BUG: cannot set independant opacity for multiple polygons ¡ Issue #275 ¡ psychopy/psychojs ¡ GitHub).

Hope this helps,
Becca

1 Like

Thank you wakecarter and Becca for your feedback. I gave some thought to the position method and that wouldn’t work either. In the initial state of my routine the bars would need to be invisible, therefore offscreen and out of reach, and consistently so until clicked. I cannot make their properties or position change on click, nor programme a cycle between settings, if there’s a state in which they are out of reach.

I went for the opacity method eventually and I can confirm that it works perfectly in the online version as well. I should have just tried it in the first place.

Many thanks for your help.

1 Like

Hi,
I encountered the same problem:
FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
if clicked_bar.color == ‘white’:

I solved it like this (in my example, I need the gray button to turn to coral when clicked, then turn back to gray when clicked again, and switch between the two colors):

  1. use PsychoPy RGB code preceded by dollar sign (e.g., $[0.0039, 0.0039, 0.0039]) instead of color name (e.g., gray) to set the property of “Fill Color” under the tab of “Appearance” for the clickable object;
    p.s.
    PsychoPy RGB code of gray: [0.0039, 0.0039, 0.0039]
    PsychoPy RGB code of coral: [1.0000, -0.0039, -0.3725]
  2. write the code in this way:
    if clicked_button.fillColor[0] == 0.0039:
    clicked_button.fillColor[0] = 1.0000
    clicked_button.fillColor[1] = -0.0039
    clicked_button.fillColor[2] = -0.3725
    elif clicked_button.fillColor[0] == 1.0000:
    clicked_button.fillColor[0] = 0.0039
    clicked_button.fillColor[1] = 0.0039
    clicked_button.fillColor[2] = 0.0039

I now can switch color of the button back and forth.
hope this helps, good luck