RatingScale customization

1,850 views
Skip to first unread message

gpagnoni

unread,
Oct 6, 2010, 6:00:31 AM10/6/10
to psychopy-users
Dear Jeremy,

thank you for providing the RatingScale class, it is indeed very
useful. Would it be difficult to add the following capabilities?

1) custom keys for moving the cursor along the scale: if the rating
is performed inside an MR scanner, a mouse or a full keyboard is not
likely to be available. One could use a standard (e.g. FORP) 4-keys
button box though, if it was possible to instruct RatingScale that for
instance '1' means 'go left', '2' means 'go right', and '4' means
'accept' (the latter option I found is already possible, using
'acceptKeys').

2) custom labels for the scale end markers (e.g., not only the default
'not at all'/'extremely').


thanks again!

very best
giuseppe

Jeremy Gray

unread,
Oct 6, 2010, 8:21:58 AM10/6/10
to psychop...@googlegroups.com
Hi Giuseppe,

thanks for your feedback and suggestions. I'll eventually make a more general solution available, but here's how to get it working quickly:


1) custom keys for moving the cursor along the scale:
this will require changes to 3 lines in visual.RatingScale.draw(). (I am not sure what the line numbers will be in your version of visual.py)

first add '1' and '2' to the 'if key in ...' lines within draw(), so that they look like
  if key in ['left', '1']:
  if key in ['right', '2']:
respectively. you can delete the left and right part, that's fine too if you don't need it

you also need to disable using 1, 2 and 4 ways to select a rating. a brutal but effective way to do this is to add 'False and' to the line just above the 'if key in ...' lines:
  if False and key in self.respKeys:

and the last thing is that you'll want to set up the rating scale to have the marker appear on the line, so that the only thing the subject has to do is move it right or left, not also do something to first place it on the line. for this, use the markerStart parameter. so in your script (not in visual.py), when you init a rating scale do this:
  myRatingScale = visual.RatingScale(myWin, markerStart=4, acceptKeys=['4','return'])

I am pretty sure this will work for you. note that the 'if False and ...' part will disable using number-keys for every script using that hacked version of visual.py.

eventually, I'll add a leftKeys and rightKeys option (analogous to acceptKeys), and have it automatically disable using number keys as response keys in the case of conflicts.

2) custom labels for the scale end markers:

I think what you are asking here is already possible, using the 'scale= ...' parameter. eg:
  myRatingScale = visual.RatingScale(myWin, scale='1=boring ... 7=hilarious',)
this changes the text description of how the subject should interpret the numbers that are the end points of the scale. (numbers are still shown as the 'anchors', the text that is shown under the line with tick-marks. I want to allow that to be set too, eg, for true - false, agree dis-agree, and so on.)

Recap:
Make the above 3 changes to the draw() method, and then try this:

myRatingScale = visual.RatingScale(myWin, scale='1=boring ... 7=hilarious', markerStart=4, acceptKeys=['4'])

--Jeremy


--
You received this message because you are subscribed to the Google Groups "psychopy-users" group.
To post to this group, send email to psychop...@googlegroups.com.
To unsubscribe from this group, send email to psychopy-user...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/psychopy-users?hl=en.


gpagnoni

unread,
Oct 22, 2010, 2:44:03 AM10/22/10
to psychopy-users
Dear Jeremy,

if you are in the process of updating the rating scale class, may I
ask also for an option to set the color and font size of the scale end
labels as well as of the current "scale" parameter (which is used
currently as a substitute of custom end labels)?

many thanks

giuseppe
> On Wed, Oct 6, 2010 at 6:00 AM, gpagnoni <gpagn...@gmail.com> wrote:
> > Dear Jeremy,
>
> > thank you for providing the RatingScale class, it is indeed very
> > useful.  Would it be difficult to add the following capabilities?
>
> > 1) custom keys for moving the cursor along the scale: if  the rating
> > is performed inside an MR scanner, a mouse or a full keyboard is not
> > likely to be available.  One could use a standard (e.g. FORP) 4-keys
> > button box though, if it was possible to instruct RatingScale that for
> > instance '1' means 'go left', '2' means 'go right',  and '4' means
> > 'accept' (the latter option I found is already possible, using
> > 'acceptKeys').
>
> > 2) custom labels for the scale end markers (e.g., not only the default
> > 'not at all'/'extremely').
>
> > thanks again!
>
> > very best
> > giuseppe
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "psychopy-users" group.
> > To post to this group, send email to psychop...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > psychopy-user...@googlegroups.com<psychopy-users%2Bunsu...@googlegroups.com>
> > .

Jeremy Gray

unread,
Oct 22, 2010, 7:32:18 AM10/22/10
to psychop...@googlegroups.com
Hi Giuseppe,

sure, I'm happy to add these. it will be a couple weeks before I can get to it, at the earliest. meanwhile, in visual.py you can add to the TextStim definitions and I think it should do the trick:

self.scaleDescription = TextStim(win=self.win, text=scale, ...
self.lowAnchor = TextStim(win=self.win, text=str(self.low), ...
self.highAnchor = TextStim(win=self.win, text=str(self.high), ...

for each of these, for font size use setHeight="..."  and for color use "setColor=..."
http://www.psychopy.org/api/visual.html#textstim

--Jeremy


To unsubscribe from this group, send email to psychopy-user...@googlegroups.com.

gpagnoni

unread,
Oct 22, 2010, 12:16:34 PM10/22/10
to psychopy-users
Excellent, thank you very much!

best,

giuseppe
> > <psychopy-users%2Bunsu...@googlegroups.com<psychopy-users%252Buns...@googlegroups.com>

gpagnoni

unread,
Jan 28, 2013, 7:00:33 AM1/28/13
to psychop...@googlegroups.com
Hello again Jeremy!

This is about a different issue..  In going through my old script with a new monitor set up, I noticed that my rating scales were a bit off. I found this old thread about labeling the end points of the rating scale in a "custom" fashion, using the "scale" parameter rather then the 'low/highAnchorText' parameters (which add some other text to the labels), as previously suggested by you:
 

2) custom labels for the scale end markers:

I think what you are asking here is already possible, using the 'scale= ...' parameter. eg:
  myRatingScale = visual.RatingScale(myWin, scale='1=boring ... 7=hilarious',)
this changes the text description of how the subject should interpret the numbers that are the end points of the scale.

I noticed, however, that when using 'stretchHoriz=2' the scale text has a wrap width that seems too short.  I horribly hacked visual.py, by changing the lines around 6400 as follows:

 # create the TextStim:
        self.scaleDescription = TextStim(win=self.win, height=self.textSizeSmall,
                                    color=self.textColor, colorSpace=self.textColorSpace,
                                    #pos=[self.offsetHoriz, 0.22 * self.displaySizeFactor + self.offsetVert],
                                    pos=[self.offsetHoriz, 0.22 * 
                                         self.displaySizeFactor +
                                         self.offsetVert], wrapWidth=2 *
                                         self.stretchHoriz *
                                         self.displaySizeFactor,
                                    name=self.name+'.scale')

It seems to work fine for me, so I just wanted to let you know in case you think something like this should be incorporated in the next code iteration.

very best
giuseppe

Jeremy Gray

unread,
Jan 28, 2013, 9:32:24 AM1/28/13
to psychop...@googlegroups.com



very best
giuseppe

--
You received this message because you are subscribed to the Google Groups "psychopy-users" group.
To post to this group, send email to psychop...@googlegroups.com.
To unsubscribe from this group, send email to psychopy-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/psychopy-users/-/qxGmMoQjtZ4J.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Lucy Cheke

unread,
Jan 28, 2013, 9:51:16 AM1/28/13
to psychop...@googlegroups.com
Hi Jeremy,

I'm also trying to adapt the rating scale to accept keyboard input, but I'm not sure I understand your instructions earlier in this thread (presumably becasue that was 2010 and stuff has changed since then!).

The ection of code for the rating scale looks like:

rating=visual.RatingScale(win=win, name='rating', escapeKeys=['escape'], displaySizeFactor=1.00,
    pos=[0.0, -0.40000000000000002], low=0, high=1, showScale=False, lowAnchorText='Boring', highAnchorText='Entertaining',
    precision=100, markerStyle='glow', showValue=False, markerExpansion=0, scale='How Entertaining Was That Video?')

 .....

#-------Start Routine "HowEnjoyVid"-------
continueRoutine=True
while continueRoutine:
    #get current time
    t=HowEnjoyVidClock.getTime()
    frameN=frameN+1#number of completed frames (so 0 in first frame)
    #update/draw components on each frame
 
    #*rating* updates
    if t > 0.0:
        rating.draw()
        continueRoutine = rating.noResponse
        if rating.noResponse == False:
            rating.response = rating.getRating()
            rating.rt = rating.getRT()
   
I can't see where it codes for the type of input its recieving, or how to alter the input to keyboard.

Sorry to ask the same question again!

Thanks

Lucy

Jeremy Gray

unread,
Jan 28, 2013, 10:03:55 AM1/28/13
to psychop...@googlegroups.com
Hi Lucy,

Its only possible to use keys to respond if there are fewer than 10 response options, either 0-9 or category choices that can be coded 0-9. If the scale responses are 0-9 compatible with keys, keys are automatically enabled (unless you suppress this with mouseOnly=True). Otherwise, keys are automatically disabled. So it does not allow you to specify this (except to turn it off).

In the code you have above, low=0, high=1, precision=100, so keys are not allowed (more than 10 possible responses, and they are not integers or categorical). 

In theory it would be possible to write some code to distinguish between someone pressing '5' and '52', based on the time between subsequent key presses, but that would be some effort and still be confusion prone. I think a mouse response is just as easy in this case.

--Jeremy


To view this discussion on the web visit https://groups.google.com/d/msg/psychopy-users/-/GMA2ioqWfwAJ.

Lucy Cheke

unread,
Jan 28, 2013, 10:13:30 AM1/28/13
to psychop...@googlegroups.com
Hi Jeremy,

I'm trying to create a task that can be used in an MRI scanner so this is why I want the keys. I actually was thinking in terms of having only one key reponse (left button) that gradually increases the response rating the more it is pressed. I.e. the response starts at 0 and increases with the number of left presses (or even better, the length the key is held down). i can code this manually from scratch, but I was just trying to investigate if its possible to tweak the response code.

Jeremy Gray

unread,
Jan 28, 2013, 10:27:20 AM1/28/13
to psychop...@googlegroups.com
Hi Lucy,

You can use the leftKeys and rightKeys parameters, and set those to be two of your scanner buttons (e.g., leftKeys='1', rightKeys='2'). Pressing these will allow subjects to navigate along the scale. And have acceptKeys be a 3rd scanner button rather than return (acceptKeys=('3']). But for this you probably want a 0-10 scale (with default precision = 1), and not a 0-1 scale with precision 100. 

You would have to write your own code to translate button hold times into a number of key presses. Its possible and would not be that hard.

--Jeremy


To view this discussion on the web visit https://groups.google.com/d/msg/psychopy-users/-/HO0tRnEJYSoJ.

gpagnoni

unread,
Jan 28, 2013, 12:12:55 PM1/28/13
to psychop...@googlegroups.com
Hi Jeremy, thank you!  do you know whether this new version of visual.py is supposed to work only on psychopy versions > 1.74?  I tried it out on a Mac (OS 10.7.5) running the self-contained 1.74 psychopy, and it worked fine when the output screen was the laptop's, but gave me an error when I selected an external monitor for output  (the original visual.py from psychopy 1.74 was fine when outputting to the external monitor).

thanks

giuseppe

Jeremy Gray

unread,
Jan 28, 2013, 12:16:26 PM1/28/13
to psychop...@googlegroups.com
did you replace the whole visual.py file? that would very likely cause problems. so I think you'll have to just manually edit the visual.py file from 1.74

--Jeremy


To view this discussion on the web visit https://groups.google.com/d/msg/psychopy-users/-/Urtl_Wlb4b0J.

Lucy Cheke

unread,
Jan 29, 2013, 6:35:11 AM1/29/13
to psychop...@googlegroups.com
Hi Jeremy,

Thanks. Sorry to be dense, but where exactly in the code would I specify this?

Thanks

Lucy

Lucy Cheke

unread,
Jan 29, 2013, 6:46:14 AM1/29/13
to psychop...@googlegroups.com
oh nevermind I get it.

Jeremy Gray

unread,
Jan 29, 2013, 6:47:09 AM1/29/13
to psychop...@googlegroups.com
Hi Lucy,

In the Builder, you have to put it in the "customize everything" box under the advance parameters -- along with all other things that differ from a default RatingScale. (The window and name parameter are done for you best not to include those.) Be sure to have a markerStart value, or else the keys won't work.

So it might be something like this:

low=0, high=5, markerStart=3, showValue=False, allowSkip=False, leftKeys=['1', 'left'], rightKeys=['2', 'right'], acceptKeys=['3','return']

--Jeremy


To unsubscribe from this group and stop receiving emails from it, send an email to psychopy-user...@googlegroups.com.

To post to this group, send email to psychop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msg/psychopy-users/-/xKScU3iaxJ8J.

Lucy Cheke

unread,
Jan 29, 2013, 7:00:31 AM1/29/13
to psychop...@googlegroups.com
Hi Jeremy,

Thats absolutely brilliant, thankyou!!!

ConsueloS

unread,
Jun 20, 2013, 11:46:05 PM6/20/13
to psychop...@googlegroups.com
Hi Jeremy,
 I am also trying to use the  rating scale with a response box (this response box returns integers as values instead of strings):
I tried to change the parameters in the rating  scale itself including the integers as key options for accept, leftKeys and rightKeys
eg. leftKeys=['left', int(4), 4, str(int(4))]
but had no success
Also, I unsuccessfully tried to modify visual.py at line 6227:
    eg. leftKeys = int(4) #[leftKeys]
and at line 5828:
      leftKeys=int(4)   

I'm using coder psychopy 1.76.00 

Would you have any suggestions on how can I possibly fix this?

Thank you very much!!
consuelo

Jeremy Gray

unread,
Jun 21, 2013, 1:16:18 AM6/21/13
to psychop...@googlegroups.com
Hi Consuelo,

How does the response box inform psychopy that a response has been made -- where do the integers show up on the PC end? RatingScale only listens for keyboard or mouse events, so if numbers are coming through a serial or parallel port, RatingScale will be blind to them, so you'll need a way to convert integers from that source to a key equivalent and perhaps simulate a keypress.

--Jeremy

ConsueloS

unread,
Jun 21, 2013, 12:59:04 PM6/21/13
to psychop...@googlegroups.com
Hi Jeremy,
Thanks for the prompt reply!
Yeah I'm using a response box that is connected to the computer through a parallel port and just using python code to read  the bits/integers.
Would you have any ideas on  how to go about implementing your suggestion? just to get me started, I'm stuck!
Thanks a lot!

def readBox(self):
self.p.setData( self.IN_FLAGS[self.currBox ] )
return (~(self.p.getInData()>>3)) & 0x1F 
 curpress=box.readBox()
 rating= readkeys.readKey(curpress)
def readKeys(keyCode):
    keysPressed = []
   #if keyCode == 0: keysPressed.append(0)
    if keyCode & 2**0:
        keysPressed.append(1)
    if keyCode & 2**1:
        keysPressed.append(2)
    if keyCode & 2**2: 
        keysPressed.append(3)
    if keyCode & 2**3: 
        keysPressed.append(4)
    if keyCode & 2**4: 
        keysPressed.append(5)
    return keysPressed

Jeremy Gray

unread,
Jun 21, 2013, 1:20:41 PM6/21/13
to psychop...@googlegroups.com
I'm not completely sure, but try this:

for key in keysPressed:
    key = str(key)[0]  # convert an int to a character
    event._onPygletKey(symbol=key, modifiers=None, emulated=True)  # add to buffer



Jeremy Gray

unread,
Jun 21, 2013, 2:23:47 PM6/21/13
to psychop...@googlegroups.com
this works for me:

>>> from psychopy import event  # event is for getting mouse and key events
>>> keysPressed = [1,2,3]  # these are type int
>>> for key in keysPressed:
...     key = str(key)[0]  # convert an int to a character
...     event._onPygletKey(symbol=key, modifiers=None, emulated=True)
... 
>>> event.getKeys()  # rating scale will do this for you; this line just proves it can work
[u'1', u'2', u'3']

the line "event._onPygletKey ..." adds that key to the key buffer *exactly* as if a human had pressed the key (except that it will say "emulated" in the logging, just so you can tell them apart!)

just to elaborate the usage: add the for-loop code to the end of your read-box function and it will probably be all thats needed for rating scale to interpret single-digit button responses as being the equivalent of someone pressing the key-board.

ConsueloS

unread,
Jun 21, 2013, 4:31:07 PM6/21/13
to psychop...@googlegroups.com
Hi Jeremy,

Thank you so much for your suggestion, it's working now!!

But now I'm having this problem: hitting the left (or right) key jumps from one side of the scale to the other end, meaning that I'm not able to select the values
in the middle, maybe i need to manipulate setMarkerPos()??? am I missing something else?

 thanks for your help!

this is my code as I have it now 
##function outside psychopy to read keys
from psychopy import event
def readKey(keyCode):
    key=[]
    if keyCode & 2**0:
        key='1'
    if keyCode & 2**1:
        key='2'
    if keyCode & 2**2: 
        key='3'
    if keyCode & 2**3: 
        key='4'
    if keyCode & 2**4: 
        key='5'
    if keyCode == int(6): #(2**2 & 2**1): #how to get the 2 base form of 6  bit(6)=110
        key='6'
    for key in key:
        #if key==1:
        #key = str(key)#[0]  # convert an int to a character
        event._onPygletKey(symbol=key, modifiers=None, emulated=True)
    return key

###Rating Scale code itself
myRatingScale = visual.RatingScale(myWin, choices=[1,2,3,4,5],minTime=0.3,markerStart=2,showAccept=True,acceptKeys='1',leftKeys='2',rightKeys='3', displaySizeFactor=0.9,markerExpansion=1,stretchHoriz=2.2,showValue=True,pos=[0,-0.6])
event.clearEvents()
ratingClock=core.Clock()

ratingClock.reset()
while myRatingScale.noResponse: 
    myItem.draw()
    myValues.draw()
    myRatingScale.draw()
    curpress=box.readBox()
    rating= readkeys.readKey(curpress)
    myWin.flip()

ratingRT=ratingClock.getTime()

rating = myRatingScale.getRating() # get the value indicated by the subject, 'None' if skipped  
ratingRT=ratingRT 

Jeremy Gray

unread,
Jun 21, 2013, 4:55:19 PM6/21/13
to psychop...@googlegroups.com
Hi Consuelo,

THere are several changes to the code I'd suggest, but a bigger issues are:

1) you appear to be using 2 and 3 both as items, as well as instructions to move left or right. it looks like left / right "wins", and these are moving along the scale (which is progress!). These are incompatible and you'll have to change something.

2) my guess is that something about your set up is detecting whether a button is currently pressed down, and if so, adds a key to the key buffer. this will result in multiple instances of a key for a single press, because a "down" press is likely to last for ~100ms. You want to catch "was up, changed to down" (first one, not all of them). So you need some logic in there to do that: maybe have a global variable last_state. only count a key press as a key if its down (as currently detected) AND is a change from last_state. and at the end of readKey() set last_state to whatever the current state is.

3) "for key in key" work only because key is a string. You probably want "for key in keylist:" -- multiple possible keys. and the readKey code will need to append to keylist rather than set key = '5', etc

Giulia Rampone

unread,
Jan 13, 2014, 10:51:35 AM1/13/14
to psychop...@googlegroups.com, gpag...@gmail.com
Hello,

I'm having some troubles with my rating scale - but I think they should be easy to fix.
It works fine on my laptop with Psychopy 1.77
However, it gives an error on our testing-PC, in which we have Psychopy 1.74 (and for some reason they don't want to move to a newer version).
This is due to the keyword 'ticMarks' and 'labels'. Which didn't exist in the older version.
 It works if I take them off - but I don't like the default text-labels (0=not at all, 100= extremely)... I would like to have mine. 
 I tried also to change it with 'low/highAncortext' but this keyword isn't recognised either.

From the manual I cannot understand whether there is a possibility to do that.
May you please suggest me how to change my bit of code in order to have the labels in the older version as well?

Here the bit of rating scale:

            myRatingScale = visual.RatingScale(myWin, low = 0, high = 100, showValue= False,showAccept=False, singleClick=True,markerStyle='triangle', 
                                   markerColor='white',lineColor='black',textColor='black',textFont='Helvetica Bold', pos =[0,0],
                                   stretchHoriz= 2) # tickMarks = [0, 25, 50, 80, 100],labels = ["Very Negative", "", "", "", "Very Positive"]) 
                                     

Many thanks in advance for your help

Giulia

Mario Reutter

unread,
Jan 19, 2015, 11:59:23 AM1/19/15
to psychop...@googlegroups.com, gpag...@gmail.com
Hi,

is it possible to reset the labels of an instance of ratingscale?
Neither
ratingScale.labels = ("foo", "bar")
nor
ratingScale.setLabels("foo", "bar")
work.

It would be nice to avoid creating a new instance every single time.

Thank you very much!
Mario

Jeremy Gray

unread,
Jan 19, 2015, 12:18:24 PM1/19/15
to psychop...@googlegroups.com
is it possible to reset the labels of an instance of ratingscale?....

No, its not set up to do that, and I don't think I want to go there. Conceptually, participants would then be responding on a different scale.
 
It would be nice to avoid creating a new instance every single time.

Often the right thing to do is try to reuse existing stim instances, since creating a new instance can take time, memory resources, etc. But if the scale is different I think the instance should be too. I can envision cases where it would be conceptually the same scale (e.g., same items in a different random order), but hopefully that is a special case.

--Jeremy

Mario Reutter

unread,
Jan 19, 2015, 2:50:56 PM1/19/15
to psychop...@googlegroups.com

I understand. It really is a separate scale (7-point SAM vs. 7-point Likert) and thus it makes sense to use a seperate instance.
Thank you very much for the quick and helpful response.

Mario

--
You received this message because you are subscribed to a topic in the Google Groups "psychopy-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/psychopy-users/StSv25V1TSc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to psychopy-user...@googlegroups.com.

To post to this group, send email to psychop...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages