psychopy.org | Reference | Downloads | Github

Randomly Displaying Certain Rows of the Condition File 4 Times While the Other Rows only 1 Time

OS (Win10):
PsychoPy version (v2020.1.3):

What are you trying to achieve?:

I have one condition file consisted of images and words. I want to present words and stimuli in a random order not having the word or image twice in a row. It is really easy if the number of images and words were equal. However, I have 80 unique pictures and 20 unique words in a condition file.

What did you try to make it work?: My condition files have 160 rows (80 rows that represent the image and 80 rows for the word). With this method, each word is repeated 4 times and they can be presented in a row which is something that I don’t want.

Is it possible to have a condition file that has 80 rows for images and 20 for words but displaying the images (let’s say image condition 1) 1 time and words (condition 2) 4 times in order to reach an equal number of word and image trials?.

Is it possible to do it without a code or do I need to implement a code for it?

Thanks in advance!

I have just reread my post and I feel like I did not clearly describe what I want to achieve.

Stimuli: I have 80 different pictures and 20 different words.
(An example of how my condition file look like with 8 images, 2 words)
excel

My goal: Presenting images 1 time and word list 4 times to have an equal number (80 each) of word and image trials (in total 160).

My requirements: These 160 trials should be presented randomly (i.e., image3, image6, word1, image2, word6, word 9, word 2…) suggesting that words (also images) can be presented consecutively as long as they are different. (not like word 1, word 1, image 3, word 3…) the only restriction here is that identical words/images should not be presented in a row.
The same restriction is not a concern for the image stimuli since 80 of them are unique.

Is there any function on the builder view that I can achieve my goal with stimuli presentation, or do I need a code component to achieve what I want?

Hope I made my post more clear.

Thank you very much in advance.

Yes, this will take code. Firstly, set the balanced but randomised order of conditions:

trial_types = ['image', 'word'] * 80
shuffle(trial_types)

Secondly, set the order within the images, which is easy:

image_list = [f'image_{i}.jpg' for i in range(80)]
shuffle(image_list)

Then set the order of words, which is trickier. I’m going to cheat here and randomise it within blocks of 20, meaning we just have to check that there is no consecutive repetition between the last entry of one block of 20 and the first of the next one:

original_words = ['cat', 'dog', 'frog', 'walrus', 'kiwi'] # you'll have 20 words here
shuffle(original_words)

word_list = []
word_list.extend(original_words)

for _ in range(4):
    # prevent first word of next list being the same as the last word of the previous:
    last_word = word_list[-1]
    original_words.remove(last_word)
    shuffle(original_words)
    first_word = original_words[0]
    word_list.append(first_word)

    # randomise and append the next 19 words:
    original_words.remove(first_word)    
    original_words.append(last_word)
    shuffle(original_words)
    word_list.extend(original_words)

    # restore the list to 20 words:
    original_words.append(last_word)

I haven’t tested that code, but hopefully it would give you a list of 80 words, randomised within 4 blocks, with no consecutive entries.

Now you need to create two routines, one to show a text stimulus and one to show an image stimulus. Surround them both with a single loop, set to have an nReps of 160.

To control which routine runs on any given trial, insert a code component on each one. In the “begin routine” tab of the image routine, put something like this:

trial_type = trial_types[your_loop_name.thisN]

if trial_type == 'word':
    continueRoutine = False
else:
    image_name = image_list.pop()
    thisExp.addData('trial_type', trial_type)
    thisExp.addData('image_name', image_name)

and this in the word routine:

trial_type = trial_types[your_loop_name.thisN]

if trial_type == 'image':
    continueRoutine = False
else:
    word = word_list.pop()
    thisExp.addData('trial_type', trial_type)
    thisExp.addData('word', word)

and set the text stimulus component’s content to be $word and the image field to be $image_name, set to update on every repeat.

Hello @Michael. Thank you so much for your help!

I get the idea of how to write the code. However, I get an error message (I will explain in detail below).

Following is my flow


Code Routine has 1 code component that I put in the begin experiment

#set the balanced but randomised order of conditions
trial_types = ['image', 'word'] * 80
shuffle(trial_types)

#my images are in the folder 'one' and named as image_(1), image_(2)..... that's why I changed the code below a bit
image_list = [f'one/image_({i}).bmp' for i in range(80)]
shuffle(image_list)
#I just wrote random words for now
original_words = ['A', 'B', 'C', 'D', 'E','F','T','W','X','G','I','K','M','O','Q','S','U','X','Y','Z'] # you'll have 20 words here
shuffle(original_words)

word_list = []
word_list.extend(original_words)

for _ in range(4):
    # prevent first word of next list being the same as the last word of the previous:
    last_word = word_list[-1]
    original_words.remove(last_word)
    shuffle(original_words)
    first_word = original_words[0]
    word_list.append(first_word)

    # randomise and append the next 19 words:
    original_words.remove(first_word)    
    original_words.append(last_word)
    shuffle(original_words)
    word_list.extend(original_words)

    # restore the list to 20 words:
    original_words.append(last_word)

image_sti routine has a code, image and keyboard component. Image is set to $image_name and keyboard component has the response keys ‘a’ and ‘l’ with responses are stored with $corrAns

Code component has the following;

#I wrote randomtrials as my loops name below
trial_type = trial_types[randomtrials.thisN]

if trial_type == 'word':
    continueRoutine = False
else:
    image_name = image_list.pop()
    thisExp.addData('trial_type', trial_type)
    thisExp.addData('image_name', image_name)

work_sti routine also has a code, text and keyboard component. Text is set to $word and keyboard component has the response keys ‘a’ and ‘l’ with responses are stored with $corrAns

Code component has the following;

#I wrote randomtrials as my loops name below
trial_type = trial_types[randomtrials.thisN]

if trial_type == 'image':
    continueRoutine = False
else:
    word = word_list.pop()
    thisExp.addData('trial_type', trial_type)
    thisExp.addData('word', word)

When I run the experiment, sometimes it shows a word and then crushes or sometimes it crushes from the beginning without showing anything and I get the following error;

I guess images

Also I share the script (please dont mind the name feedback I forgot to change it)
feedback_trial.py (20.0 KB)

Thank you so much!

The .py file isn’t as easy to inspect as the .psyexp so I’m just guessing here. But I guess there is a clash between what the image variable represents (a string, possibly the name of a variable in your conditions file) and want you think it represents (an image component).

Check the name of your image component and make sure it is unique, and that you use it’s correct name if referring to it in any custom code.

@Michael, I managed to fix the issue thanks to your help! There was a clash between what the image variable represents and want I think it represents, as you suggested.

At the moment, I can present 160 stimuli (80 images and 80 words, all randomized with no repetition) without a problem. But I have one question. When 160 trials are presented, experiment crushes, I get the following error message:

errorr
I thought that maybe in the code component I asked for more stimuli in range than I actually have (I know that the default value of indexing and range starts from 0); therefore, I named the image_(80) as image_(0). However, I still get the error and tells me that there is a problem with the line that I write my loop name ( trials ). I couldn’t solve the problem (to be honest I couldn’t understand perfectly what is the problem). Do I have any mistakes in my condition file? For instance, I couldn’t be sure If I need to write all of the words (i.e., A, B…) on condition file since I created a list in the code component already.

However, I uploaded experiment to Pavlovia since the py code would be hard to inspect https://gitlab.pavlovia.org/emreg/randomization

Lastly, just to be sure. Do I need to translate this code manually from Py to Javascript to make it run online?

Thanks a lot

Emre, to put an experiment online you need not to translate Javascript code manually, the builder automatically does this. Make sure you have the 2020 version of Psychopy. However there are some functions / methods which are not translated from .py code to .js you will need to adapt the .js script accordingly for those. Refer to the cribsheet for more info: https://docs.google.com/document/d/13jp0QAqQeFlYSjeZS0fDInvgaDzBXjGQNe4VNKbbNHQ/edit#heading=h.hty8g0ubiw08

As for the repository link you provided, you must change it’s accessibility from GitLab first, otherwise nobody will be able to see it. Go to your repository and click “Settings” you will see options for this under the “Permissions” tab.

Before this line:

trial_type = trial_types[trials.thisN]`

put something like:

print(len(trial_types))
print(trials.thisN)

and let us know the output around the time it crashes.

Hi @Tamer_Gezici ! Thank you for your advice.

I do have the latest version of PsychoPy, and the cribsheet is amazingly helpful however I guess there are some methods (rather than functions) that are not translated from .py to .js and they are really hard for me to grasp.

For the accessibility, it is totally my mistake that I forgot to change its visibility. I guess it should be visible now.

Hi @Michael I put the following into two code components both image and word routine.

print(len(trial_types))
print(trials.thisN)

This is the output that I got fort word routine;


########### Running: C:\Users\Emre\Desktop\deneme3\trial3_lastrun.py ###########
1691.2687     EXP     Imported OrderA.xlsx as conditions, 100 conditions, 6 params
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
160
0
160
1
160
2
.
.
.
.
160
158
160
159
160
160
Traceback (most recent call last):
  File "C:\Users\Emre\Desktop\deneme3\trial3_lastrun.py", line 233, in <module>
    trial_type = trial_types[trials.thisN]
IndexError: list index out of range
##### Experiment ended. #####

and this is when I put the code into image routine:

########### Running: C:\Users\Emre\Desktop\deneme3\trial3_lastrun.py ###########
1691.2687     EXP     Imported OrderA.xlsx as conditions, 100 conditions, 6 params
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
160
0
160
1
160
2
.
.
.
.
160
157
160
158
160
159
Traceback (most recent call last):
  File "C:\Users\Emre\Desktop\deneme3\trial3_lastrun.py", line 233, in <module>
    trial_type = trial_types[trials.thisN]
IndexError: list index out of range
##### Experiment ended. #####

I shortened the middle part of the output (…) otherwise it was going to be pretty long.
According to my impression image routine runs 159 trials instead of 160. Did I understand correctly? Can this be the reason why experiment crushes and tell me that list index out of range?

How are you limiting the trials loop to 160 loops (0 to 159)? It sounds like it’s reaching 160 (or perhaps preparing for 160 before exiting the loop)

@wakecarter, I want to present 20 unique words 4 times and 80 unique images 1 time in a total of 160 trials. Words and images should be randomized and the same words should not be presented twice in a row.
With the help of Micheal, I created a word list containing 20 unique words that repeat 4 times and image list repeat 1 time by codes. I set nRreps to 160 because I think that code component pulls one trial each time (either image or word) from the created list randomly (I am not 100% sure if I am correct).
My condition file has 100 rows (80 rows are pictures, 20 rows are words). Do you think limiting the trials loop to 160 is the cause of the problem?

Are you pointing at your conditions file in your loop? If you have already set up an array with your words you shouldn’t need to point at the conditions file a second time.

@wakecarter Yes, I do point at my condition file. However, since I created a word list with code component I deleted all the words from my condition file and there are only 80 rows that correspond to images. I am not sure if I can delete them and rely on the code component solely? Don’t I need to point at the condition file for the image so that psychoPy can find correct images from the folder and present it? Because I used
a code like [f'image_({i}).bmp' for i in range(80)] that corresponds to image number 1 to 79

If your conditions file has 80 rows, were you planning to use them all twice? You don’t need to specify a conditions file if you have all the information in code. If you do specify a conditions file then each nRep will cycle through the specified rows once.

BMP files won’t work online

There are 160 elements in the trial_types list (numbered 0 through 159).

trials.thisN should not exceed 159, or else it will exceed the last index of that list. Yet your output shows that it reaches 160. How have you determined the number of iterations of the trials loop? Either it needs to be limited to 160 (i.e. numbered 0 through 159), or the trial_types list needs to be longer to match it.

@wakecarter I am sorry for the confusion before.
Actually, I want to use condition file because there are other columns in my condition file that I want to see in the output (i.e., whether the have single or multiple items, or whether the words are long or short, etc.). I would like to use condition file since relying on code components can be harder.

So, my aim is to repeat the first 80 rows that contain 80 different pictures 1 time and
-------------------to repeat the last 20 rows (from row 80 to 100) 4 times in total 160 trials.
These 160 trials should be randomly presented.

For the BMP files, I will change them into JPG then.

Many Thanks

Hi @Michael

I set nReps to 160. I thought this limits the iterations and trials.thisN cannot reach 160. However, I did not understand how word trials reach 160 while images do not.

I have changed the nReps to 161and 159 (even to 10 to see what happens) I performed the same amount of trials then experiment crushed and I got the same output.

I increased trail types to 81 times each while keeping range(80)

#set the balanced but randomized order of conditions
trial_types = ['image', 'word'] * 81
shuffle(trial_types)

#set the order within the images
image_list = [f'face/image_({i}).jpg' for i in range(80)]
shuffle(image_list)

but then I get the following error

image_name = image_list.pop()
IndexError: pop from empty list

Number of trials = nReps x number of conditions

If you want 160 trials and you have 80 rows in your Excel file, set nReps to 2

Hi @wakecarter.

Sorry for the late reply! And thank you for the information.
I got a bit confusion about nReps. However, problem is solved!