Displaying stimulus for a limited amount of time before disappearing

OS (e.g. Win10): Mac OS Sierra 10.12.6
PsychoPy version (e.g. 1.84.x): Psychopy 3 2020.2.10
Standard Standalone? (y/n) yes
What are you trying to achieve?: I would like to display two pictures side by side (image x and image y, for 5 seconds) and, upon pressing one of the two suggested keys (x or y), enlarging one of the two pictures for 500ms before going back to the two pictures. Pressing the other key during the 500ms period of time where image x appear should break the displaying of image x to enlarge image y for a new 500ms period of time.
So to clarify: image x and image y are shown on the screen for 5 seconds. Pressing X should cause image x to be enlarged for 500ms before going back to image x and image y presented side by side (for the remaining time of the 5 seconds). Pressing Y should cause image Y to be enlarged for 500ms, and pressing X while image y is displayed should disrupt the displaying if image y to display image x for 500ms before going back to the initial setting for the remaining time of the initial 5 seconds. If a participant was to keep pressing repeatedly X, then the image x should be displayed for the whole 5 seconds.

What did you try to make it work?:
I tried to set a routine with four images: the two images side by side and then the two same images enlarged but with opacity set to ā€œopacleftā€ and ā€œopacrightā€ set in the begin routine tab to 0.
I added a code component for setting opacity of the selected image to 1 upon pressing the correct key. I tried to add a timer for setting back the opacity to 0 after 0.5 seconds.

Here is the code I tried in the ā€œeach frameā€ tab:

if key_resp.keys:
    if key_resp.keys == 'a':
        opacleft =1
        opacright=0
        timer = core.CountdownTimer(0.5)
        if timer.getTime() == 0:
            opacleft = 0
    elif key_resp.keys == 'p':
        opacright = 1
        opacleft=0
        timer = core.CountdownTimer(0.5)
        if timer.getTime() == 0:
            opacright = 0

What specifically went wrong when you tried that?:
it kinda works, but the opacity parameter is not set back to 0 after the 0.5 seconds have passedā€¦ So the problem is with the timer I guess. I tried several other things with the timer but it always failedā€¦

Any help would be much appreciated :slight_smile:
Do not hesitate if you need further information.

Cheers,
Jean

P.S.: Ultimately, this experiment will be an online experiment. First I am trying to make it work locally but, in the end, I will have to convert everything to JS. So that might be something worth knowing if you have any tips :slight_smile:

I think is not changing back because the code checks the timer well before 0.5 seconds has elapsed. Try this way:

#in the begin routine tab

opacClock = core.Clock()

# in the each frame tab
if key_resp.keys:
    opacClock.reset() #resets the clock back to 0
    if key_resp.keys == 'a':
        opacleft =1
        opacright=0
    elif key_resp.keys == 'p':
        opacright = 1
        opacleft=0

if opacClock.getTime() >= 0.5: #after 0.5 seconds
   opacleft =0
   opacright =0 #both opacity are set to 0

For the JS conversion look at this: PsychoPy Python to Javascript crib sheet

Also, changing the opacity online seems to cause a lot of problem, so if you can try changing the color instead (if you make the fillcolor = to the background color the stimulus disappear), and if you canā€™t try searching the forum for a solution.

tandy

The other trick I use to make something invisible is to change the position so itā€™s off screen (e.g. a y coordinate of 2 in height units)

1 Like

Hi!

Thanks for you response!
So, Iā€™ve tried it and the same result appears: the image does not disappear.

Thanks a lot for your advices regarding Pavlovia :slight_smile: Itā€™ll help me anticipate future difficulties.

Hi!
That might be a good trick if opacity does not work as expected online! Iā€™ll have a look into this!

Thanks a lot :slight_smile:

Instead of setting the opacity every frame with a variable I would recommend that the opacity is set to 0 and constant and then set in code with e.g. left_object.setOpacity(1)

Same results. The images appear as expected when a key is pressed, but then fail to disappear after 0.5s. I guess the problem really is located in the code timing the moment of the disappearance.

This is so big brain

I think the issue you are having is that once a key is pressed, your keypress conditional is always true, and therefore the condition to change the images back will not be satisfied. Also, rather than using 4 or different sizes and changing the opacity. you can just change the size of the image. You can also use the trial clock (t) to time your stimuli, rather than creating a new timer. Here is a version of code you can use, which relies on a little keyboard hack requiring you to wipe all stored keypresses that are stored in the background. In the relevant tabs (see code comments), add the Python code, which will auto-translate to JS. Note, the keyboard will not automatically store the keypress data in the datafile using this code, so if you want them you will have to manually store keypresses.

# Begin Routine
keyTime = 0
keyPressed = False
timeDelay = 5

# Each Frame
if key_resp.keys and len(key_resp.keys) > 0:
    # Set time condition
    keyTime = t + timeDelay 
    keyPressed = True
   
    if key_resp.keys == "a":
        imageLeft.size = [.5, .5]  # Enlarge left image
        imageRight.size = [0, 0]   # Shrink right image
    if key_resp.keys == "p":
        imageRight.size = [.5, .5]
        imageLeft.size = [0, 0]

    # Reset keyboard
    _key_resp_allKeys = []
    key_resp.keys = []
    key_resp.rt = []
    key_resp.clearEvents()

# Check time and change images back to original size
if t > keyTime and keyPressed:
    keyPressed = False
    imageLeft.size = [0.25, 0.25]
    imageRight.size = [0.25, 0.25]

Hi!

Thanks for your response!
So Iā€™ve tried it, and your codes do enlarge and shrink the imagesā€¦ But once again, it does not turn back to normal sizesā€¦ So the images stay enlarged for the whole experiment duration, and I can enlarge and shrink the image I want repeatedly by pressing ā€œaā€ and ā€œpā€ā€¦ But it will never turn back to the original sizes.

So I think it has something to do with the timer once again (the 'if t > keytime" part namely).

It should work, here is an example (use left and right direction keys rather than a and p)

https://run.pavlovia.org/dvbridges/imagecolor/html/

If not, there must be some differences that are causing the issue.

1 Like

My bad! I forgot to change some references in the last part of the codes (that referenced the images set to opacity = 0, so only these two useless images must have taken back a normal size, but being transparent I could not see theseā€¦)
Many thanks!!
The ā€œimage sizeā€ solution might also be easier to implement online than the ā€œopacityā€ one!

Iā€™m pretty sure I can find an answer online, but since you mentioned this issue, what would be the code lines I should use to store the key pressed? (in the case you have it in mind and in the case it does not require you to check, because Iā€™m sure this info is quite easy to find on the forum)

Once again, many thanks to @tandy @wakecarter and @dvbridges for your help! :slight_smile:

Great. It depends what you want to store. Do you want all keys pressed, first or last key pressed? Do you want the RTs of the keypresses too?

All keys pressed. I have to know for each trials how many times the participant pressed the ā€œaā€ and the ā€œpā€ keys.

Also, I remarked that between each trial (5s long), if participants clicked one of the image (just before the end of the trial), it will not go back to the original sizes. So I slightly modified your code checking if ā€˜t > keyTimeā€™ by deleting the condition that ā€˜keyPressedā€™ should exist like this:

if t > keyTime:
    keyPressed = False
    imageLeft.size = [0.25, 0.25]
    imageRight.size = [0.25, 0.25]

And now the images are correctly reset at the end of the routine. I think the problem was that the condition was not necessarily met: time had elapsed, but a keypress in the new trial was not ensured (because keyPressed is reset to False at the beginning of the new trial), so it did not need to go back to the original sizes. A priori it works when deleting this last condition, but I hope it does not create problems I donā€™t see.

To store all key presses for each trial, you can create a list and append all the key presses before they are deleted, then save that list to the data file. In your keyboard, you will want to only allow keys a and p to be valid keys, and then only those keypresses will be recorded.

# Begin Routine
keysPressed = []
KeyRTs = []

# Each Frame

if key_resp.keys and len(key_resp.keys) > 0:
    # Set time condition
        #...code
    if key_resp.keys == "a":
        #...code
    if key_resp.keys == "p":
        #...code
    keysPressed.append(key_resp.keys)
    keyRTs.append(key_resp.rt)
#...code

# End Routine
thisExp.addData("keysPressed", keysPressed)
thisExp.addData("keyRTs", keyRTs)

There will be an issue with the translation as you are using append, but check the crib sheet for the fix - check the code_JS heading for instructions creating a JS only code component, and add Array.prototype.append = [].push; to the Begin Experiment JS code tab .

1 Like

Thanks for your answer!
I used the crib sheet to fix the append command translation to JS. However, for reasons unknown, nothing is stored in the keysPressed and keysRTs (For each trials I get empty lists in the outputted files) [note that when run locally from psychopy, keypresses are correctly recorded so your codes work perfectly in Python!].

However, I think I can figure the problem out with a bit of head-scratching. The topicā€™s subject has been solved so I guess it might be best for me to keep working on it and, should this issue be more complicated to me than it appears, search for topics on this issue or open a new topic if I donā€™t find any.

Thanks again for your precious help! :slight_smile:

Cheers,
Jean