Selecting different rows per iteration in a loop

I can think of two ways to do this.

Split up the conditions file

Advantage: easy to understand. Disadvantage: many conditions files.

In this case, you need two loops around your routine(s). The outer loop loops over a file with four rows, each containing a conditions file (say, in a column called conditions_file. The inner loop loads these conditions files in turn (enter $conditions_file as file name). So you have five conditions files in total: (1) row 1-12, (2) row 13-24, (3) row 25-36, (4) row 37-48, (5) the names of these four conditions files.

Select rows dynamically

Advantage: only one conditions file. Disadvantage: quite complex.

  1. Create a new routine with a code component in the beginning of your loop.
  2. Under “Begin experiment” define a variable: this_loop_number = 0.
  3. Then under “Begin Routine” increment this value on each loop: this_loop_number +=1.
  4. In the loop, set “select rows” to $((this_loop_number-1)*12+1):(this_loop_number*12)
  5. Finally, add a loop around the whole thing which repeats four times to get 1:12, 13:24, 25:36, and 37:48.
7 Likes

I wanted to check that @lindeloev’s “setting rows dynamically” solution worked (that’s how it was designed but I don’t think this is often tested). It did! :dancers:

So here’s an example experiment file showing it in action. Put these 3 files together in a folder and run the blockSubset experiment. A couple of notes:

  • the entries in the blocks file are '0:5, '5:10, '10:15 and note the ' just at the beginning of each one. That tells Excel to treat this as a string and not be clever and convert it into a date/time. For excel a string is indicated by just one ' at the beginning of the cell.
  • I set up this to run a single repeat of each trial. The trials within the blocks I made random and the blocks I made sequential (so you get 1-5 shuffled, then 5-10 shuffled etc)

blockSubset.psyexp (6.6 KB)
allConds.xlsx (28.5 KB)
blocks.xlsx (27.3 KB)

5 Likes

Hi sorry I have a similiar issue, I just wanted to see if it would apply to my problem. I have also created a task looped from an excel file with 50 rows. I currently have it working from a place in which the participant provides a rating at each row. I was hoping to change my task (because it takes too long) to get ratings for the first 10 rows. Then to only trigger a rating for every second row for the next rows that comes through (with odd rows having the stimulus appear for two seconds then moving to the next row). Would I use a simliar method to yours here?

Probably not. In your case, you still want to run through every row in the conditions file, it’s just that on some of those trials you want to skip the rating scale. Probably the best way to do this is instead with a code snippet that decides if the rating scale will run on a given trial. The easiest way to arrange this would be to put the rating scale in its own routine. Insert a code component on that routine, and in its Begin routine tab, put some code something like this, which decides whether the routine will run, depending on the trial number (the default is that the routine will run, so you only need to determine trials where it won’t):

# am assuming your trial loop is called 'trials'. Replace with 
# your actual loop name if necessary.

# NB loops are 0-based, so trial index 9 refers to the tenth trial.
if trials.thisN > 9 and trials.thisN % 2 == 0:
    continueRoutine = False

The % operator returns the remainder after division. As 10 is even, 10 % 2 returns 0 and 11 % 2 returns 1, and so on, allowing you to flip behaviour between odd and even number trials. NB this is all zero based, so trial # 10 is actually the 11th trial, and so on.

1 Like

Hi Michael thanks so much for your reply! I appreciate it! I tried inserting a code component and putting in

if bead_loop.thisN > 9 and bead_loop.thisN % 2 == 0:
     continueRoutine = False

I copied this into the ‘begin routine’ tab and my task continued with no syntax errors but nothing changed it ran through ratings at all 50 iterations. I also tried taking this same code and cutting it into the ‘end routine’ tab and nothing changed here either. Do I potentially need to change something in the rating component to make it recognise the code. When I open up the rating component ‘start’ is set on time(s) ‘1’, would this override the code?

This will only work in latest version(s) of PsychoPy, so check that you are up-to-date. You can also put in some debugging code like this:

    if bead_loop.thisN > 9 and bead_loop.thisN % 2 == 0:
        continueRoutine = False
        print(bead_loop.thisN)

This will let you know if the if/then in the code is actually working and on what trial numbers.

1 Like

On updating Psychopy it works!!! Thank you so much!!! One last thing, so for the turns where ‘continueRoutine = False’ I was hoping to get the stimuli (beads) from each of those iterations to still display on the screen for 1 second (before it triggers the routine to end). At the moment it immediately triggers routines to end but I would like to get it so the iterations without ratings still have their stimulus appear for a second or so, Is this possible? I tried a few things such as

if bead_loop.thisN > 9 and bead_loop.thisN % 2 ==0 and t > 1:
      thisN.time = t
      continueRoutine = False

#I also tried this - 

while t > 1:
     thisN.time = t 
     if bead_loop.thisN > 9 and bead_loop.thisN % 2 ==0:
            continueRoutine = False

None of my attempts worked though (I also made my ‘rating’ component in this routine to only start at 1.5 seconds hoping that it would mean for the routines that are forced to end it would not have appeared yet)

I would guess that the easiest thing to do is just create another separate routine that shows the stimulus for 1 second, which runs on every trial. Insert it before the routine with the rating scale.

1 Like

I can’t believe I didn’t think of that!! I’ve spent so long trying to figure out how to do it via loop. Thank you so so much, this has helped me a real lot!! Cheers again have a great week

Hi everyone. This thread has been very helpful but I have hit a snag. My solution is similar to Jon’s, i.e. I have a separate Excel file that tells PsychoPy which rows to use (from a second Excel file) in each block. The entries of the former file are something like '0:4, '4:8, etc. These entries are in a column named $curr_block_trial_picks_training_phase, and I call this variable in a nested loop using Selected rows.

This works fine when I index the first ten rows (zero to nine). However, whenever I try indexing rows that are greater than a single digit, e.g. '0:10 instead of '0:9 I get the following error:

elif len(selection)>0:
TypeError: object of type ‘float’ has no len()

Note that this does not happen if I e.g. just type 0:10 directly into Selected rows.

What might be going on is that PsychoPy is casting numbers larger than single digits to floats, and then not knowing what to do with them. However, I have no clue how to fix it.

Help!

I think actually that this thread saved my ass> https://github.com/psychopy/psychopy/issues/881

3 Likes

3 posts were split to a new topic: Syntax error when selecting rows

Hello Jon,

I am having a smiliar problem which can’t be fixed with this solution.

I have an images routine and a video routine. They both have loops individually (images picking 3 images at random from its own excel file and videos picking one video randomly from its excel file) I then have an router loop which repeats this 9 times. The problem is for the videos i only want the 1 video that is picked randomly to display once, so 9 different videos are shown. But sometimes the same video shows again. I do not want this but I cannot set rows as I only want it to select one video.

Is there a solution to this?

Hi Jon,
Your demo code was the basis for a couple of experiments I ran using PsychoPy2 and PsychoPy v3.0.6 (builder versions). Now, I want to run the experiments on Pavlovia and the behavior is quite different. Instead of presenting all the items of each block, only the first item is presented. The experiment just proceeds. There is no error message.

I also put your demo experiment on Pavlovia and observed the same behavior; only the first item is presented. Here is the experiment on Pavlovia: https://pavlovia.org/run/markus.huff/select_different_rows/html/.

I’d be great if I could run my experiments on Pavlovia.

Any help is appreciated. Thanks for your great work on PsychoPy!
Markus

Hello, I think im trying to do something similar on PsychoPy Builder but I haven’t been able to the achieve it with the tips you gave.

I have to make a routine where two images show up at the same time, in a random order.

I created an excel where I have image_1 and image_2 and the pair that they belong to (depends on the row). I need for the images on each row to show up together, and at the same time, for the order to be random.

I’ve attached some screenshots.

How could I do this?
Thanks in advance!

What I would do is create a new variable which is either 1 or -1, for example

order = 0
if random()>.5:
     order=-1
thisExp.addData(‘order’,order)

Then multiply the horizontal positions of the two images by order.

Could you be a bit more specific?
I just started using this program and im still learning.
I would put another variable as a column? So I would have Pair_practice, New variable, image1, image 2?

And how could I multiple the two images by order?

Thank you!

Hi,

My solution was based on the assumption that you want two images side by side.

However, it can still be used if you want two images one after the other. Please could you show your two image components in the situation where image1 comes before image2?

Hi @jon

I am having some trouble downloading the .psyexp file for this demo. Can you please help?

Hi Jon, thank you for the reply- “blockSubset.psyexp” was not able to be downloaded. Are there any ways where I can download the demo and take it as a reference for one of my trouble?

Many thanks.