psychopy.org | Reference | Downloads | Github

Conditional looping problem

hello, I am trying to make it so the participant has to repeat the set of practice trials again if they get less than 85% correct,
so far it is running through the trials in a loop with the % score calculated after this loop
i presume i will need to use an if/else statement after this score is calculated but have no idea what i can put in this statement to make the loop repeat - and have only managed to find builder view examples online.
i think it would look something like this:

if nCorr<85:

else:

with nCorr being the percentage correct

any help would be much appreciated!

You would have to put your current loop inside another loop, but rather than a for loop, it would have to be a while loop. while loops repeat as long as the condition you provide is true. So one option for you could be:

runPractice = True

while runPractice:
    for trial in practiceTrials:
        # This for loop should be the same as you have already
    
    # then after your for loop, you check if they got the necessary amount right,
    # and if so you set runPractice false
    if nCorr<85:
        runPractice = False

Note that while-loops can run forever if for some reason the condition for the while loop never turns false, so it would be a good idea to have some other way of terminating the experiment.

1 Like

while loops, of course!
its working partially (as in it moves on if you get 85%+) but its having a problem with looping back to the beginning, and is instead looping between my accuracy statement (“you have got _% correct”) and try again statement over and over.
here’s the basic structure of the code

while runPractice: 
    for trial in practiceTrials:
        #trial details 
    nCorr=#accuracy calculation
    fmsg.setText("you got %i %% \n of trials correct" %(nCorr))
    fmsg.draw()
    win.flip()
    core.wait(2.0)
    if nCorr <85:
        fmsg.setText("sorry, try again!")
        fmsg.draw() 
        win.flip() 
        core.wait(2.0) 
    else:
        runPractice=False

I think this may be an indentation problem as this is on the same level as the for and if statements, but i cant work out how to resolve this

also don’t worry, I’ve got an escape key in there for that very reason

Thanks for the help!

Just a hunch, maybe practiceTrials is empty after the first run? Add this line before your for loop:

print("There are {0} trials in practice trials".format(len(praticeTrials)))
for trial in practiceTrials:

Maybe there’s nothing in there so nothing happens…

But honestly I didn’t quite understand your explanation of the problem. If this doesn’t fix it, could you be a little clearer about what is happening or not happening and when?

Hmm, that doesn’t seem to work, its coming up with the error:

print("There are {0} trials in practice trials".format(len(practiceTrials)))
    TypeError: object of type 'TrialHandler' has no len()

i presume this is because practiceTrials is a trial handler containing a spreadsheet rather than a variable?
(but I’m not sure - I’m quite new to PsycoPy)
so this could be the problem, but that particular method doesn’t solve it

as for explaining it better:

the experiment is a Posner style task, and successfully loops through the list of practice trials, once it gets to the end of the list of practice trials (there are 32 trials on the spreadsheet) i have programmed it to show your percentage correct.

If the participant gets less than 85% of the answers correct i would like it to display a message (I’ve used “sorry try again” in the code above), and then repeat all 32 practice trials.

but instead when it reaches this “sorry try again” screen it loops back to the “you got _% of trials correct” screen, then back to the "sorry try again screen and back to the “you got _% of trials correct” and so on…
so it seems to be looping through these feedback messages rather than the actual experiment

hope that clarifies things!

I think Daniel is right that your TrialHandler doesn’t return anything anymore - basically, since you’ve already run through your trials, if you try for trial in practiceTrials: again, this loop will run 0 times.

The easiest way to fix this (I think) would be for you to move your creation of practiceTrials into the while loop (so just before the for loop).

Note that this would “erase” your record of the participant’s response in the previous practice runs, so you may want to save that data if you need it.

I should have really thought of this when I suggested the while loop the first time around!

Ah ok, the error just means they didn’t implement a method for “len”. I’m not incredibly familiar with the TrialHandler, so anyone else reading please chime in.

The problem I’m trying to get at is that after running

for trial in practiceTrials:

once, I suspected practiceTrials is empty all subsequent times, so nothing happens after the first loop through.

Now that I’m in front of my computer I made a simple test script to see if this was the case, and yes, it turns out that you can only loop over a TrialHandler once (without further intervention).
faceCombinations.xlsx (5.3 KB)
thTest.py (1.4 KB)

So we’ve identified the problem, but actually I personally don’t have a lot of experience with the TrialHandler, so I’m going to wait for someone else to give a better answer, unless I get a chance to do a little more research later (which I of course encourage you to do as well!), in which case I’ll write back.

EDIT

Ah, sorry @jan.freyberg , I was writing this while you responded!

1 Like

Yes that was the problem, and putting the trial handler inside the loop has fixed it!
as for saving the data I’m not sure if ill need to do that as it just practice conditions - but if i do ill cross that bridge when i come to it! (i probably will when it comes to my main trials)

thank you both for your help,
i could have been stuck on this for days!

No problem, good luck with the experiment :slight_smile:

You’re welcome! (though we haven’t given a good answer, and hopefully someone else will chime in with some good advice)

But after looking (slightly) more at the files that the builder generates, it looks like the typical way things are done is that each experiment has an ExperimentHandler, which is in charge of saving data, and that the loops you add in the builder are TrialHandler objects, which are given to the ExperimentHandler with .addLoop() . So my guess would be that you’ll need to call that if you want data saved correctly, but again don’t quote me.

If you’re going to be coding experiments and using these objects, it would be worth studying the page for these in the the docs, and studying the _lastRun.py files that are generated by the builder to see how psychopy uses ExperimentHandler and TrialHandler . I’ve personally been lazy in this department so far and have just coding data saving myself, sorry I don’t have time to give you a better answer at the moment. I’m sure some better advice will be coming soon from someone!

Exactly, the iterator is exhausted after, well, iterating over it. So you should create a new one if you want to iterate once more.

It shouldn’t be necessary to use the ExperimentHandler, it just makes saving all log files easier, and provides a simple way to pickle (create a psydat file) of ALL TrialHandlers in your experiment at once. A bundle, so to speak :wink: But saving the data for each TrialHandler individually should work equally well. In fact, I rarely use the ExperimentHandler in my own studies.

1 Like