Creating a variable based off of a rating scale response

487 views
Skip to first unread message

Robert Thomas

unread,
Jul 15, 2016, 10:08:49 PM7/15/16
to psychopy-users
Hello everyone, very new to PsychoPy here, and I am currently feeling way over my head using the builder to create my first experiment. 
My main issue at present is that I need to create a variable labeled as 'score' based on a response a subject would have made on a previous rating scale using categorical choices. What I have currently is a small loop with the first routine as a rating scale, with the rating scale component called "s1". The next routine in the loop is where I am trying to create the score variable and have a short ISI, and a custom code component that writes "score=$s1.response" meant to create a score equivalent to the response made on s1. The next routine is just a text component with the text body as $score, with the fields updating at set every repeat. When I try to run this I get a Name Error: name 'score' is not defined. I am wondering how I can make it so this is defined or perhaps figure out another way to create this variable known as score.
- I was originally thinking of trying to use the output file as a condition file within this loop but I am not sure if this is possible or how to do this.

Any help would be appreciated.

Thanks
-Bobby

Michael MacAskill

unread,
Jul 17, 2016, 6:56:44 PM7/17/16
to psychop...@googlegroups.com
Hi Bobby,

You're on exactly the right track, so it must just be something small that is tripping you up.

The only obvious error I can see is this:

> score=$s1.response

The '$' symbol will cause a problem in regular Python code. It is just a special prefix symbol used in Builder to indicate that something should be interpreted as a Python expression rather than as literal text. It shouldn't ever appear within regular Python code itself.

I'm not that familiar with the rating scale, so am not sure what its .response attribute is. According to the API <http://www.psychopy.org/api/visual/ratingscale.html>, I think you are actually after .getRating()

So perhaps just use this:

score = s1.getRating()

That $ symbol should have caused a syntax error, though, before the later name error appeared, so I'm a bit unsure what is going on. Let us know what happens. Actually, just for debugging purposes, you might want to also insert this line:

print(s1.getRating())

Just to check that it is working properly. Let us know how you get on.

Regards,

Michael
--
Michael R. MacAskill, PhD 66 Stewart St
Research Director, Christchurch 8011
New Zealand Brain Research Institute NEW ZEALAND

Senior Research Fellow, michael....@nzbri.org
Te Whare Wānanga o Otāgo, Otautahi Ph: +64 3 3786 072
University of Otago, Christchurch http://www.nzbri.org/macaskill

Robert Thomas

unread,
Jul 19, 2016, 11:18:24 PM7/19/16
to psychopy-users
Hi Michael, I just had the chance to try your suggestions and I made mroe progress in a few minutes then I have in weeks, so thank you very much.
The only problem I had to figure out for myself was that I needed this code component either in the Begin Routine box or the Each Frame box. 

This advice has hopefully led me to my last obstacle in building this experiment:
Essentially what I am trying to do now is have multiple rating scale responses (18 total) and to have the variable I have as score to be presented in a way that adds each previous rating scale response to the one just taken. So in the 2 rating scale demo I am working with now I am trying to get it where after rating scale 1 the score from rating scale 1 is presented (which I can do), and after rating scale 2 the score variable presented would be equal to the score of rating scale 1 + rating scale 2. 
The kicker is I need a way to do this no matter what order the rating scales are presented in, because in the final version I would ideally like to present all 18 rating scale trials in a random order, (each trial of a rating scale and response page contained within a loop inside the larger loop that would randomize the 18 smaller loops). 
I have attached a copy of the error I get in trying to just make the variable once with the code score= s1.getRating()+s2.getRating()   , and this is refreshed each frame
Is there anyway I can get this variable to be generated either within each small loop, or perhaps just have it be constantly refreshed and presenting the total amount for the variable score no matter which order the loops rating scale 1 (slide1) and rating scale 2 (slide2) are presented?

Let me know if there is any other info you need to help answer this question, and thank you very much again for your previous help.
-Bobby
Screenshot (1).png
Screenshot (2).png

Michael MacAskill

unread,
Jul 19, 2016, 11:45:15 PM7/19/16
to psychop...@googlegroups.com
Hi Robert,

Planning to have 18 loops means that you likely really need a re-design before you go any further… 

As a general principle in computer programming, one should strive assiduously to avoid duplication, for many reasons. With 18 duplications, the possibility of errors an inconsistencies skyrockets, and the program becomes much harder to maintain (e.g. needing to make a tweak to the trial procedure means it needs to be done 18 times rather than just once).

In essence, it is very likely that you can achieve what you need with a single routine and rating scale, being run 18 times via a single loop, with varying attributes contained in a conditions file, rather than 18 routines with differing but fixed attributes. The single loop structure will also make randomising the order and summing the ratings much easier.

That is, there is almost certainly a more efficient and simpler way to achieve this, but you'll need to give us a detailed description of your procedure and design. From this, we can hopefully advise both on a properly structured conditions file and then the Builder routine & loop structure to iterate over it.

Regards,

Michael

PS the error you are getting is very likely because the rating scale response is not being returned to you as a number. If the answer isn't a number, then it can't be added or otherwise manipulated arithmetically. I suspect (even if the response is a single number), that it is contained in a list object. Check this with debugging code like this:

print(s1.getRating())
print(type(s1.getRating())

If the value is a list object, and contains numbers rather than text, then you'd need to do something like this:

score = s1.getRating()[0] + s2.getRating()[0]

i.e. extract the first (i.e. zeroth) element of each list in order to add them to each other. e.g. you have $20 in each pocket and want to buy something for $40. You can't do that by adding the pockets together: you have to extract the money first in order to be able to combine it.


Robert Thomas

unread,
Jul 20, 2016, 8:59:44 AM7/20/16
to psychopy-users
Thanks for the speedy response as always Michael,
What I am essentially trying to do is recreate what is known as the SVO slider measure test (link to paper example found here http://vlab.ethz.ch/svo/SVO_Slider/SVO_Slider_paper_based_measures_files/SVO_slider_va_p12_blank.pdf ).
In terms of the Independent variable of my study I am trying to look at how feedback of scores after trials affects future trials. So the subject would make a decision on the slider (rating scale) and then a new routine would begin that presents a certain score, either the score represents the points allocated to themselves, or the points allocated to the other. After the second slider the score on the first slider would be added to this second score, and the sum of these two would be presented, and this would continue the 15 (I made a mistake on 18) times.
When starting to build this I was playing around with the idea of a single loop using a conditions file but I couldnt figure out how to get any information in my conditions file to be presented just in the rating scale component in the builder, rather I resorted to presenting the 9 options for each party (self and other) in a row of text above in below the slider that got their values from the conditions file. But this made it so I had no idea how I would get a score to be presented, as psychoPy wasnt actually storing any of the needed values from the rating scale.
Let me know what you think my best course of action is at your earliest convenience.
-Robert


On Friday, July 15, 2016 at 8:08:49 PM UTC-6, Robert Thomas wrote:

Michael MacAskill

unread,
Jul 20, 2016, 6:12:48 PM7/20/16
to psychop...@googlegroups.com

On 21/07/2016, at 00:59, Robert Thomas <roth...@colorado.edu> wrote:

Let me know what you think my best course of action is at your earliest convenience.

Hi Robert,

You'll have to treat us like children here: describe exactly what you want to be presented to the subject, in detail, as you would for a methods section in a paper. At the moment, your description assumes that the reader already understands what you are doing, e.g.

So the subject would make a decision on the slider
Decision about what? What is the scale they respond on (presumably numeric)?

and then a new routine would begin that presents a certain score,
either the score represents the points allocated to themselves,
what does "themselves" refer to?

or the points allocated to the other.
Other what?
How is the decision made as to what the score represents?
Is this indicated to the subject in some way?

After the second slider the score on the first slider would be added to this second score,
Are there two sliders per trial? Or does the second slider just refer to the next trial?

and the sum of these two would be presented, and this would continue the 15 (I made a mistake on 18) times.
So is the last score the cumulative sum of all 14 previous items, or just the previous two?

What information needs to be presented to the subject on each trial, and are the trials sequential or randomised?

etc, etc…


Regards,

Michael

Robert Thomas

unread,
Jul 20, 2016, 8:50:01 PM7/20/16
to psychopy-users
Sorry about that Michael, wrote that in a little bit of a rush this morning and I think I got you confused on some irrelevant information. Ill try and start from square one here of how I have it envisioned.

So the subject will come in and begin the rating scale trials, and end after completing all 15 of them. The trial, as I am calling it, will consist of two things:
1. There will be a rating scale component that has 9 numerical labels both above the rating scale and below the rating scale, but it will only be one choice made. The numbers above the scale correspond to an amount of money they allocate to themselves and below the scale is the amount of money the allocate to another, arbitrary person. An example would be that the amounts above the bar to be allocated to the self are 85-86-87- and so on up to the ninth value. while the numbers below which are the amount to the other random person are 50-49-48- so on to the ninth value.The subjects decision affects how much they get and how much the other arbitrary person gets.
2. The second part of my so called trial would be a different routine which would be presenting some aspect of how the choice on the rating scale was made. As an example for the rest of this post I will say that this second routine will present the amount of money that the subject has allocated to the other person. But this amount would be compounded on top of ALL of the previous amounts allocated to the other person. So after the very first rating scale decision is made only the amount allocated to the other person would show up on the next screen after they accept their rating scale decision. After the second rating scale decision the amount allocated to the other person on this second rating scale would be added to the first and then presented, the third rating scale response would then be added to both of these, and so on, so the last rating scale choice would be followed by a screen that gave the total amount given to the other person over the 15 rating scales. 
So if on rating scale 1 (RS1) $50 was given to the other person, and on RS2 $100 was given to the other person, and on RS3 $50 was again given to the other person, the routines following each of these rating scales would be: after RS1 $50, after RS2 would be $150, and after RS3 would be $200.

Additionally the rating scales would be presented in a random order for each subject so the first rating scale would not consistently have the same values on the rating scale.

I hope this helps clarify some of the information you needed, I of course left out exactly what instructions/text would be given to the subject as that is all very easy for me to put in, and the main thing I am struggling with is creating a conditions file that would fill in the rating scale and how I could get this to then be presented as feedback to the subject after each choice made.

-Bobby

Michael MacAskill

unread,
Jul 21, 2016, 12:43:14 AM7/21/16
to psychop...@googlegroups.com
Hi Bobby,

No apology necessary. This latest message gave a very good description of the pertinent information.

(1) You only need a single loop.
(2) You only need two routines within that loop: one to present the rating scale and one after that to present the feedback of the running total.
(3) This structure will allow the randomisation you need (just set the loop type to random).
(4) I'm not really familiar with the rating scale options, so it is quite possible that there are more efficient ways to display what I'm about to describe.
(5) I'm not sure if the interval between amounts will always be $1, so I've incorporated a 'step' value to capture what it might be (e.g. if on some trials the interval might be $5 or $10). If it is always $1, you can eliminate that bit.

The trickiest bit is actually the labelling above and below the rating scale. I'm not sure what the options are there, so will just assume that you can just use two separate text components, one above and one below the rating scale, and change its text size and inter-value padding with space characters to get it to line up. This may take quite some tweaking to get right, or even specifying the text size trial-by-trial if the values differ quite a bit in terms of number of digits per value.

Your conditions file should look something like this:

self_value other_value step
85 50 1
200 150 5
etc for 15 rows of values

Insert a code component in the first (rating) routine, above the other components. In its "begin routine" tab, put something like this:

# initialise blank label strings:
self_label = str(self_value)
other_label = str(other_value)

# construct the rest:
# could be modified to set attributes of the rating scale directly?
# use more spaces/dashes to pad between numbers as required:
for i in range(1, 9):
    self_label = self_label + ' - ' + str(self_value + i * step)
    other_label = other_label + ' - ' + str(other_label - i * step)

Then in the text components, put $self_label and $other_label as required, set to update on every routine.

I'm going to assume that the rating scale is simply set to have fixed response values of 0 to 8 on every trial. In the code component's "begin experiment" tab, put this to initialise the running total:

other_total = 0
self_total = 0 # not sure you need this but anyway...

And in the "end routine" tab, something like this:

# get the first element of the response list. 
# Not sure if actually need to convert to a number?
response = val(s1.getRating()[0])

# calculate running totals:
other_total = other_total + (other_value - (response * step))
self_total = self_total + (self_total + (response * step))

# save the current running values on each trial:
# (the rating response is automatically saved):
thisExp.addData('other_total', other_total)
thisExp.addData('self_total', self_total)

Then on the second routine, you can use $other_total in a text field to give feedback to the subject of the current running total.

Make sense? 

(NB this is completely untested code: CHECK, to make sure there aren't any off-by-one errors in particular).

Regards,

Michael



On 21/07/2016, at 12:50, Robert Thomas <roth...@colorado.edu> wrote:

Sorry about that Michael, wrote that in a little bit of a rush this morning and I think I got you confused on some irrelevant information. Ill try and start from square one here of how I have it envisioned.

So the subject will come in and begin the rating scale trials, and end after completing all 15 of them. The trial, as I am calling it, will consist of two things:
1. There will be a rating scale component that has 9 numerical labels both above the rating scale and below the rating scale, but it will only be one choice made. The numbers above the scale correspond to an amount of money they allocate to themselves and below the scale is the amount of money the allocate to another, arbitrary person. An example would be that the amounts above the bar to be allocated to the self are 85-86-87- and so on up to the ninth value. while the numbers below which are the amount to the other random person are 50-49-48- so on to the ninth value.The subjects decision affects how much they get and how much the other arbitrary person gets.
2. The second part of my so called trial would be a different routine which would be presenting some aspect of how the choice on the rating scale was made. As an example for the rest of this post I will say that this second routine will present the amount of money that the subject has allocated to the other person. But this amount would be compounded on top of ALL of the previous amounts allocated to the other person. So after the very first rating scale decision is made only the amount allocated to the other person would show up on the next screen after they accept their rating scale decision. After the second rating scale decision the amount allocated to the other person on this second rating scale would be added to the first and then presented, the third rating scale response would then be added to both of these, and so on, so the last rating scale choice would be followed by a screen that gave the total amount given to the other person over the 15 rating scales. 
So if on rating scale 1 (RS1) $50 was given to the other person, and on RS2 $100 was given to the other person, and on RS3 $50 was again given to the other person, the routines following each of these rating scales would be: after RS1 $50, after RS2 would be $150, and after RS3 would be $200.

Additionally the rating scales would be presented in a random order for each subject so the first rating scale would not consistently have the same values on the rating scale.

I hope this helps clarify some of the information you needed, I of course left out exactly what instructions/text would be given to the subject as that is all very easy for me to put in, and the main thing I am struggling with is creating a conditions file that would fill in the rating scale and how I could get this to then be presented as feedback to the subject after each choice made.

-Bobby

Robert Thomas

unread,
Jul 22, 2016, 9:52:50 AM7/22/16
to psychopy-users
Alright Micheal I think we are getting close here, just a few problems left that I cant solve.

First and foremost I am getting an error (screenshot attached) about the line :
# get the first element of the response list. 
# Not sure if actually need to convert to a number?
response = val(slide.getRating()[0])                                (I changed s1 to slide as that is the new name of the rating scale component)
The error says: val is not defined.

The 2 small other problems were due to my lack of exact detail in explaining the experiment again.
First off know that I added an extra column to my conditions file because I forgot to explain that the steps for self and other are not always the same (ie the step for self can be 1 while the step for other can be -5). So I just created two different step values, step_s (step self) and step_o (step other), and then just changed the corresponding places in the code, from my understanding this wont mess anything up too much. On to the questions

1. The step value for the self is not always a positive value, and the step value for other is not always negative. My plan for getting around this is to just make the step values in the condition file either positive or negative and then changing all the mathematical values in your code to only be +, so adding a positive step when that is the step value, and simply adding a negative step when that happens to be the step value. Let me know if you see problems here.

2. I am really hoping, and I dont think this problem will be as bad as it sounds with some explanation. So another problem with the step value is that there are actually points on the SVO slider test there on one row of the slider the steps are not equal whole numbers all the way across. For example the very first slider (I have attached a pdf of the slider document as well), has the row that the other person receives as 85--76--68--59--50--41--33--24--15, as you can see this means it has some steps that are -8 and some that are -9. Now I believe it would be impossible with our current set up to have different values for steps within each row of the slider but I think there is another solution. 
From reading about the SVO slider measure being developed, the reason that there are two different step values on the exact same rows of most of the sliders is because the numbers that are the values were created by taking 9 linear spaced numbers between two values, in the example I typed out above this would be 85 and 15. This gives you an output with a step that is actually equal to -8.75, so with decimals the slider would actually present 85--76.250--67.500--and so on. After these values are created they are then rounded to make the whole numbers that are found on the current slider measure. So, if I modify the conditions file so that the steps are decimals, and some of the step values are positive and some negative, would there be a way to implement a line of code that would then round these values before they are presented on screen. And actually there would not even be a need to have the total scores, or data output as decimals so I believe it is something that could potentially be done at the very beginning of the experiment. Let me know your thoughts

As always thanks for your help, I am very confident that I would still be on the wrong track without it.

-Bobby
SVO_slider_va_p12_blank.pdf
Screenshot (4).png

Michael MacAskill

unread,
Jul 23, 2016, 12:54:34 AM7/23/16
to <psychopy-users@googlegroups.com>
On 23/07/2016, at 01:52, Robert Thomas <roth...@colorado.edu> wrote:

# Not sure if actually need to convert to a number?
response = val(slide.getRating()[0])
The error says: val is not defined.
Sorry, that was a collision in my brain from another language. val() doesn't exist in Python and should be either int() or float(). But please note this function probably isn't necessary at all: the rating scale probably directly returns numbers that don't need to be converted.

First off know that I added an extra column to my conditions file because I forgot to explain that the steps for self and other are not always the same (ie the step for self can be 1 while the step for other can be -5). So I just created two different step values, step_s (step self) and step_o (step other)
Good. But see below, given your other requirements.

1. The step value for the self is not always a positive value, and the step value for other is not always negative. My plan for getting around this is to just make the step values in the condition file either positive or negative and then changing all the mathematical values in your code to only be +,
Sounds just right. But again see below about your other constraints. The step size should now be calculated rather than specified, and this will get its sign correct automatically.

So another problem with the step value is that there are actually points on the SVO slider test there on one row of the slider the steps are not equal whole numbers all the way across. For example the very first slider (I have attached a pdf of the slider document as well), has the row that the other person receives as 85--76--68--59--50--41--33--24--15, as you can see this means it has some steps that are -8 and some that are -9. Now I believe it would be impossible with our current set up to have different values for steps within each row of the slider but I think there is another solution.
I think what you actually need here in your conditions file is to define the start and end of each range rather than the start and the step. Then for each trial, in code you can take the difference between the start and end and divide by 8 to get the step size (NB 9 points create the boundaries for 8 intervals). Then in the code for creating the labels, just apply the Python int() and round() functions at each step as required. 

i.e. your conditions file will have forum columns:

self_start self_end other_start other_end
85 15 100 200
etc

Then the code would be roughly like:

self_step = (self_start - self_end)/8
self_label = str(self_start)

for i in range(1, 9):
    self_label = self_label + ' - ' + str(int(round(self_value + i * self_step)))

Note the step size should be automatically +ve or -ve depending on whether the start and stop values are ascending or descending.

Regards,

Michael

Robert Thomas

unread,
Jul 23, 2016, 12:13:00 PM7/23/16
to psychopy-users
Hi Michael, 
Good news here is that the rating scale component is working perfectly. All I needed to change to your code was that 
self_step = (self_start - self_end)/8
self_label = str(self_start)

needed to  be changed to
self_step=(self_end - self_start)/8
self_label = str (self_start)

As subtracting end from start gave me negative steps when I needed positive and positive when I needed negative.

I am still having trouble getting the feedback routine to work properly. There is no error or crash coming up but when I put $other_total in the text component on this routine it just stays at 0 throughout all 15 trials. I have attached the code boxes for the 'beginning of experiment' and 'at end of routine' as I think the trouble lies in one of these two places. In terms of the code in the beginning of the experiment box I am wondering if setting the totals to 0 is causing this to be set throughout the whole experiment, and even though you said it was perhaps not needed, when these lines were removed I did get a crash. I am not sure what problems may exist in the end of routine code. 
Thanks again.
-Bobby
Screenshot (6).png
Screenshot (5).png

Michael MacAskill

unread,
Jul 24, 2016, 4:40:19 AM7/24/16
to psychop...@googlegroups.com

In terms of the code in the beginning of the experiment box I am wondering if setting the totals to 0 is causing this to be set throughout the whole experiment, and even though you said it was perhaps not needed, when these lines were removed I did get a crash.
You definitely need to give this variable an initial value or else an error will occur (when you refer to it later without it already having been defined). Don't worry, code at the beginning of the experiment is executed only once, so it can't keep re-setting the variable to 0.

 I have attached the code boxes for the 'beginning of experiment' and 'at end of routine' as I think the trouble lies in one of these two places.
You'll need to debug the "end routine" tab. e.g. sprinkle some print statements here to look at each of the individual variables to see what is going wrong. e.g.

print(slide.getRating())
print(other_step)

etc

Actually, one simple check first: are you sure you have the text component set to update every routine?

Robert Thomas

unread,
Jul 27, 2016, 11:15:05 PM7/27/16
to psychopy-users
Well, turns out I just needed to have it set to update every routine, guess I should always try  the easy solutions first. Sorry it took so long to respond to this last one. The experiment is completely coded now besides instructions so thank you so so much for all your help Michael, I would have never figured this out without you. Let me know if there is any way to repay the favor.
-Bobby

Michael MacAskill

unread,
Jul 27, 2016, 11:18:45 PM7/27/16
to psychop...@googlegroups.com
Hi Bobby,

> On 28/07/2016, at 15:15, Robert Thomas <roth...@colorado.edu> wrote:
>
> Let me know if there is any way to repay the favour.

Sure, by passing on what you've learned to someone else 😊

Cheers,
Reply all
Reply to author
Forward
0 new messages