psychopy.org | Reference | Downloads | Github

Random block order and pause after each block

OS : MacOS Mojave
PsychoPy version : 2021 2.3
What are you trying to achieve?: I am running an fMRI experiment. I need to randomize the order of blocks. However, if for some reason the experiment needs to stop in the middle, I would like to find a way to stop the code in the middle and pick back up where it left off.

What did you try to make it work?:
So far, I was able to randomize the order of my blocks using a for loop, where I randomize the order of the four blocks (only one shown).

r = list(range(1,5))
random.shuffle(r) #randomly shuffles the block order 

print(r)

for i in r:
    if i ==1:
#no switch - one block type 
        noswitch_log = noswitch(win, fixation, i, image, scenes_df, words_df, num_scenes, num_words, j, curr_word, curr_scene, word, word_item, scene_item_indoor, scene_item_outdoor, scene_list, scene_indoor,scene_outdoor)

        noswitch_log['subnum'] = int(subnum)
        output_noswitch = os.path.join(sub_folder, 'sub{}_noswitch_run{}.csv'.format(subnum, i))
        noswitch_log.to_csv(output_noswitch, index=False)
        
        
        math_log = math_distraction(win, fixation, i, cur_equation, math)

        math_log['subnum'] = int(subnum)
        output_math = os.path.join(sub_folder, 'sub{}_math_run{}.csv'.format(subnum, i))
        math_log.to_csv(output_math, index=False)

    if i ==2: #second block type ... 
.......

If I need to stop for any reason, I’m not sure how I would start from the second, or third block, for example, without starting from the beginning of the script. A for loop might not be the best way to do this, so open to other ways of randomizing these blocks! Thanks!!

In this case it seems that simply saving the block order variable r can help.

You can for example save it to a text file that will be saved locally on the computer. Then, each time you run your script you can see if such a text file exists. If it does, take the information from that file to be your block order. If it does not, continue as usual and start the experiment from scratch.

import os # package to interact with local Opersating System

filename = 'block_order_file.txt'

# First see if a file already exists
if os.path.exists(filename ):  # if it exists already
  with open(filename, 'r') as f: # open the file
    r = f.read(filename) # and read it
    r = eval(r) # in the file it is considered a string, so convert it back to a list here
else:                                    # if it does not exist
  r = list(range(1,5))
  random.shuffle(r) #randomly shuffles the block order

print(r)

So far so good. This opens the file ONLY if it exists. If it does not exist, it will make a new trial order from scratch.

Now, from here we can continue running the script. Then, whenever we complete a block, we can update the block_order_file.txt file, so that if we stop now and start again, we will not do this block again but instead from the next block.


for i in r:
    if i ==1:
       # do everything in your block and add this part at the end
       r = r[1:] # take all elements from r EXCEPT the first one
       with open(filename, 'r') as f: # open the file again and overwrite it 
         f.write(str(r))  

Now, these last lines in the block could be copy-pasted to each block, but we can also simply turn it into a function and call it at the end of each block

def write_block_file(filename, r):
  r = r[1:] # take all elements from r EXCEPT the first one
  with open(filename, 'r') as f: # open the file again and overwrite it 
    f.write(str(r))
  return r # return the new r which is now without the block we just completed


for i in r:
  if i == 1:
     # do your block
     r = write_block_file(filename, r) # writes the file and updates r

Then, when a participants has completed all the blocks and the experiment is finished, we can simply remove the existing block_order_file.txt. It should be empty by now, anyway

os.remove(filename) # remove the file

I didn’t test this code but it should work. There might be a minor type somewhere. Hope it helps!

2 Likes

That worked great, thanks!!

Two minor changes if anyone is using this in the future:

if os.path.exists(filename ): # if it exists already
with open(filename, ‘r’) as f: # open the file
r = f.read() # and read it
r = eval(r)

with open(filename, ‘w’) as f: # open the file again and overwrite it
f.write(str(r))