Cannot assign fixed (independent of RT) duration to rating scale component

For my fMRI experiment, I would like to have a rating window
of a fixed 4s duration, i.e.

  1. if a response is given in this window, the
    component stays active (visual feedback is displayed) for the remaining time, i.e. 4-rt
  2. if no response is given in this window, the component ends and the script
    moves on to the next trial

I’ve set the duration property of my rating scale component to 4s, but the scale still awaits a response indefinitely. The maxTime property is of no help, as that just deactivates the component rather than end it. Adding code to force the end of the routine after 4s would not help, as I just want the ratingScale component to end rather than the entire trial routine.

On the other hand, if a response is given, the component ends right then, making the rating window effectively of variable duration, which I do not want.

I’ve defined a blank text component to stay on the screen for 4-ratingScale.rt and thus act as a “buffer” that makes the total duration fixed. But I get the error “AttributeError: ‘RatingScale’ object has no attribute ‘rt’”. If instead of ratingScale.rt I use ratingScale.getRT(), I do get a value, however it does not seem to correspond at all to the RT (i.e. time passed between the scale being displayed and a response being given).

Thanks for any thoughts!

1 Like

Sorry, forgot to mention that one more issue with this ratingScale component is the following: even though it’s conditioned to start when previousComponent.status==FINISHED, any key pressed during that previous component will nevertheless be registered and be displayed on the screen as feedback during the rating scale component!

I am still struggling with this and would very much appreciate any help, many thanks

I hope you don’t mind my saying so, but I think part of the reason there hasn’t been a response yet is that there’s a lot of information in your question (it seems like there may be several questions here) and it’s not organized in a way that makes it easy for us to understand exactly what the question is, or exactly what you want done.

So to help me understand your question, you have a routine containing a rating scale, and you want it to remain on the screen for 4 seconds, regardless of whether or not there is a response, I think you made that clear. What else is being displayed at the same time? Nothing else?

What do you mean by “visual feedback”? Is this another routine? I’m not sure I understand what is meant by “4-rt” and “stay on the screen for 4-ratingScale.rt”.

Could you maybe send a screenshot of your settings for the Rating scale, so we can try to replicate what you’re doing?

A thought, since this will be displayed for a fixed amount of time, what happens with multiple key presses?

I’ve started tinkering with the rating scale, here are a few observations (in builder).

I created routine with a rating scale, named it “ratingScale”, and changed no other settings, put it in a loop to display it five times, and then looked at the data and the automatically generated “last_run.py” script to figure out how to best get the routine to abort after four seconds. I added a code component, and under the section “each frame”, added this:

# t is the trial time
if t >= 4:
    continueRoutine = False

This will make the routine stop after roughly four seconds.

It’s important to understand that the reaction time (which in this case would be recorded as ratingScale.rt in the data file), the reaction time that is recorded is when the rating is “submitted”: in my case, by hitting enter. This is important because it doesn’t record the time when I selected a number. After looking at the docs, it became clear that if you want that information, you want the “history”, so in the Advanced properties of the rating scale, check “Store history”.

Now in the data file, under the column “ratingScale.history”, it has saved all of the times I selected a number. For example, in one trial I pressed 4, then 5, then 3. Here’s what was saved:

[(None, 0.0), (4, 1.164), (5, 1.931), (3, 2.798)]

You can see the 4 was selected at 1.164 seconds into the routine, for example.

I’m attaching this test experiment here, hopefully this is what you wanted. It displays the rating scale for 4 seconds, and will save all of the ratings. You would probably have to do a little post-processing on the data to extract the last rating clicked. If I get a couple of minutes later, I could write a script that would do this if you would like.

ratingScaleTesting.psyexp (4.5 KB)

Thanks Daniel. I think if I’d given less information in the original post, people would have said that it’s not detailed enough - so it’s hard to say what the optimal thread length is that’s likely to get answers :wink:

Anyway, basically the problem is that I cannot reliably obtain a duration for the rating scale component (i.e. for how long it’s been on the screen). It is that duration that I would use to define a timeout, so that the script moves on after 4s if no response is given, or to define a ‘padding’ text component to fill in the remaining time, in case there is a timely response given to the ratnig scale.

As I said, using .t and .rt after the component name produces an error. I’ve had some success with .getRT(), but there seems to be a bug there, as having this code component in my routine:

if vividnessRating_I.status==STARTED:
  if vividnessRating_I.getRT() > 4:
    continueRoutine = False

gives the following error:

  File "D:\Experiments\Imagery\Tasks\2.MRI\imageryMRI_lastrun.py", line 795, in <module>
    I.addData('vividnessRating_I.rt', vividnessRating_I.getRT())
  File "C:\Program Files (x86)\PsychoPy2\lib\site-packages\psychopy-1.83.04-py2.7.egg\psychopy\visual\ratingscale.py", line 1195, in getRT
    if self.timedOut:
AttributeError: 'RatingScale' object has no attribute 'timedOut'
Exception TypeError: "'NoneType' object is not callable" in <bound method Server.__del__ of <pyolib.server.Server object at 0x05727810>> ignored

unless the value that comes after “>” is large enough - for instance, if I write 100 in there, the script works as expected and the rating scale component times out after 100 s!

By visual feedback I just meant the marker that is displayed on the rating scale when one of the accepted keys is pressed. In case of multiple key presses, only the last one should be considered.

Thanks again for your help.

Thaanks for that example! I had in fact written a similar script from scratch just to make sure the basic things work - they do, it’s really just that strange bug with how large the value that comes after the “>” sign is (see previous post)

So it looks like we were working on our last two posts at the same time :slight_smile:

Well before getting into if there’s a bug, note the difference between my code and yours: “t” is the trialClock, which starts over every time the routine is shown. In your case, you’re basing it on the reaction time: if they haven’t responded, there is no reaction time, so it returns None, so comparing a time to None is going to give you strange behavior.

(And I totally know what you mean about not giving enough information, I guess just for me its organization was a little confusing, and I wasn’t sure which problem was the one you wanted solved. But that could just be me.)

So when you get a chance, try out the example and let us know if it works?

The thing is, the rating scale component is quite late into my routine, and so the trialClock would not be of interest here. What I would need is that some clock/stopwatch but for the ratingscale component. The ratingscale.getRT() does actually appear to return this: if I display this variable using a text component, it starts from 0 as soon as the rating scale has appeared on the screen, as desired. It’s just that the time out constant needs to be large enough for it to work, and otherwise the “‘RatingScale’ object has no attribute ‘timedOut’” error comes up - which suggested to me a bug.

You can create a separate clock at the beginning of the experiment, and reset it at the beginning of the routine. Here’s a revised version, “feedback” below is the name of the text component that will show feedback for as long as is left after a response, until 4 seconds have past. In the code component (which should be below the rating scale):

Begin experiment:

rsClock = core.Clock()

Begin routine:

rsClock.reset()

Each frame:

rsTime = rsClock.getTime()
if rsTime >= 4:
    continueRoutine = False

rsH = ratingScale.getHistory()

if rsH:
    # get last tuplet of the list,
    # get the second element of the 
    # tuple it returns (the reaction time)
    rsRt = rsH[-1][1]
    # rating scale choice
    rsCh = rsH[-1][0]
    if rsRt:
        ratingScale.setAutoDraw(False)
        feedback.setAutoDraw(True)
        feedback.text = "You chose {0} at {1} seconds".format(rsCh, rsRt)

Note that, if I’m not mistaken, this reaction will be calculated from the point the rating scale is shown. Check out this updated version.

ratingScaleTesting.psyexp (4.5 KB)

Thank you very much Daniel, I think I got it to work now!

Oh - I realised we haven’t also fixed the issue about the rating scale component picking up key presses before it is meant to begin.

Even though the component is conditioned to start when previousComponent.status==FINISHED, any key pressed during that previous component will nevertheless be registered and be displayed on the screen (as the default marker) during the rating scale component!

Any way to fix this?

Try adding:

event.clearEvents()

To the code component at Begin Routine.

Doesn’t work :frowning: I added this in a code component in the same Trial routine as the rating scale, in its BeginRoutine tab as you indicated.

Tudor sent me some files and we got it worked out. I’ve also opened an issue on github, since I assume key presses bleeding from the previous stimulus is not desired behavior. Is that right @jeremygray ? Here’s some of what I wrote in the issue ticket:

The workaround is to call event.clearEvents() before
displaying the rating scale. When the rating scale is in its own
routine, in a code component, in Begin routine, the call:

event.clearEvents()

solves the problem. When the prior Stimulus is in the same routine as
the rating scale (i.e. Show text for 3 seconds, then rating scale), the
code component has:

Begin routine

eventsCleared = False

Each frame

# assumes the rating scale is named ratingScale
if ratingScale.status == STARTED:
    if not eventsCleared:
        event.clearEvents()
        eventsCleared = True

It was also important that the code component in the builder be positioned lower than the rating scale component, since this affects how the builder components are converted into code.

Problem indeed solved, many thanks once again for all your help Daniel.