Search code examples
python-2.7mouseeventpsychopy

Mouse selection of images with Psychopy


I have created two stimuli(red and green rectangles) as stimuli in Psychopy. Also, I have enabled mouse movements to four directions. Using the function[mouse.getPressed()] in Psychopy for selecting the stimuli, I am facing some issues. Basically, I want the mouse to move in four directions, and when the mouse reaches red/green rectangle stimuli, I need to select that stimuli and change its color to blue.

Can anyone look into the issue and help me to resolve the same?

Here is my code:

from psychopy import visual, core, event 
import numpy as np


# Create a window.
# For configuring and debugging the code turn off full screen.
fullscr = False
win = visual.Window(
    [1200,1000],
    monitor="testMonitor",
    units="deg",
    fullscr=fullscr
    )

#cursor = visual.Circle(win, radius=0.2)

#cursor = visual.CustomMouse(win,
#    leftLimit=-10, topLimit=10, rightLimit=10, bottomLimit=-10,
#    showLimitBox=True, clickOnUp=True)

pos_zero = (0, 0)
cursor = visual.Rect(
        win=win, 
        size=400,
        pos=pos_zero,
        opacity=0
        )

mouse = event.Mouse(visible=True)


# Sinusoidal control version.
freq_one = 0.5
freq_two = 1.5
# Colors of the rectangles.
#color_zero='black'
color_one = 'red'
color_two = 'green'
# Positions of the rectanges.
pos_one = (-10, 0)
pos_two = (10, 0)


start = core.getTime()
cnt = 0
cursor.pos = mouse.getPos()
print cursor.pos
while cnt<600:
    second = core.getTime() - start

    sin_val_one = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_one))
    sin_val_two = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_two))

#while not mouse.getPressed()[0]:
    # Do something if mouse moved

    for key in event.getKeys():
        if key == 'escape': 
           core.quit()
        elif key == "right":
           cursor.pos = cursor.pos + (2,0)
        elif key =="left":
           cursor.pos = cursor.pos - (2,0) 
        elif key =="up":
           cursor.pos = cursor.pos + (0,2) 
        elif key =="down":
           cursor.pos = cursor.pos - (0,2) 


        #if cursor.pos == pos_one:
        #   mouse.getpressed(rect_one)
        #elif cursor.pos == pos_two:
        #   mouse.getpressed(rect_two)

    mouse.setPos(cursor.pos)  
    mouse.lastPos = cursor.pos  

    rect_one = visual.Rect(
        win=win,
        fillColor=color_one,
        lineColor=color_one, 
        size=15,
        pos=pos_one,
        opacity=sin_val_one
        )
    rect_two = visual.Rect(
        win=win,
        fillColor=color_two,
        lineColor=color_two, 
        size=15,
        pos=pos_two,
        opacity=sin_val_two
        )

#images = [rect_one, rect_two]

#for image in images:
#    if mouse.isPressedIn(image):
#        pressed_shape = shape
#            
#    pressed_image.fillColor = 'blue'
#    pressed_image.draw()
#    print pressed_image.name

    rect_one.draw()
    rect_two.draw()
    cursor.draw()
    win.flip()
    cnt += 1

win.close()

Any help is greatly appreciated. Thanks!


Solution

  • I made several changes and post the updated code below. It's significantly shorter and simpler.

    • Removed everything using mouse. Since you just want something visual to move on key presses, there's no need to invoke the mouse - especially when you actually don't want subjects to use the mouse...

    • Create the colored shapes once, then updating the color during runtime. This is significantly faster, i.e. avoids dropping frames.

    • Changed the cursor size. It was 400 degrees!

    • Removed the line around the rectangles so that only fillColor needs to be changed on overlap.

    • A few other simplifications.

    Here is the code:

    from psychopy import visual, core, event 
    import numpy as np
    
    # Settings
    fullscr = False
    directions = {'left': (-2,0), 'right': (2,0), 'up': (0, 2), 'down': (0, -2)}
    freq_one = 0.5  # # Sinusoidal control
    freq_two = 1.5
    
    # Create a window.
    win = visual.Window([1200,1000], monitor="testMonitor", units="deg", fullscr=fullscr)
    
    # The two rectangles
    rect_one = visual.Rect(win=win, fillColor='red', lineColor=None, size=15, pos=(-10, 0))
    rect_two = visual.Rect(win=win, fillColor='green', lineColor=None, size=15, pos=(10, 0))
    
    # Cursor
    cursor = visual.Circle(win, fillColor='white', radius=0.2)
    
    # Run five trials
    for trial in range(5):
        # Set to initial condition
        rect_one.fillColor = 'red'
        rect_two.fillColor = 'green'
        cursor.pos = (0, 0)
    
        # Start task
        start = core.getTime()
        for frame in range(600):
            # Set rectangle opacities
            second = core.getTime() - start
            rect_one.opacity = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_one))
            rect_two.opacity = 0.5+0.5*np.sin(2 * np.pi * second * float(freq_two))
    
            # Show it
            rect_one.draw()
            rect_two.draw()
            cursor.draw()
            win.flip()
    
            # Get keyboard responses and change color if there is overlap
            for key in event.getKeys():
                if key == 'escape': 
                   core.quit()
                elif key in directions.keys():  # if this is a key corresponding to a direction
                   cursor.pos += directions[key]   # Lookup the pos change in "directions" and add it to current position
                   if cursor.overlaps(rect_one):
                       rect_one.fillColor = 'blue'
                   if cursor.overlaps(rect_two):
                       rect_two.fillColor = 'blue'