psychopy.org | Reference | Downloads | Github

Tracking mouse location on perimeter of a circle/show angle between mouse location and 0 degrees

#1

Hi,

I’m currently attempting to build a time estimation task using the builder but have run into a bit of difficulty. This is my first attempt at building an experiment in PsychoPy so apologies in advance if what I’m asking is extremely basic!

To give an overview of the task:

Participants will be trained to associate a circle “filling in” with the passing of time. I do this by showing them images of circle segments in black in quick succession e.g., 1/20 of the circle every 40ms. This part is straightforward.

My problem is that for the experimental phase of the task I want to show participants two events and for them to estimate the time between them by indicating how much of circle could have filled-in in the interval between the two events. Essentially, I want to show them event A, then event B and then present them with a circle on the screen (black outline, white fill) and ask them, “How much of the circle could have filled-in in the time between those two events”. I want them to be able to click on a part of the circle perimeter and for this to be shown as a proportion of the circle filled in in black.

From reading various forum posts I’ve gathered that what I should do is draw a circle (black outline on white background) and then track the location of the participants’ mouse on the perimeter of the circle by showing a black line from the center of the circle to the mouse position on the perimeter.

My questions are:

  1. is this possible to do in Builder?
  2. Is it possible to fill in the proportion of the circle between 0 degrees and their mouse location in black while leaving the fill of the rest of the circle in white?

Thanks in advance

#2

I have a solution, it involves using triangles to create segments in your circle, that change color when clicked. See segments.psyexp (19.2 KB)

In this example, there are four segments to a circle, and when one of the segments is clicked, they are all colored black up to and including the clicked segment. It uses triangle polygons for the segments, an aperture and and an actual unfilled circle for the outline. The code in the code component to make this happen is easy to follow:

# Begin Experiment
segments = [polygon, polygon_2, polygon_3, polygon_4]  # Create list of your triangle segments

# Begin Routine
segmentIndex = None  # Reset segment index, and segment colors on each trial
for segment in segments:
    segment.fillColor = 'grey'

# Each Frame
for segment in segments:  # Check if a segment was clicked, and find the index of that segment
    if mouse.isPressedIn(segment) and segmentIndex is None:
        segmentIndex = segments.index(segment)
        
if segmentIndex is not None:  # If segment was clicked, color in relevant segs from list of segments
    for index, segment in enumerate(segments):
        if index <=segmentIndex:
            segment.fillColor = 'black'

If you need more segments, you need to add more polygons, sized and positioned correctly. You then need to add the new polygons to the segments list in the Begin Experiment tab of the code component.

1 Like
#3

Some of this might be able to be done more directly by controlling the visibleWedge of a RadialStim:

https://www.psychopy.org/api/visual/radialstim.html

e.g.

Only if your screen refresh rate is some integer multiple of 25 Hz… This wouldn’t be possible on a standard 60 Hz LCD display, for example.

1 Like
#4

This was really helpful! I managed to get it working with 20 segments. Is there a way that participants could change their mind, for example, could they press once, think that the segment looks too small, press again, and then press enter to confirm their final choice?

#5

Yes, you just need to modify the code (see also segments.psyexp (19.4 KB)):

# Begin Routine
segmentIndex = None
for segment in segments:
    segment.fillColor = 'grey'
resetSegments = False # Flag for resetting segments on clicks

# Each Frame
for segment in segments:
    if mouse.isPressedIn(segment):
        segmentIndex = segments.index(segment)
        resetSegments = True  # On click, reset the segments

if resetSegments:  # reset segment color on click,  ready to be filled again
    for segment in segments:
        segment.fillColor = 'grey'
    resetSegments = False

if segmentIndex is not None:
    for index, segment in enumerate(segments):
        if index <=segmentIndex:
            segment.fillColor = 'black'

What Michael has shown draws what you want accurate to a degree, but requires maths to work out the angle between two points of the circle to be filled, which would then be used to set the visibleWedge parameter of the RadialStim E.g., radial.psyexp (6.7 KB). The numpy function that you use to calculate the internal angle is arctan2.

1 Like