Error giving feedback after a trial

Hi there,

I am new to Psychopy (since Monday!) and do not have any Python experience, so am using Builder. I am using Win7,PsychoPy version 3.0.0b7.

I am trying to give feedback to participants after a trial regarding whether their response was correct or incorrect. However, at the moment, the feedback is always telling them that they are incorrect.

In my study, each trial involves two pictures being shown at the same time - a shape and label. Prior to the trial, participants are instructed that certain shapes are matched with certain labels (e.g., triangle = affected hand, circle = unaffected hand, square = other (strangers) hand). Then in the trials, if the two images that they see on the screen are a correct pairing, then they are to press ‘3’ and if it is incorrect, then press ‘2’.

This is the way that I have my .xlsx spreadsheet set up:

Here is how I have things set-up in Builder…
Practice trials


Feedback:

Here are the settings for the response in the practice trial (Practice_Resp):

For the Picture_trial and the Label_trial, I have chosen “set every repeat” and the Trials loop is “random”, 1 rep, rows 0:60.

I followed a past thread about error in giving feedback (Error in giving feedback after a trial) which was very helpful and I tried all the suggestions - i.e., in case my excel CorAns values were being treated like integers instead of string variables.

Here is the output that I got when I ran the updated the program with the suggestions from the previous thread:

Running:
keys: <psychopy.event.BuilderKeyResponse object at 0x11940B50>
CorAns: 3
False
False
keys: <psychopy.event.BuilderKeyResponse object at 0x11944C30>
CorAns: 2
False
True
keys: <psychopy.event.BuilderKeyResponse object at 0x119470D0>
CorAns: 3
False
False
keys: <psychopy.event.BuilderKeyResponse object at 0x11947490>
CorAns: 2
False
True
keys: <psychopy.event.BuilderKeyResponse object at 0x119477B0>
CorAns: 3
False
False
keys: <psychopy.event.BuilderKeyResponse object at 0x119478D0>
CorAns: 3
False
False
keys: <psychopy.event.BuilderKeyResponse object at 0x11947AF0>
CorAns: 2
False
False
keys: <psychopy.event.BuilderKeyResponse object at 0x11947D10>
CorAns: 3
False
False
keys: <psychopy.event.BuilderKeyResponse object at 0x11944FF0>
CorAns: 2
False
True
keys: <psychopy.event.BuilderKeyResponse object at 0x119400D0>
CorAns: 2
False
True

This is clearly going wrong, but I’m not quite sure what to fix! It seems like it is giving a separate true or false answer for each of my stimuli (shape picture and label picture), when I what I want is for it to give a true/false answer for the stimuli pair. I suppose this might be a problem with randomisation if the stimuli are not being presented as a pair (i.e., as one row in the excel spreadsheet) and instead are being randomly sampled from the column. However, I don’t think this is the case as it was my understanding that using the set-up I have, the random function (loop) should randomly select a row. I am sure there are other problems too because I don’t know why I am getting this output for key response (<psychopy.event.BuilderKeyResponse object at 0x119400D0>

This is what I have for the code component in my feedback routine:
if Practice_Resp == CorAns:
msg = ‘Correct’
else:
msg = ‘Sorry, Incorrect’

And this is what I have for my variable component (Practice_feedback_msg):

Last, here is what I get when I click on Compile Script:
from future import absolute_import, division
from psychopy import locale_setup, sound, gui, visual, core, data, event, logging, clock
from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED,
STOPPED, FINISHED, PRESSED, RELEASED, FOREVER)
import numpy as np # whole numpy lib is available, prepend ‘np.’
from numpy import (sin, cos, tan, log, log10, pi, average,
sqrt, std, deg2rad, rad2deg, linspace, asarray)
from numpy.random import random, randint, normal, shuffle
import os # handy system and path functions
import sys # to get file system encoding

Ensure that relative paths start from the same directory as this script

_thisDir = os.path.dirname(os.path.abspath(file))
os.chdir(_thisDir)

Store info about the experiment session

expName = ‘CRPS_SPEtask_5_Jie_deg_setttings’ # from the Builder filename that created this script
expInfo = {‘participant’: ‘’, ‘RespHand’: “[‘left’, ‘right’]”, ‘Shapelabelpairing’: “[‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’]”, ‘session’: ‘001’}
dlg = gui.DlgFromDict(dictionary=expInfo, title=expName)
if dlg.OK == False:
core.quit() # user pressed cancel
expInfo[‘date’] = data.getDateStr() # add a simple timestamp
expInfo[‘expName’] = expName

Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc

filename = thisDir + os.sep + u’data/%s%s_%s’ % (expInfo[‘participant’], expName, expInfo[‘date’])

An ExperimentHandler isn’t essential but helps with data saving

thisExp = data.ExperimentHandler(name=expName, version=’’,
extraInfo=expInfo, runtimeInfo=None,
originPath=‘C:\Users\stantonr\Desktop\TASH\RESEARCH PROJECTS\Visit to Charles Spence Oxford\CRPS and SPE\CRPS SPE Experiment\CRPS_SPEtask_5_Jie_deg_setttings.py’,
savePickle=True, saveWideText=True,
dataFileName=filename)

save a log file for detail verbose info

logFile = logging.LogFile(filename+’.log’, level=logging.EXP)
logging.console.setLevel(logging.WARNING) # this outputs to the screen, not a file

endExpNow = False # flag for ‘escape’ or other condition => quit the exp

Start Code - component code to be run before the window creation

Setup the Window

win = visual.Window(
size=[1920, 1080], fullscr=True, screen=0,
allowGUI=False, allowStencil=False,
monitor=‘testMonitor’, color=[0,0,0], colorSpace=‘rgb’,
blendMode=‘avg’, useFBO=True)

store frame rate of monitor if we can measure it

expInfo[‘frameRate’] = win.getActualFrameRate()
if expInfo[‘frameRate’] != None:
frameDur = 1.0 / round(expInfo[‘frameRate’])
else:
frameDur = 1.0 / 60.0 # could not measure, so guess

Initialize components for Routine “Shapelabelpairs”

ShapelabelpairsClock = core.Clock()
imageShape = visual.ImageStim(
win=win, name=‘imageShape’,
image=None, mask=None,
ori=0, pos=(0, 0), size=(0.5, 0.5),
color=[1,1,1], colorSpace=‘rgb’, opacity=1,
flipHoriz=False, flipVert=False,
texRes=128, interpolate=True, depth=0.0)

Initialize components for Routine “InstrTask”

InstrTaskClock = core.Clock()
InstrTask_2 = visual.TextStim(win=win, name=‘InstrTask_2’,
text=‘A key - LEFT index finger\nPress this if the shape and label MATCH\n\nQ key - LEFT middle finger\nPress this if the shape and label DO NOT MATCH\n\nPlease be as FAST and as ACCURATE as posssible.\n\nPress any button to begin\n’,
font=‘Arial’,
pos=(0, 0), height=0.07, wrapWidth=None, ori=0,
color=‘white’, colorSpace=‘rgb’, opacity=1,
languageStyle=‘LTR’,
depth=0.0);

Initialize components for Routine “Practicetrials”

PracticetrialsClock = core.Clock()
Fix = visual.TextStim(win=win, name=‘Fix’,
text=’+’,
font=‘Arial’,
pos=(0, 0), height=0.1, wrapWidth=None, ori=0,
color=‘white’, colorSpace=‘rgb’, opacity=1,
languageStyle=‘LTR’,
depth=0.0);
Picture_trial = visual.ImageStim(
win=win, name=‘Picture_trial’,units=‘deg’,
image=‘sin’, mask=None,
ori=0, pos=(0, 3.5), size=(3.8, 3.8),
color=[1,1,1], colorSpace=‘rgb’, opacity=1,
flipHoriz=False, flipVert=False,
texRes=128, interpolate=True, depth=-2.0)
Label_trial = visual.ImageStim(
win=win, name=‘Label_trial’,units=‘deg’,
image=‘sin’, mask=None,
ori=0, pos=(0, -3.5), size=(6.3, 3.6),
color=[1,1,1], colorSpace=‘rgb’, opacity=1,
flipHoriz=False, flipVert=False,
texRes=128, interpolate=True, depth=-3.0)

Initialize components for Routine “Feedback”

FeedbackClock = core.Clock()
#msg variable just needs some value at start
msg=‘doh’
Practice_feedback_msg = visual.TextStim(win=win, name=‘Practice_feedback_msg’,
text=‘default text’,
font=‘Arial’,
pos=(0, 0), height=0.1, wrapWidth=None, ori=0,
color=‘white’, colorSpace=‘rgb’, opacity=1,
languageStyle=‘LTR’,
depth=-1.0);

Create some handy timers

globalClock = core.Clock() # to track the time since experiment started
routineTimer = core.CountdownTimer() # to track time remaining of each (non-slip) routine

------Prepare to start Routine “Shapelabelpairs”-------

t = 0
ShapelabelpairsClock.reset() # clock
frameN = -1
continueRoutine = True

update component parameters for each repeat

shapelabelpairs = event.BuilderKeyResponse()

keep track of which components have finished

ShapelabelpairsComponents = [imageShape, shapelabelpairs]
for thisComponent in ShapelabelpairsComponents:
if hasattr(thisComponent, ‘status’):
thisComponent.status = NOT_STARTED

-------Start Routine “Shapelabelpairs”-------

while continueRoutine:
# get current time
t = ShapelabelpairsClock.getTime()
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame

# *imageShape* updates
if t >= 0.0 and imageShape.status == NOT_STARTED:
    # keep track of start time/frame for later
    imageShape.tStart = t
    imageShape.frameNStart = frameN  # exact frame index
    imageShape.setAutoDraw(True)
frameRemains = 0.0 + 1.0- win.monitorFramePeriod * 0.75  # most of one frame period left
if imageShape.status == STARTED and t >= frameRemains:
    imageShape.setAutoDraw(False)

# *shapelabelpairs* updates
if t >= 0.0 and shapelabelpairs.status == NOT_STARTED:
    # keep track of start time/frame for later
    shapelabelpairs.tStart = t
    shapelabelpairs.frameNStart = frameN  # exact frame index
    shapelabelpairs.status = STARTED
    # keyboard checking is just starting
    win.callOnFlip(shapelabelpairs.clock.reset)  # t=0 on next screen flip
    event.clearEvents(eventType='keyboard')
if shapelabelpairs.status == STARTED:
    theseKeys = event.getKeys()
    
    # check for quit:
    if "escape" in theseKeys:
        endExpNow = True
    if len(theseKeys) > 0:  # at least one key was pressed
        if shapelabelpairs.keys == []:  # then this was the first keypress
            shapelabelpairs.keys = theseKeys[0]  # just the first key pressed
            shapelabelpairs.rt = shapelabelpairs.clock.getTime()
            # a response ends the routine
            continueRoutine = False

# check if all components have finished
if not continueRoutine:  # a component has requested a forced-end of Routine
    break
continueRoutine = False  # will revert to True if at least one component still running
for thisComponent in ShapelabelpairsComponents:
    if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
        continueRoutine = True
        break  # at least one component has not yet finished

# check for quit (the Esc key)
if endExpNow or event.getKeys(keyList=["escape"]):
    core.quit()

# refresh the screen
if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
    win.flip()

-------Ending Routine “Shapelabelpairs”-------

for thisComponent in ShapelabelpairsComponents:
if hasattr(thisComponent, “setAutoDraw”):
thisComponent.setAutoDraw(False)

check responses

if shapelabelpairs.keys in [’’, , None]: # No response was made
shapelabelpairs.keys=None
thisExp.addData(‘shapelabelpairs.keys’,shapelabelpairs.keys)
if shapelabelpairs.keys != None: # we had a response
thisExp.addData(‘shapelabelpairs.rt’, shapelabelpairs.rt)
thisExp.nextEntry()

the Routine “Shapelabelpairs” was not non-slip safe, so reset the non-slip timer

routineTimer.reset()

------Prepare to start Routine “InstrTask”-------

t = 0
InstrTaskClock.reset() # clock
frameN = -1
continueRoutine = True

update component parameters for each repeat

key_resp_InstrTask = event.BuilderKeyResponse()

keep track of which components have finished

InstrTaskComponents = [InstrTask_2, key_resp_InstrTask]
for thisComponent in InstrTaskComponents:
if hasattr(thisComponent, ‘status’):
thisComponent.status = NOT_STARTED

-------Start Routine “InstrTask”-------

while continueRoutine:
# get current time
t = InstrTaskClock.getTime()
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame

# *InstrTask_2* updates
if t >= 0.0 and InstrTask_2.status == NOT_STARTED:
    # keep track of start time/frame for later
    InstrTask_2.tStart = t
    InstrTask_2.frameNStart = frameN  # exact frame index
    InstrTask_2.setAutoDraw(True)

# *key_resp_InstrTask* updates
if t >= 0.0 and key_resp_InstrTask.status == NOT_STARTED:
    # keep track of start time/frame for later
    key_resp_InstrTask.tStart = t
    key_resp_InstrTask.frameNStart = frameN  # exact frame index
    key_resp_InstrTask.status = STARTED
    # keyboard checking is just starting
    event.clearEvents(eventType='keyboard')
if key_resp_InstrTask.status == STARTED:
    theseKeys = event.getKeys()
    
    # check for quit:
    if "escape" in theseKeys:
        endExpNow = True
    if len(theseKeys) > 0:  # at least one key was pressed
        # a response ends the routine
        continueRoutine = False

# check if all components have finished
if not continueRoutine:  # a component has requested a forced-end of Routine
    break
continueRoutine = False  # will revert to True if at least one component still running
for thisComponent in InstrTaskComponents:
    if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
        continueRoutine = True
        break  # at least one component has not yet finished

# check for quit (the Esc key)
if endExpNow or event.getKeys(keyList=["escape"]):
    core.quit()

# refresh the screen
if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
    win.flip()

-------Ending Routine “InstrTask”-------

for thisComponent in InstrTaskComponents:
if hasattr(thisComponent, “setAutoDraw”):
thisComponent.setAutoDraw(False)

the Routine “InstrTask” was not non-slip safe, so reset the non-slip timer

routineTimer.reset()

set up handler to look after randomisation of conditions etc

Trials = data.TrialHandler(nReps=1, method=‘random’,
extraInfo=expInfo, originPath=-1,
trialList=data.importConditions(‘Conditions_2.xlsx’, selection=‘0:60’),
seed=None, name=‘Trials’)
thisExp.addLoop(Trials) # add the loop to the experiment
thisTrial = Trials.trialList[0] # so we can initialise stimuli with some values

abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)

if thisTrial != None:
for paramName in thisTrial:
exec(’{} = thisTrial[paramName]’.format(paramName))

for thisTrial in Trials:
currentLoop = Trials
# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)
if thisTrial != None:
for paramName in thisTrial:
exec(’{} = thisTrial[paramName]’.format(paramName))

# ------Prepare to start Routine "Practicetrials"-------
t = 0
PracticetrialsClock.reset()  # clock
frameN = -1
continueRoutine = True
# update component parameters for each repeat
Practice_Resp = event.BuilderKeyResponse()
Picture_trial.setImage(Picture)
Label_trial.setImage(Label)
# keep track of which components have finished
PracticetrialsComponents = [Fix, Practice_Resp, Picture_trial, Label_trial]
for thisComponent in PracticetrialsComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

# -------Start Routine "Practicetrials"-------
while continueRoutine:
    # get current time
    t = PracticetrialsClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame
    
    # *Fix* updates
    if t >= 0.0 and Fix.status == NOT_STARTED:
        # keep track of start time/frame for later
        Fix.tStart = t
        Fix.frameNStart = frameN  # exact frame index
        Fix.setAutoDraw(True)
    
    # *Practice_Resp* updates
    if t >= 0.0 and Practice_Resp.status == NOT_STARTED:
        # keep track of start time/frame for later
        Practice_Resp.tStart = t
        Practice_Resp.frameNStart = frameN  # exact frame index
        Practice_Resp.status = STARTED
        # keyboard checking is just starting
        win.callOnFlip(Practice_Resp.clock.reset)  # t=0 on next screen flip
        event.clearEvents(eventType='keyboard')
    if Practice_Resp.status == STARTED:
        theseKeys = event.getKeys(keyList=['2', '3'])
        
        # check for quit:
        if "escape" in theseKeys:
            endExpNow = True
        if len(theseKeys) > 0:  # at least one key was pressed
            if Practice_Resp.keys == []:  # then this was the first keypress
                Practice_Resp.keys = theseKeys[0]  # just the first key pressed
                Practice_Resp.rt = Practice_Resp.clock.getTime()
                # was this 'correct'?
                if (Practice_Resp.keys == str(CorAns)) or (Practice_Resp.keys == CorAns):
                    Practice_Resp.corr = 1
                else:
                    Practice_Resp.corr = 0
                # a response ends the routine
                continueRoutine = False
    
    # *Picture_trial* updates
    if t >= 1.0 and Picture_trial.status == NOT_STARTED:
        # keep track of start time/frame for later
        Picture_trial.tStart = t
        Picture_trial.frameNStart = frameN  # exact frame index
        Picture_trial.setAutoDraw(True)
    frameRemains = 1.0 + 0.20- win.monitorFramePeriod * 0.75  # most of one frame period left
    if Picture_trial.status == STARTED and t >= frameRemains:
        Picture_trial.setAutoDraw(False)
    
    # *Label_trial* updates
    if t >= 1.0 and Label_trial.status == NOT_STARTED:
        # keep track of start time/frame for later
        Label_trial.tStart = t
        Label_trial.frameNStart = frameN  # exact frame index
        Label_trial.setAutoDraw(True)
    frameRemains = 1.0 + 0.20- win.monitorFramePeriod * 0.75  # most of one frame period left
    if Label_trial.status == STARTED and t >= frameRemains:
        Label_trial.setAutoDraw(False)
    
    # check if all components have finished
    if not continueRoutine:  # a component has requested a forced-end of Routine
        break
    continueRoutine = False  # will revert to True if at least one component still running
    for thisComponent in PracticetrialsComponents:
        if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
            continueRoutine = True
            break  # at least one component has not yet finished
    
    # check for quit (the Esc key)
    if endExpNow or event.getKeys(keyList=["escape"]):
        core.quit()
    
    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()

# -------Ending Routine "Practicetrials"-------
for thisComponent in PracticetrialsComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)
# check responses
if Practice_Resp.keys in ['', [], None]:  # No response was made
    Practice_Resp.keys=None
    # was no response the correct answer?!
    if str(CorAns).lower() == 'none':
       Practice_Resp.corr = 1;  # correct non-response
    else:
       Practice_Resp.corr = 0;  # failed to respond (incorrectly)
# store data for Trials (TrialHandler)
Trials.addData('Practice_Resp.keys',Practice_Resp.keys)
Trials.addData('Practice_Resp.corr', Practice_Resp.corr)
if Practice_Resp.keys != None:  # we had a response
    Trials.addData('Practice_Resp.rt', Practice_Resp.rt)
# the Routine "Practicetrials" was not non-slip safe, so reset the non-slip timer
routineTimer.reset()

# ------Prepare to start Routine "Feedback"-------
t = 0
FeedbackClock.reset()  # clock
frameN = -1
continueRoutine = True
routineTimer.add(1.500000)
# update component parameters for each repeat
if Practice_Resp == CorAns:
     msg = 'Correct'
else:
   msg = 'Sorry, Incorrect'
print("keys: %r" %(Practice_Resp))
print("CorAns: %r" %(CorAns))
print(CorAns == Practice_Resp.keys)
print(str(CorAns) == Practice_Resp.keys)
Practice_feedback_msg.setText(msg)
# keep track of which components have finished
FeedbackComponents = [Practice_feedback_msg]
for thisComponent in FeedbackComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

# -------Start Routine "Feedback"-------
while continueRoutine and routineTimer.getTime() > 0:
    # get current time
    t = FeedbackClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame
    
    
    # *Practice_feedback_msg* updates
    if t >= 0.5 and Practice_feedback_msg.status == NOT_STARTED:
        # keep track of start time/frame for later
        Practice_feedback_msg.tStart = t
        Practice_feedback_msg.frameNStart = frameN  # exact frame index
        Practice_feedback_msg.setAutoDraw(True)
    frameRemains = 0.5 + 1.0- win.monitorFramePeriod * 0.75  # most of one frame period left
    if Practice_feedback_msg.status == STARTED and t >= frameRemains:
        Practice_feedback_msg.setAutoDraw(False)
    
    # check if all components have finished
    if not continueRoutine:  # a component has requested a forced-end of Routine
        break
    continueRoutine = False  # will revert to True if at least one component still running
    for thisComponent in FeedbackComponents:
        if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
            continueRoutine = True
            break  # at least one component has not yet finished
    
    # check for quit (the Esc key)
    if endExpNow or event.getKeys(keyList=["escape"]):
        core.quit()
    
    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()

# -------Ending Routine "Feedback"-------
for thisComponent in FeedbackComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)

thisExp.nextEntry()

completed 1 repeats of ‘Trials’

these shouldn’t be strictly necessary (should auto-save)

thisExp.saveAsWideText(filename+’.csv’)
thisExp.saveAsPickle(filename)
logging.flush()

make sure everything is closed down

thisExp.abort() # or data files will save again on exit
win.close()
core.quit()

Sorry for the long message, but I’ve tried to provide as much detail as I can to assist with your answer!

Kind regards,
Tasha

Hahaha! Sorry that my images included both my screens! I should have checked that ahead of time!

Hi Tasha,

If I’m not mistaken (sorry, the relevant information was a bit hard to find…), the issue is this:

if Practice_Resp == CorAns:
msg = ‘Correct’
else:
msg = ‘Sorry, Incorrect’

The simple solution:

if Practice_Resp.corr == 1:
    msg = ‘Correct’
else:
    msg = ‘Sorry, Incorrect’

You could compare the correct key to the key that was pressed, but then you would need to use this:

if Practice_Resp.keys[0] == CorAns:
    msg = ‘Correct’
else:
    msg = ‘Sorry, Incorrect’

Hope this helps.

Jan

2 Likes

Thanks so much – I will try this today.

Sorry that it was confusing…it is always hard to know how much information to give especially as someone new to this system.

Kind regards,

Tasha

The final one work! :star_struck: