How to "Easily" Add 32 Response Boxes

OS (e.g. MacOS):
PsychoPy version (e.g. 2020.2.5):
Standard Standalone? (y)
What are you trying to achieve?:

Trying to make a routine for a response screen with 32 response boxes.

What did you try to make it work?:

Have started adding the stimuli, but mapping out the size and positioning of each response box is rather cumbersome.

What specifically went wrong when you tried that?:
No specific error, looking for best practices.

Hello all,

I am currently building an experiment where the participant makes there response by clicking a box on screen. Easy enough! The catch being there are thirty-two possible responses. Pictured below is what I am trying to create

I know this is simply adding the response boxes to the routine. However does anyone have any suggestions on how to easily format the sizing and position? Trying the numbers by trial and error is proving quite tiresome!

Thanks for any advice.

You could create them in code and that way, you only need to alter a few parameters rather than the values for every stimulus individually. e.g. insert a code component (from the “custom” component panel) and in either its “begin experiment” or “begin routine” tab, put something like this:

# specify top-left corners of each row of blocks:
corners = [[-0.1, 0.05],   [-0.1, 0.025], [0.05, 0.05],   [0.05, 0.025],
           [-0.1, -0.025], [-0.1, -0.05], [0.05, -0.025], [0.05, -0.05]]

# set the colours in the same order:
colours = ['blue', 'blue', 'red', 'red', 'green', 'green', 'white', 'white']
text_colours = ['white'] * 6 + ['black'] * 2

# number labels:
number_lists = [[1, 2, 3, 4], [5, 6, 7, 8]]

# populate the list of stimuli that will get drawn on each frame:
stimuli = []

for corner_number, corner in enumerate(corners):
    if corner_number % 2 == 0: # upper row (1-4)
        number_list = number_lists[0]
    else:
        number_list = number_lists[1] # lower row (5-8)
        
    # create the boxes and matching labels:
    for i, number in enumerate(number_list):
       stimuli.append(visual.Rect(win, 
                      size = [0.02, 0.02], 
                      pos = [corner[0] + i * 0.03, corner[1]],
                      lineColor = None,
                      fillColor = colours[corner_number],
                      name = f'{colours[corner_number]}_{number}')) 
       stimuli.append(visual.TextStim(win, 
                      text = str(number),
                      height = 0.022,
                      color = text_colours[corner_number],
                      pos = [corner[0] + i * 0.03, corner[1]])) 

and then to make the stimuli appear, simply put this in the “each frame” tab:

for stimulus in stimuli:
    stimulus.draw()

Adjust the numbers as required to get the layout and shape you want (these numbers are set assuming that “height” units have been applied). You might prefer to work with pixels, degrees, etc.

The code above is not very elegant and no doubt there would be more parsimonious ways to achieve it if some more thought was applied.

I just edited to add a name for each rect stimulus so you can tell which one was clicked, but have not tested that.

Hi @Michael ,

Thank you so very much for this! It was a great help, and offline works perfectly.

A note to other users stumbling upon this thread. The above code will not automatically convert to JS for use on pavlovia. You can however use this code to write a JS code component yourself or use the code yourself to help map out the coordinates of your shapes.