Sliders moved by keyboard and response recording

OS : macOS Mojave, version 10.14.6
PsychoPy version : PsychoPy v2020.2.4

Hello,
I am new on PsychoPy and I am trying to set an experiment about decision making.
In this experiment participants will see different image and will rate them according to how much they think each image is associated with a color (3 different colours).
I already set up a simple version of the task that display the image and where participants have to choose between two options (with their keyboard) and it seems to work fine.

This time I want to do something a little bit more complicated: I want to use 6 different sliders (3 for each images) with a keyboard. In addition, these sliders need to be mutually exclusive.

For the moment I found a way to create and move sliders with the keyboard in the forum (by @dvbridges).
I put the following code in “each frame” in the builder

slider = visual.Slider(win=win, name='radio',
    size=(1.0, 0.1), pos=(0, -0.1),
    labels=['a','b','c','d','e'], ticks=(1, 2, 3, 4, 5),
    granularity=0, style=['slider'],
    color='LightGray', font='HelveticaBold',
    flip=True)
sliderHistorySecond = []

slider.markerPos = 2

while True:
    keys = event.getKeys()
    if keys:
        if 'down' in keys:
            slider.markerPos -= 1
            continueRoutine = True
        if 'up' in keys:
            slider.markerPos += 1
            continueRoutine = True
        if 'space' in keys:
            slider.getRT()
            continuRoutine = False


            break
    if 'escape' in keys:
        core.quit()
    slider.draw()  
    win.flip()

I change the code a little bit to enable to finish the trial by pressing “space”. As continueRoutine = false doesn’t work I add a break but I don’t think that it’s the good way to do it.

The first issue is that it doesn’t record the response of participants event if I add slider.getRating() in the script. The sliders move correctly and pressing “space” enable to finish the trial.
I tried to create an empty list and to append slider.getRating() in it and even if I have no error it doesn’t appear anywhere.
In addition, is it possible to have vertical coded slider like a “normal slider” that can be added in the builder directly? I didn’t find the option in visual.Slider parameters.

My ultimate goal is to have 2 pie charts (with 3 colors each and that follow the sliders ratings) that is update each time a participant moves the sliders (to show them their rating more visually) and the first step is then to have sliders that record something.

Thank you

I think the problem is that you’re setting markerPos - this updates where the marker appears on the slider, but not the slider’s value. To change the slider’s value, use rating instead.

I don’t think we have a preset for a vertical slider that isn’t a Radio slider, but you could always rotate it by setting ori to 90

@kenzakadri @TParsons

I was able to use that first code to change the slider marker using keyboard presses, but I am running into the issue that is messing up the timing of my experiment. Each stimulus is supposed to continue after 12 seconds (regardless of if participants move the slider marker location), but with the code I am using, it seems to be only 12 second after the slider is moved. Is there a code I can use to ensure the experiment continues regardless of button press? Or perhaps should the code go under a different tab instead of each frame? Currently, my images that change after 12 seconds are set to “set every repeat.” Thank you!

You should almost always avoid putting a while True: loop or a win.flip() line in the “Each frame” tab of a code component, because yes, they will almost certainly muck up Builder’s timing.

A Builder script calls win.flip() itself, aiming to do this once on every screen refresh cycle. Typically that will happen 60 times a second (or every 16.7 ms). That means that any code in an “Each frame” tab must be able to be completed well within a 16.7 ms duration. If you put a while loop inside that tab, waiting for a response, then that will almost certainly take substantially longer than 16.7 ms to complete. In this case, you would be putting the entire experiment on hold until a key is pressed. Then issuing another win.flip() call will only compound the issue, as Builder scripts expect to be in control of when that occurs and why.

So delete the loop-related code, the .draw() call (Builder will take care of that too), and the win.flip().

If you have a keyboard component, then you could also avoid calling event.getKeys() and having to manually check if the experiment needs to be quit. Instead of keys, refer to the_name_of_your_keyboard_component.keys - i.e. let Builder handle the checking of the keyboard for you.

So roughly, your code in that tab could simply be something like:

if '1' in the_name_of_your_keyboard_component.keys:
    slider_Objects18in.markerPos -= 1
elif '2' in the_name_of_your_keyboard_component.keys:
    slider_Objects18in.markerPos += 1

I’m not sure what will happen here with regard to the same key being pressed or detected multiple times, and would need to know what your task is supposed to do there.

@Micheal thank you so much for this! I implemented these changes and the timing of my experiment is back to normal. In my experiment participant’s have to move a slider to a target location. I am planning to add a third option, that allows paricipants to confirm thier option using the ‘3’ key meaning that once they click this key, they will not be able to change their answer for that trial. Is there a code that would ‘fix’ or hold steady the slider marker location ?

In the “begin routine” tab, create a custom variable to keep track of whether the slider should still be accepting responses:

slider_locked = False

Then change the “Each frame” tab code to be something like:

if '3' in the_name_of_your_keyboard_component.keys:
    slider_locked = True

if not slider_locked:
    if '1' in the_name_of_your_keyboard_component.keys:
        slider_Objects18in.markerPos -= 1
    elif '2' in the_name_of_your_keyboard_component.keys:
        slider_Objects18in.markerPos += 1

hi @Michael thank you very much for the detailed help-- this did the trick! I will mark this as solved now. Many thanks!