psychopy.org | Reference | Downloads | Github

Time duration of mouse click and add dynamic risky outcome to that duration

Hi all.
I am really new to Psychopy and Python and have to code a risk decision making task using Psychopy (variation of Balloon Analogue Risk Task). My task basically asks participants to click on any one of three rectangles (left/mid/rightButton) on free trials, or the correct one on forced trials. The choice availability is indicated with the rectangle’s colour turning yellow. The tricky bit is that, like inflating a balloon, we ask them to hold on the mouse instead of just clicking on the rectangle they want, and the longer they hold it, the bigger the potential reward, but also the bigger the chance of losing all reward (each rectangle has a different rate of reward/risk incrementation). I managed to get the appearance and trial conditions of the 3 stages of my study (between trial waiting - trial - reward (if won)) set up alright with builder but now got really stuck after I go into coding the bit where I determine reward/risk outcomes. I checked that the bit of code I wrote for determining if the choice (‘anyclick’) made was correct (esp for forced trials), and I think until then the code works fine. But whenever I attempt to add in timer to time the duration of the mouse click, the program seems to be stuck between/within loops. I have made versions after versions to try to find the problem in my loops, but maybe it is just because my code is way too complex and inefficient.

Here is the failed code - with my print commands I find it is stuck and only printed ‘step 1’ (previous attempts I have also gotten infinite loop between step 2 and 4, step 2 and 8)
(I think I should use while loop before ‘if buttons != prevButtonState:’ to track mouse click/release, but somehow the programmed still get stuck and only printed ‘step1’). Would really appreciate any comments or suggestions! Thank you in advance.

-------Run Routine “trial”-------

while continueRoutine:
    # get current time
    t = trialClock.getTime()
    tThisFlip = win.getFutureFlipTime(clock=trialClock)
    tThisFlipGlobal = win.getFutureFlipTime(clock=None)
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame
    
    # *leftbutton* updates
    if leftbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        leftbutton.frameNStart = frameN  # exact frame index
        leftbutton.tStart = t  # local t and not account for scr refresh
        leftbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(leftbutton, 'tStartRefresh')  # time at next scr refresh
        leftbutton.setAutoDraw(True)
    
    # *midbutton* updates
    if midbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        midbutton.frameNStart = frameN  # exact frame index
        midbutton.tStart = t  # local t and not account for scr refresh
        midbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(midbutton, 'tStartRefresh')  # time at next scr refresh
        midbutton.setAutoDraw(True)
    
    # *rightbutton* updates
    if rightbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        rightbutton.frameNStart = frameN  # exact frame index
        rightbutton.tStart = t  # local t and not account for scr refresh
        rightbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(rightbutton, 'tStartRefresh')  # time at next scr refresh
        rightbutton.setAutoDraw(True)
    # *anyclick* updates
    if anyclick.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        anyclick.frameNStart = frameN  # exact frame index
        anyclick.tStart = t  # local t and not account for scr refresh
        anyclick.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(anyclick, 'tStartRefresh')  # time at next scr refresh
        anyclick.status = STARTED
        anyclick.mouseClock.reset()
        prevButtonState = anyclick.getPressed()  # if button is down already this ISN'T a new click
    if anyclick.status == STARTED:  # only update if started and not finished!
        x, y = anyclick.getPos()
        anyclick.x.append(x)
        anyclick.y.append(y)
        buttons = anyclick.getPressed()
        anyclick.leftButton.append(buttons[0])
        anyclick.midButton.append(buttons[1])
        anyclick.rightButton.append(buttons[2])
        
        gotclick=False
        gotValidClick=False
        unclicked=False
        Attempt1=True
        print("step1")

    if buttons != prevButtonState:  # button state changed?
        prevButtonState = buttons
        if sum(buttons) > 0:
            t0=time.clock()
            gotValidClick = False
            gotclick = True
            print("step2")
        if sum(buttons) == 0 and gotclick == True:
            t1=time.clock()
            tpoke=t1-t0
            unclicked = True
            pokeduration = visual.TextStim(win=win, name='poke duration',
                    text=str(tpoke),
                    font='Arial',
                    units='norm', pos=(0, 0), height=0.07, wrapWidth=None, ori=0, 
                    color='white', colorSpace='rgb', opacity=1, 
                    languageStyle='LTR',
                    depth=0.0);
            pokeduration.setAutoDraw(True)
            print("step3:"+tpoke)

    while gotclick == True and gotValidClick == False:
        if thisTrial['contingency']=='ll':
            for obj in LLcorAns:
                if obj.contains(anyclick):
                    gotValidClick = True
                    anyclick.clicked_name.append(obj.name)
                    anyclick.clicked_pos.append(obj.pos)
                    anyclick.time.append(anyclick.mouseClock.getTime())
                    correct.append(obj.name)
                    correcttime.append(anyclick.mouseClock.getTime())
                    print("step4")
                    break

                else:
                     gotValidClick = False
                     incorrect.append(obj.name)
                     incorrecttime.append(anyclick.mouseClock.getTime())
                     print("step5")
                     continue
            break

        if thisTrial['contingency']=='mm':
            for obj in MMcorAns:
                if obj.contains(anyclick):
                    gotValidClick = True
                    flag=False
                    anyclick.clicked_name.append(obj.name)
                    anyclick.clicked_pos.append(obj.pos)
                    anyclick.time.append(anyclick.mouseClock.getTime())
                    correct.append(obj.name)
                    correcttime.append(anyclick.mouseClock.getTime())
                    print("step6")
                    break
                
                else:
                     gotValidClick = False
                     incorrect.append(obj.name)
                     incorrecttime.append(anyclick.mouseClock.getTime())
                     print("step7")
                     continue 
            break
        if thisTrial['contingency']=='hh':
            for obj in HHcorAns:
                if obj.contains(anyclick):
                    gotValidClick = True
                    flag=False
                    anyclick.clicked_name.append(obj.name)
                    anyclick.clicked_pos.append(obj.pos)
                    anyclick.time.append(anyclick.mouseClock.getTime())
                    correct.append(obj.name)
                    correcttime.append(anyclick.mouseClock.getTime())
                    print("step8")
                    break
                else:
                     gotValidClick = False
                     incorrect.append(obj.name)
                     incorrecttime.append(anyclick.mouseClock.getTime())
                     print("step9")
                     continue
            break
        if thisTrial['contingency']=='free':
            for obj in FFcorAns:
                if obj.contains(anyclick):
                    gotValidClick = True
                    flag=False
                    anyclick.clicked_name.append(obj.name)
                    anyclick.clicked_pos.append(obj.pos)
                    anyclick.time.append(anyclick.mouseClock.getTime())
                    correct.append(obj.name)
                    correcttime.append(anyclick.mouseClock.getTime())
                    print("step10")
                    break

                else:
                     gotValidClick = False
                     incorrect.append(obj.name)
                     incorrecttime.append(anyclick.mouseClock.getTime())
                     print("step11")
                     continue
            break
                
    while True:
        if gotValidClick == True and unclicked == True:
            print("step12")
            continueRoutine = False
            break
                    
    
    # *collectbutton* updates
    if collectbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        collectbutton.frameNStart = frameN  # exact frame index
        collectbutton.tStart = t  # local t and not account for scr refresh
        collectbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(collectbutton, 'tStartRefresh')  # time at next scr refresh
        collectbutton.setAutoDraw(True)
    
    # check for quit (typically the Esc key)
    if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]):
        core.quit()
    
    # 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
    
    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()

Here is a code for trial that worked without the timing feature.

# -------Run Routine "trial"-------
while continueRoutine:
    # get current time
    t = trialClock.getTime()
    tThisFlip = win.getFutureFlipTime(clock=trialClock)
    tThisFlipGlobal = win.getFutureFlipTime(clock=None)
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame
    
    # *leftbutton* updates
    if leftbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        leftbutton.frameNStart = frameN  # exact frame index
        leftbutton.tStart = t  # local t and not account for scr refresh
        leftbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(leftbutton, 'tStartRefresh')  # time at next scr refresh
        leftbutton.setAutoDraw(True)
    
    # *midbutton* updates
    if midbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        midbutton.frameNStart = frameN  # exact frame index
        midbutton.tStart = t  # local t and not account for scr refresh
        midbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(midbutton, 'tStartRefresh')  # time at next scr refresh
        midbutton.setAutoDraw(True)
    
    # *rightbutton* updates
    if rightbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        rightbutton.frameNStart = frameN  # exact frame index
        rightbutton.tStart = t  # local t and not account for scr refresh
        rightbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(rightbutton, 'tStartRefresh')  # time at next scr refresh
        rightbutton.setAutoDraw(True)
    # *anyclick* updates
    if anyclick.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        anyclick.frameNStart = frameN  # exact frame index
        anyclick.tStart = t  # local t and not account for scr refresh
        anyclick.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(anyclick, 'tStartRefresh')  # time at next scr refresh
        anyclick.status = STARTED
        anyclick.mouseClock.reset()
        prevButtonState = anyclick.getPressed()  # if button is down already this ISN'T a new click
    if anyclick.status == STARTED:  # only update if started and not finished!
        x, y = anyclick.getPos()
        anyclick.x.append(x)
        anyclick.y.append(y)
        buttons = anyclick.getPressed()
        anyclick.leftButton.append(buttons[0])
        anyclick.midButton.append(buttons[1])
        anyclick.rightButton.append(buttons[2])
        buttons = anyclick.getPressed()
        if buttons != prevButtonState:  # button state changed?
            prevButtonState = buttons
            if sum(buttons) > 0:  # state changed to a new click
                # check if the mouse was inside our 'clickable' objects
                gotValidClick = False
                if thisTrial['contingency']=='ll':
                    for obj in LLcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                elif thisTrial['contingency']=='mm':
                    for obj in MMcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                elif thisTrial['contingency']=='hh':
                    for obj in HHcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                elif thisTrial['contingency']=='free':
                    for obj in FFcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                if gotValidClick:  # abort routine on response
                    continueRoutine = False
    
    # *collectbutton* updates
    if collectbutton.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
        # keep track of start time/frame for later
        collectbutton.frameNStart = frameN  # exact frame index
        collectbutton.tStart = t  # local t and not account for scr refresh
        collectbutton.tStartRefresh = tThisFlipGlobal  # on global time
        win.timeOnFlip(collectbutton, 'tStartRefresh')  # time at next scr refresh
        collectbutton.setAutoDraw(True)
    
    # check for quit (typically the Esc key)
    if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]):
        core.quit()
    
    # 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
    
    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()

After days of meltdown I managed to get the timing working. If anyone needs this in the future, this is what i have done to get it running. Not exactly sure what made the old one crush but this new code is as simple and effective as i can get it, and it has given me feed back with print commands as expected.

gotclick=False
gotValidClick=False
unclicked=False
attempt1=False
buttons = anyclick.getPressed()
print(‘step1a’)
if buttons != prevButtonState: # button state changed?
prevButtonState = buttons
print(‘step1b’)
if sum(buttons) > 0: # state changed to a new click
# check if the mouse was inside our ‘clickable’ objects
gotValidClick = False
t0=time.clock()
gotclick=True
print(‘step2’)

            if sum(buttons) ==0:
               t1=time.clock()
               tpoke=t1-t0
               gotValidClick=False
               unclicked = True
               pokeduration = visual.TextStim(win=win, name='poke duration',
                        text=str(tpoke),
                        font='Arial',
                        units='norm', pos=(0, 0), height=0.07, wrapWidth=None, ori=0, 
                        color='white', colorSpace='rgb', opacity=1, 
                        languageStyle='LTR',
                        depth=0.0);
               pokeduration.setAutoDraw(True)
               attempt1 = True
               print("step3:"+str(tpoke))
               gotclick = False 

        while attempt1 == True:
                if thisTrial['contingency']=='ll':    #check if response was made correctly
                    for obj in LLcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                            print("step4")
                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                             print("step5")
                elif thisTrial['contingency']=='mm':
                    for obj in MMcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                            print("step6")

                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                             print("step7")
                elif thisTrial['contingency']=='hh':
                    for obj in HHcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                            print("step8")

                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                             print("step9")
                elif thisTrial['contingency']=='free':
                    for obj in FFcorAns:
                        if obj.contains(anyclick):
                            gotValidClick = True
                            anyclick.clicked_name.append(obj.name)
                            anyclick.clicked_pos.append(obj.pos)
                            anyclick.time.append(anyclick.mouseClock.getTime())
                            correct.append(obj.name)
                            correcttime.append(anyclick.mouseClock.getTime())
                            print("step10")

                        else:
                             gotValidClick = False
                             anyclick.clicked_name.append(obj.name)
                             anyclick.clicked_pos.append(obj.pos)
                             anyclick.time.append(anyclick.mouseClock.getTime())
                             incorrect.append(obj.name)
                             incorrecttime.append(anyclick.mouseClock.getTime())
                             print("step11")
                if gotValidClick:  # abort routine on response
                    print("step12")
                    attempt1=False
                    continueRoutine = False
1 Like