psychopy.org | Reference | Downloads | Github

Randomize image after selection on slider

Hey, I want to create an experiment with Builder, where people should indicate they’re choice between two different shapes that I present on screen. I did this with the slider component because I want my experiment to run online later.
Then, I want to “respect” the choice of half of the participant and show them they’re desired shape in the next routine. For the other half I want to “neglect” their choice. I’ve got two pictures, lets say A represents a circle and B a triangle. slider = 1 represents circle and 2 = triangle. How can I show a picture depending on the choice on the slider component? And how can I present 50:50 the picture that they wanted and not? I managed to randomly show the images with the post linked down below. But how can I select it based on the slider response?
I hope you get an idea of what I am trying to do
@dvbridges maybe you’ve got an idea?

You can use a Variable component for this. Create a Variable in the same routine as the slider, and set its End Routine value to be:

{1: "CircleImage.png", 2: "TriangleImage.png"}[ MySlider.getRating() ]

(with CircleImage.png being the file name of your circle image, TriangleImage.png being the file name of your triangle image and MySlider being the name of your slider)

What you’re saying is: From a dictionary where 1 is mapped to "CircleImage.png" and 2 is mapped to "TriangleImage.png", get the value mapped to whatever MySlider.getRating() is. So if the slider is at 1, the variable’s value will be "CircleImage.png", if it is 2, it will be "TriangleImage.png".

You can then set the value of your image in the next routine to be the value of this variable, e.g. $MyVariable

But then every time I get the image corresponding to the response, right? But I also want to get the opposite one for half of the participant. So half of them should not get their slider choice

But then every time I get the image corresponding to the response, right? But I also want to get the opposite one for half of the participant. So half of them should not get their slider choice

How is PsychoPy to know if the participant is one of those for whom the “correct” image should be shown, or one of those where the image presentation has nothing to do with the participant’s response?

If you were to create a completely separate version of the experiment, you could use something like this variable component:

This is what @TParsons suggested, only with a slight modification. The int(random()*2+1) part tells PsychoPy to generate a random integer, 1 or 2.

But it’s a really bad idea to make two separate versions of the experiment, if this is to be the only difference. The reason is that if you have two versions, you’ll probably end up fixing a bug in one of them but forget to do it in the other, and so on.

You could instead go to “Experiment Settings -> Basic -> Experiment Info” and add another field there which says e. g. ‘exp_version’:

experiment settings

Say you do that, and decide on using the letters ‘N’ for “non-random version” and ‘R’ for “random version”. It’s probably better to pick something longer to decrease the risk of a typo leading to the wrong version being run, but I’m keeping things simple here. Then you could add a code snippet like this:

# Begin Experiment tab
def random_choice():
    return int(random()*2+1)

def respectful_choice():
    return MySlider.getRating()

exp_version = expInfo['exp_version']
assert exp_version in ('R', 'N'), 'Invalid experiment version'

if exp_version=='R':
    choice_fun = random_choice
else:
    choice_fun = respectful_choice

And you could then change your variable component’s “Routine start value” to:
{1: "CircleImage.png", 2: "TriangleImage.png"}[ choice_fun() ]

This suggestion makes use of how everything, including functions, is an object in Python. It also makes use of how the values of global variables are available (though not modifiable by default) even within a function’s scope. If you don’t know that much Python then you probably don’t know what this means. You could try finding a less code-heavy solution, or study Python itself (which takes some time of course). I can’t think of a simpler/code-less solution unfortunately, but maybe someone else can :slight_smile:

Hey thanks for your help. Maybe things get even more simple if I tell you that the random one isn’t that random at all. So I should always show the other picture, that was not selected, never the one that was selected. Does this makes it easier?

Sorry another question that came to my mind just now: The problem with your solution is that it does not work online, does it? Cause then I would tell participants what to insert here (would be ok cause they have no idea what R and N mean but maybe not the best). But I think I try your solution anyway. Sounds really good to me. Thank you so much :slight_smile:

You could also do:

{ "respect": {1: "CircleImage.png", 2: "TriangleImage.png"}[ MySlider.getRating() ], "neglect" {2: "CircleImage.png", 1: TriangleImage.png"}[ MySlider.getRating() ] }[ cond ]

but we’d be getting into unreadably complicated territory, so might be better to expand it out into some if statements in a code component:

if cond == "respect":
    MyVar = {1: "CircleImage.png", 2: "TriangleImage.png"}[ MySlider.getRating() ]
elif cond == "neglect":
    MyVar = {2: "CircleImage.png", 1: "TriangleImage.png"}[ MySlider.getRating() ]
1 Like

So I should always show the other picture, that was not selected, never the one that was selected. Does this makes it easier?

Ah, I misunderstood. That means that the participant’s choice is “respected”, only it’s reversed. It’s a good idea to think carefully if this is really what you want, and how participants will react to this pattern, but I’ll put this aside.

The problem with your solution is that it does not work online, does it?

I haven’t used the online capabilities much, but you’re right, it’s very likely that PsychoPy’s script conversion tool won’t understand how to translate from Python to JavaScript if you’d use the pattern I suggested. I wasn’t thinking of that, sorry.

@TParsons solution is much cleaner. There’s still the issue of how you specify which participants should be in the ‘reverse’ and which ones should be in the ‘non-reverse’ group. How are you assigning participant ID’s? If you just go 1, 2, 3, 4, 5… and so on, you could use something like

# Begin experiment tab
p_num = int(expInfo['participant'])

if p_num%2==0:
    cond = 'respect'
else:
    cond = 'neglect'

# Begin routine tab
if cond == "respect":
    MyVar = {1: "CircleImage.png", 2: "TriangleImage.png"}[ MySlider.getRating() ]
elif cond == "neglect":
    MyVar = {2: "CircleImage.png", 1: "TriangleImage.png"}[ MySlider.getRating() ]

This would mean that for all participants who have an even ID, the image choice is not reversed, while for those with an odd ID, the choices are reversed.

You might want to have some less basic ID’s than just 1, 2, 3…, most of all to avoid someone accidentally entering the wrong ID, meaning you don’t know which data go with which participant. You could try this instead:

import re
p_num = re.search('[1-9][0-9]*', expInfo['participant'])
p_num = int(p_num[0])

# ... same as before

That scans the participant ID for a sequence of digits, so you could use participant ID’s like “foo4010”, “bar5011”, “word6010”, “hello7011”… Anything works, as long as each ID has a sequence of digits that doesn’t only consist of a 0, where every other sequence is even, and the rest are odd.

I don’t know if the converter knows how to translate re package function calls. The JavaScript equivalent would be something like:

let p_num = expInfo['participant'];
p_num = Number( p_num.match(/\d+$/)[0] );

# ... conditional logic, presumably generated by PsychoPy

You can read a little bit about using the expInfo dictionary in the PsychoPy docs if you want, but it doesn’t describe much about how things will work after conversion to JavaScript. So I don’t know if you can actually access the participant ID on the JavaScript side as I suggested above.

The Routine Start should be blank, as you’re setting the value at the end of each routine, if you then set it to something different at the start it would override your previous setting.

The code @Arboc posted is Python - they posted the Python code and then a JavaScript translation.

I meant for this part iin the begin routine tab. Cause without any code there I always get the error message “can’t find myVar”

Cause without any code there I always get the error message “can’t find myVar”

It might be that you need to set an initial value for MyVar in the “Begin experiment” section.

# Begin experiment tab
MyVar = "anything"

# ... code I described earlier

This is so that the image component can be initialized (though its image path value will be replaced later, once the routines start running).

The problem might be even more basic however, or there might be two things you need to fix. You wrote “can’t find myVar". The code snippets we wrote however used the variable name MyVar, so you need to make sure that you use exactly the same variable name wherever you want to reference the variable.

(side note: it’s actually more in line with Python naming conventions to use a variable name of my_var, or myVar for JavaScript, but anything works as long as you use the same name throughout)