How to loop through 2 different Excel files sequentially?

OS (e.g. Win10): Mac (Catalina 10.15.1)
PsychoPy version (e.g. 1.84.x): 3.2.4
Standard Standalone? (y/n) Y
**What are you trying to achieve?: ** Randomly displaying target pictures followed by fillers

I’m creating an experiment that shows a picture to participants and has them describe what is occurring in the picture. After each target picture (where we care about their response and will analyze it) I want to put 2-3 filler pictures so that participants can’t guess which pictures we care about their responses to so that knowledge of the similarities between those pictures won’t influence their responses.

I have the target images files all saved in an excel document and a loop that goes through them, and chooses randomly between the Left-right orientation or Right-left orientation. So if there’s 16 target pictures, there’s 32 rows in the excel document for each image file, going picture1_LR, picture1_RL, picture2_LR, picture2_RL, and so on. I wrote a short bit of code to just pick a random number (0 or 1) which chooses whether the LR or RL orientation is used so that only one is chosen (so only 16 pictures displayed total). The loop then randomizes the order these are presented in.

However, I’m not sure what the best way would be to introduce the fillers. Ideally, I’d like to have them in a separate excel document, and somehow have 2 selected after each target picture, and then go back to the next target picture I wanted to display. However I’m not sure how to put this within my main loop for the target pictures. I know I can’t have them as separate loops because then Psychopy would just loop through all the target pictures first and then loop through all the fillers, and having one main loop outside the two separate loops also doesn’t seem like the right direction to go in. Would something like a loop inside my target picture loop that runs 2 times and selects from the excel file where I have my filler image files sound like the way to go? Or is there another way of doing this that I haven’t mentioned yet?

I’m fairly new to python so if possible I would really prefer suggestions I can implement in the builder, but I understand this might be something that would require adding code to do.

Thank you!

Hi, welcome along,

This probably isn’t the ideal way to do this. Builder is structured around having each row in a conditions file correspond to a trial, so I would suggest you actually just want 16 rows in this file, with two columns of filenames (one for RL and one for LR), and then use your code to decide between which column variable to use on each trial.

Is this the best way to do this sort of thing? Participants can be remarkably good at picking up regularities in stimulus presentation like this. In general, I’d suggest that you would be better off by having the targets and fillers randomly interspersed. You could do this simply by having a single conditions file, containing all of the image names, with a column variable identifying each as a target or a filler. Yes, you might get successive target presentations, but in general, true random presentation like that will disrupt the ability of the subjects to notice any pattern far better than imposing a regular dispersion of them. It will also produce a much better structured data file for your analysis.

If you do want to go with having a separate loop for the fillers, I’ll describe that below, but wouldn’t recommend it, and note that it will cause your data file to need some wrangling before it can be easily analysed.

You can have them in two separate loops, but the filler loop needs to be nested within the target loop, so that it runs a couple of times for each target stimulus that is presented. The tricky thing is that you want it to just select 2-3 rows of their second loop to run with each iteration of the target loop, and ensure that those rows aren’t repeated across the session.

So if you want to go this route, I’d suggest making a list of the indices of the rows in this conditions file, and shuffling it to get a random order. Do this at the start of the experiment. Then at the end of the routine that shows the target image, pop out two entries of that list (i.e. in effect, sampling without replacement) and put that into a variable which you then use in the "selected “rows” field of the second loop for this trial.

But again, this is a lot of work to avoid using what is probably the much better scheme of a single loop with true randomisation between targets and fillers.

Hi, thank you for the reply!

The reason I had my code structured to pick one out of every two image files corresponding to either LR or RL orientation is because I want the data file to include the orientation of the picture, and if each picture is in its own row in the excel document then I can also have a column just coding whether it was LR or RL so I don’t have to go back and manually do that later. Will having two separate columns give something similar in the output? Having to do it manually wouldn’t be the end of the world, but since I’m going to need to note which orientation the participants saw for each picture if there’s a way to have that output in the data file it would save me a few hours of manual coding.

Thank you for the note about how doing separate loops for targets and fillers would lead to a difficult data file - I hadn’t considered that and would definitely like to avoid it. I think I’ll put both targets and fillers in the same excel sheet but am now having trouble conceptualizing how to do the code that picks only one of the right-left or left-right oriented pictures and then chooses the correspondingly-named column. This is the code I have so far:

import random

a = randint(0,1)
if a == 0:
    Img_col = "ImageFile_LR"
if a == 1:
    Img_col="ImageFile_RL"

ImageFile_RL and ImageFile_LR are the column names in my excel sheet, and Img_col is then the variable name I use to select the file for the image component, but I get an error that says it can’t find the path - it’s looking for a folder called Img_col inside the folder I put the documents for my experiments (which has the main excel document, the images, etc) rather than using the value of either ImageFile_RL or ImageFile_LR to select the column. How can I get Psychopy to match the value of Img_col to the column name in the excel document rather than look for a folder named Img_col?

Right now I have the code in its own component that runs before each picture trial - I’m not sure if that could be responsible for the problem but when I put it at the beginning of the routine with the image component I get a different error saying Img_col not defined, so I thought it might need to be run before the routine with the image component. Is there a better way to do this that I’m not aware of?

Thank you so much for your help, I really appreciate the knowledge from someone who knows how this program works and the kinds of inputs it needs to give a manageable data file.

Prefix it with a $ symbol to tell Builder not to take Img_col literally as a filename, but to treat it as a variable name that itself points to the actual image name. i.e.

$Img_col

This problem is two levels deep, as in your code you are assigning Img_col to literal strings like "ImageFile_LR", when you should be assigning to the variable name ImageFile_LR (i.e. without quotes, as you want to use the actual image name pointed to by that variable, not the literal filename "ImageFile_LR".)

But also, some rows won’t correspond to actual trials, so you would end up with a very confusing data file structure. I’d suggest you do it this way (including using a balanced randomisation scheme to ensure equal numbers of left and right orientations. If that isn’t important to your design, then stick with your randint(0,1) approach). Note that we address your concerns by manually recording in the data file the orientation that was selected on each trial.

Begin experiment tab:

# create orientations for 16 trials:
orientations = ['LR', 'RL'] * 8

# randomise the order:
shuffle(orientations)

Begin routine tab:

# sample an orientation without replacement:
this_orientation = orientations.pop()

# record it in the data file:
thisExp.addData('orientation', this_orientation)

if this_orientation == 'LR':
    Img_col = ImageFile_LR # note: no quotes
else
    Img_col = ImageFile_RL # note: no quotes

Do insert the code component on the same routine as the actual image components: it makes it much easier to understand. The issue with " Img_col not defined" can be due to two things:

  • The code in the “begin routine” tab has not run by the time the image component wants to refer to the Img_col variable. To ensure the code component runs first, make sure it appears above the image component. You can change the vertical ordering of components by right-clicking on their icons.
  • The “image” field of your image component needs to be set to update “every repeat” rather than to be “constant” (if it is constant, Builder assumes it will be information available at the very beginning of the experiment and so will try to create it in advance).

Thank you so much, this fixed everything and I understood the reasoning behind everything. Plus it led to a very nice and manageable data file :smiley:

1 Like