Error in giving feedback after a trial

Hi, I’ve been stuck with this problem for quite a few days now. So, every time I tried to give feedback in trial (whatever the experiments are), my responses were detected as “incorrect”, so the feedback just said that it’s wrong. I just curious why this function did not work properly on my experiment. So, I create a simple task about math, and still I never got the “correct” feedback. Because I can upload the file here, I’ll just post what I do in the builder.

In the begin experiment, I have this line:

msg=''

And in the begin routine, I have this line:

if key_resp_2.corr:
    msg='correct'
else:
    msg='wrong'

And the result in the ms. excel, the “corrAns” values and the “key_resp_2.keys" values are the same, but still the “key_resp_2.corr” values were all 0. Please anyone help me.

I also already put the code component above the text component in the feedback routine. And already set it to “every repeat”.

I’m using the latest version of psychopy, 64 bit.
Any idea for this problem?

Thanks in advance!

1 Like

In the keyboard component have you put the correct answer as $corrAns or or just corrAns?

The latter means that the correct answer is the actual key called corrAns!

I’ve post my “.psyexp” file in the old mailing list, since I can’t upload it here. Last time, Michael told me that it works fine for him, but it didn’t work for me. I don’t know whether it is a kind of bugs or not. And I’ve also tried the stroopextended experiment, and again, the feedback always show that my responses were “incorrect”.

This is what I’ve done. I also have the “corrAns” column in the ms. excel and no misspelled.

Really hope I can solve this issue.
Thank you for the response!

Puzzling. I think we can rule out any problem with your code component. The fact that key_resp_2.corr is listed as 0 in every row suggests that code isn’t the problem.

Would you mind compiling the experiment to a script and sending that here? We don’t normally ask for that (it isn’t normally the easy way to find errors) but, if the experiment was working correctly on @m-macaskill’s machine and not yours, I wonder if the script is being compiled incorrectly on your computer.

This is what I have in the coder. I’m a newbie in phyton, so I don’t understand if maybe there’s something wrong. Thank you Jon!

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
This experiment was created using PsychoPy2 Experiment Builder (v1.84.0rc5),
    on Wed Aug  3 15:47:18 2016
If you publish work using this script please cite the PsychoPy publications:
    Peirce, JW (2007) PsychoPy - Psychophysics software in Python.
        Journal of Neuroscience Methods, 162(1-2), 8-13.
    Peirce, JW (2009) Generating stimuli for neuroscience using PsychoPy.
        Frontiers in Neuroinformatics, 2:10. doi: 10.3389/neuro.11.010.2008
"""

from __future__ import absolute_import, division

import psychopy
psychopy.useVersion('latest')

from psychopy import locale_setup, visual, core, data, event, logging, sound, gui
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__)).decode(sys.getfilesystemencoding())
os.chdir(_thisDir)

# Store info about the experiment session
expName = 'b'  # from the Builder filename that created this script
expInfo = {u'session': u'001', u'participant': u''}
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=None,
    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=(1440, 900), 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 "trial"
trialClock = core.Clock()
text = visual.TextStim(win=win, name='text',
    text='default text',
    font=u'Arial',
    pos=(0, 0), height=72, wrapWidth=None, ori=0, 
    color=u'white', colorSpace='rgb', opacity=1,
    depth=0.0);

# Initialize components for Routine "feedback"
feedbackClock = core.Clock()
msg=''
text_2 = visual.TextStim(win=win, name='text_2',
    text='default text',
    font=u'Arial',
    pos=(0, 0), height=72, wrapWidth=None, ori=0, 
    color=u'white', colorSpace='rgb', opacity=1,
    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 

# set up handler to look after randomisation of conditions etc
trials = data.TrialHandler(nReps=1, method='fullRandom', 
    extraInfo=expInfo, originPath=-1,
    trialList=data.importConditions(u'Test 3.xlsx'),
    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.keys():
        exec(paramName + '= thisTrial.' + paramName)

for thisTrial in trials:
    currentLoop = trials
    # abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)
    if thisTrial != None:
        for paramName in thisTrial.keys():
            exec(paramName + '= thisTrial.' + paramName)
    
    # ------Prepare to start Routine "trial"-------
    t = 0
    trialClock.reset()  # clock
    frameN = -1
    continueRoutine = True
    routineTimer.add(2.000000)
    # update component parameters for each repeat
    text.setText(Stimulus1)
    key_resp_2 = event.BuilderKeyResponse()
    # keep track of which components have finished
    trialComponents = [text, key_resp_2]
    for thisComponent in trialComponents:
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED
    
    # -------Start Routine "trial"-------
    while continueRoutine and routineTimer.getTime() > 0:
        # get current time
        t = trialClock.getTime()
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
        # update/draw components on each frame
        
        # *text* updates
        if t >= 0.0 and text.status == NOT_STARTED:
            # keep track of start time/frame for later
            text.tStart = t
            text.frameNStart = frameN  # exact frame index
            text.setAutoDraw(True)
        frameRemains = 0.0 + 2- win.monitorFramePeriod * 0.75  # most of one frame period left
        if text.status == STARTED and t >= frameRemains:
            text.setAutoDraw(False)
        
        # *key_resp_2* updates
        if t >= 0.0 and key_resp_2.status == NOT_STARTED:
            # keep track of start time/frame for later
            key_resp_2.tStart = t
            key_resp_2.frameNStart = frameN  # exact frame index
            key_resp_2.status = STARTED
            # keyboard checking is just starting
            win.callOnFlip(key_resp_2.clock.reset)  # t=0 on next screen flip
            event.clearEvents(eventType='keyboard')
        frameRemains = 0.0 + 2- win.monitorFramePeriod * 0.75  # most of one frame period left
        if key_resp_2.status == STARTED and t >= frameRemains:
            key_resp_2.status = STOPPED
        if key_resp_2.status == STARTED:
            theseKeys = event.getKeys(keyList=['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'])
            
            # check for quit:
            if "escape" in theseKeys:
                endExpNow = True
            if len(theseKeys) > 0:  # at least one key was pressed
                if key_resp_2.keys == []:  # then this was the first keypress
                    key_resp_2.keys = theseKeys[0]  # just the first key pressed
                    key_resp_2.rt = key_resp_2.clock.getTime()
                    # was this 'correct'?
                    if (key_resp_2.keys == str(corrAns)) or (key_resp_2.keys == corrAns):
                        key_resp_2.corr = 1
                    else:
                        key_resp_2.corr = 0
                    # 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 trialComponents:
            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 "trial"-------
    for thisComponent in trialComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)
    # check responses
    if key_resp_2.keys in ['', [], None]:  # No response was made
        key_resp_2.keys=None
    # was no response the correct answer?!
    if str(corrAns).lower() == 'none':
       key_resp_2.corr = 1  # correct non-response
    else:
       key_resp_2.corr = 0  # failed to respond (incorrectly)
    # store data for trials (TrialHandler)
    trials.addData('key_resp_2.keys',key_resp_2.keys)
    trials.addData('key_resp_2.corr', key_resp_2.corr)
    if key_resp_2.keys != None:  # we had a response
        trials.addData('key_resp_2.rt', key_resp_2.rt)
    
    # ------Prepare to start Routine "feedback"-------
    t = 0
    feedbackClock.reset()  # clock
    frameN = -1
    continueRoutine = True
    routineTimer.add(0.500000)
    # update component parameters for each repeat
    if key_resp_2.corr:
        msg='correct'
    else:
        msg='wrong'
    text_2.setText(msg)
    # keep track of which components have finished
    feedbackComponents = [text_2]
    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
        
        
        # *text_2* updates
        if t >= 0.0 and text_2.status == NOT_STARTED:
            # keep track of start time/frame for later
            text_2.tStart = t
            text_2.frameNStart = frameN  # exact frame index
            text_2.setAutoDraw(True)
        frameRemains = 0.0 + 0.5- win.monitorFramePeriod * 0.75  # most of one frame period left
        if text_2.status == STARTED and t >= frameRemains:
            text_2.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'

# get names of stimulus parameters
if trials.trialList in ([], [None], None):
    params = []
else:
    params = trials.trialList[0].keys()
# save data for this loop
trials.saveAsExcel(filename + '.xlsx', sheetName='trials',
    stimOut=params,
    dataOut=['n','all_mean','all_std', 'all_raw'])
trials.saveAsText(filename + 'trials.csv', delim=',',
    stimOut=params,
    dataOut=['n','all_mean','all_std', 'all_raw'])

# 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()

Well the script looks fine. Maybe you could add the following code into the code component where you have your feedback checking:

print("keys: %r" %(key_resp_2.keys))
print("corrAns: %r" %(corrAns))
print(corrAns == key_resp_2.keys)

NB The %r symbol tells python print not just how the string of how the object looks (because "1" can look the same as 1) but its representation as a string or unicode or integer etc.

Thanks

Are you using the number pad or the keys on the top row of the keyboard?

Dan, the key in the data file reports 9 not num_9 so that doesn’t seem to be the issue. Is very weird :confused:

Jon, you are right you cannot sneak num_9 past, however, you can sneak 1.0 by because excel/libreoffice displays 1.0 as 1. It is quite possible that the issue is in the conditions file. My conditions file is:

corrAns
1.0
2 Likes

Good point. That should be picked up by print("%r" %corrAns)
I think we need to hear back from @Lily_Kusuma to know more

Hi Jon & Daniel,

Sorry for the late reply. I just got back home today and checked here. I’m not sure where I should paste the code, so I just attach the pic here. Should I did it like this (paste it in the begin routine) or should I paste it in another place? I tried to run the experiment by adding the code like the pic below, but still, it won’t work. So I guessed I paste the code in the wrong place.

As I mentioned before, although I change the “corrAns” to alphabet, for example ‘a’,‘b’,‘c’ etc, it still did not work, and the stroop extended experiment also did not work on my laptop here (although that experiment were using ‘left’,‘right’,‘down’). I’ve been guessing that maybe the problem is in the conditions file, but couldn’t find what it is.

Thanks for the responses! Really appreciate it.

Update:
I also had this message:
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/psychopy/data.py:4498: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
self[thisType][position[0], position[1]] = value

(Not sure what it means).

The idea was that this would output some information for us to work out what’s wrong. What was printed when you ran it this time?

Just the same as before @jon. My responses always detected as “wrong”. Should I just put the code in the begin experiment like the one I did in the picture above? Not sure if that’s the right way to do it.

No, we need to know what was printed. In the output window when the experiment finished there should have been more info from those print statements

Ah, sorry I didn’t understand. This was the output that I got after the experiment ended.

############### Running: /Users/lilykusuma/Desktop/b_lastrun.py ################
pyo version 0.7.9 (uses single precision)
2016-08-08 18:04:00.882 python[1569:79483] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/yr/2r187mzx0x1dtckhhs97zngh0000gn/T/org.psychopy.PsychoPy2.savedState
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/openpyxl/worksheet/worksheet.py:377: UserWarning: Call to deprecated function or class get_highest_column (Use the max_column propery.).
def get_highest_column(self):
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/openpyxl/worksheet/worksheet.py:350: UserWarning: Call to deprecated function or class get_highest_row (Use the max_row property).
def get_highest_row(self):
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/numpy/ma/core.py:3245: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
_data[indx] = dval
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/numpy/ma/core.py:3246: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
_mask[indx] = mval
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/psychopy/data.py:4498: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
self[thisType][position[0], position[1]] = value

That doesn’t seem to include any print statement outputs. Are you sure this is the version with that new code added? Did you run from Builder or did you accidentally go to Coder instead?

Sorry Jon, I guessed I did it wrongly before. I tried to run it again from the builder. This is what I got. What I don’t understand here is, why the corrAns has “L” letter.

############### Running: /Users/lilykusuma/Desktop/b_lastrun.py ################
pyo version 0.7.9 (uses single precision)
keys: '8’
corrAns: 8L
False
keys: '2’
corrAns: 2L
False
keys: '5’
corrAns: 5L
False
keys: '4’
corrAns: 4L
False
keys: '9’
corrAns: 9L
False
keys: '9’
corrAns: 9L
False
keys: '4’
corrAns: 4L
False
keys: '0’
corrAns: 0L
False
keys: '9’
corrAns: 9L
False
2016-08-08 18:46:00.034 python[1856:94113] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/yr/2r187mzx0x1dtckhhs97zngh0000gn/T/org.psychopy.PsychoPy2.savedState
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/openpyxl/worksheet/worksheet.py:377: UserWarning: Call to deprecated function or class get_highest_column (Use the max_column propery.).
def get_highest_column(self):
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/openpyxl/worksheet/worksheet.py:350: UserWarning: Call to deprecated function or class get_highest_row (Use the max_row property).
def get_highest_row(self):
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/numpy/ma/core.py:3245: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
_data[indx] = dval
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/numpy/ma/core.py:3246: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
_mask[indx] = mval
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/psychopy/data.py:4498: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
self[thisType][position[0], position[1]] = value

Another update:
I also tried to run another experiment. And here’s the print statement outputs. As we can see here, some of my responses, although detected as correct below, but when i ran the experiment, it just told me that my responses were all “wrong”.

############ Running: /Users/lilykusuma/Desktop/leetword_lastrun.py ############
pyo version 0.7.9 (uses single precision)
keys: 'd’
corrAns: u’d’
True
keys: 'd’
corrAns: u’d’
True
keys: 'd’
corrAns: u’d’
True
keys: 's’
corrAns: u’s’
True
keys: 'd’
corrAns: u’a’
False
keys: 'a’
corrAns: u’s’
False
keys: 'a’
corrAns: u’a’
True
keys: 'a’
corrAns: u’a’
True
keys: 'a’
corrAns: u’s’
False
2016-08-08 23:35:56.912 python[3040:146268] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/yr/2r187mzx0x1dtckhhs97zngh0000gn/T/org.psychopy.PsychoPy2.savedState
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/openpyxl/worksheet/worksheet.py:377: UserWarning: Call to deprecated function or class get_highest_column (Use the max_column propery.).
def get_highest_column(self):
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/openpyxl/worksheet/worksheet.py:350: UserWarning: Call to deprecated function or class get_highest_row (Use the max_row property).
def get_highest_row(self):
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/numpy/ma/core.py:3245: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
_data[indx] = dval
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/numpy/ma/core.py:3246: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
_mask[indx] = mval
/Applications/PsychoPy2_64bit.app/Contents/Resources/lib/python2.7/psychopy/data.py:4498: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
self[thisType][position[0], position[1]] = value

This one was different from the experiment I shared before (simple math experiment). This time, the outputs did the job well, it correctly told me whether my responses were correct/wrong, but still when I ran the experiment, it just said my responses were all wrong. I was pretty confused right now. And I also don’t know why there were “u” letter in my corrAns.

Thank you!

@daniel.e.shub 's suspicion seems to be correct, that the correct answer column in your conditions file for some reason is being interpreted as a number rather than as text. i.e. the character ‘8’ (with quotes) is not equal to the number 8 (without quotes). The L here indicates what sort of number it is (a long integer, I think).

If you are using a .xlsx conditions file, try switching to .csv, or vice versa. Excel files are more likely to have formats specified for their cells which get carried over in the import process, but on the other hand, the .csv importer we sue also sometimes does unexpected things. Try switching, anyway.

In the second example (you don’t really explain why the conditions have changed to use letters instead of numbers), the comparison is working correctly, as both the keys and the correct answer are strings (i.e. characters). Ignore the ‘u’ prefix, that just says that that particular string is encoded as Unicode. 'a' still equals u'a'.

So PsychoPy is getting the comparison correct in the keyboard component in that case. I your code says that the responses are wrong, presumably there is an error in that code.