If this template helps then use it. If not then just delete and start from scratch.
OS (e.g. Win10): Win10 PsychoPy version (e.g. 1.84.x): v2021.1.2 Standard Standalone? (y/n) If not then what?: y What are you trying to achieve?:
I have 40 different stimuli
I would like to split those into two groups of 20 stimuli
For Session 001, I want to randomly present the first 20 stimuli from the first group and Session 002, randomly presents 20 stimuli from the other group. I have it coded and everything but it repeats some stimuli which I do not want.
What did you try to make it work?:
import random, xlrd
#randomize the SEED
random.seed()
#stimulus file
infile = 'FragStimuli.xlsx'
#num of study items
num_study = 20
(Begin Experiment)
#access the stim file
inbook = xlrd.open_workbook(infile)
insheet = inbook.sheet_by_index(0)
#arrays for stimuli
word = []
#for randomizing words
random_order = list(range(num_study))
#read the stimuli from sheet (all columns)
for rowx in range(num_study+1):
row = insheet.row_values(rowx)
#save word to word array
word.append(row[0])
random.shuffle(num_study)
#array for final stimuli
word_frag = word
for i in range(num_study):
word_frag.append(word[i])
(Begin Experiment in the experiment loop)
#list of order to show study items
study_order = word_frag
#randomize order of study list
random.shuffle(study_order)
#current study trial
study_trial = 0
(Begin Routine in loop)
#assign study item
WordTing = study_order[study_trial]
#current study item counter
study_trial = study_trial + 1
By session you mean at a separate time? Locally the easiest way would be to save a personalised word list during session 1 of the words to be used in session 2
Alternatively, instead of setting a random seed (which isnât necessary, as there will be a new seed each time unless you set it otherwise), create a fixed one for each subject. e.g. in the information dialog at the start of the experiment, enter a seed value which is unique for each subject. Then the randomisation will be the same across the two sessions for that subject. In the first session, use the first 20 stimuli, and in the second, use the second lot of 20.
NB donât use the random package from Pythonâs standard library. Use numpy's random package instead. That way, the seed you set will apply to all relevant PsychoPy functions as well.
e.g. this is what all Builder scripts make available:
import numpy as np # whole numpy lib is available, prepend 'np.'
from numpy.random import random, randint, normal, shuffle, choice as randchoice
So similarly, if you have an experiment info dialog field called âseedâ, you could do:
np.random.seed(expInfo['seed'])
Then shuffle your list. Present the first half in session 1, and the second half in session 2. Probably easiest to also enter the session number in the exp. info dialog.
Iâd recommend you go with @Michael âs suggestion. In session 1 use continueRoutine=False to skip second 20 trials and in session 2 skip the first 20.
Thank you Michael - Iâm sorry but Iâm new with PsychoPy so I am just a little confused: I want to get my stimulus file from an excel sheet and just have it take 20 words from there, randomized but not repeated. How would I go about that and what would be my seed value?
Hi wakecarter, thanks so much - I already have a session 1 and a session 2 set for the order in which my tests are going to be administered, so I just want my first 20 to be presented in session 1 and the last 20 to be presented in session 2, randomized. Where would I put Routine = False?
Any integer. It just needs to be unique per subject. That means that each subject will get a different random order but the ârandomâ order will be the same across sessions for a given subject. If youâre not comfortable with programming, then just use a spreadsheet to create a list of random numbers between say 1 and 1000 000. Record those in a table so you can enter in each personâs value.
In the loop dialog, there is a box for a seed value that is specific to that loop. So you could simply put this in that field:
expInfo['seed']
Then when the loop runs again for a subject, it will use the same ârandomâ order. The only thing you need to do then is select the first 20 rows on the first session and the second twenty rows on the next one. So insert a code component and in the âbegin experimentâ tab, put something like this:
if expInfo['session'] == 1:
selected_rows = [0, 20]
else:
selected_rows = [20, 40]
# record that for checking in the data file:
thisExp.addData('selected_rows', selected_rows)
This is what I have in my Begin Routine at the beginning of my experiment:
` >#word lists - contains all words
totalwords = [] #list that contains study words
studywords = []
#randomize words
random_order = list(range(num_total))
#iterates all words in list
for rowx in range(1, num_total+1): #row containing all values in row
row = insheet.row_values(rowx) #store 0th place value in total word list
totalwords.append(row[0])
#shuffles the words
random.shuffle(random_order)
for i in range(num_fragment):
studywords.append(totalwords[random_order[i]])
Unless Iâve misunderstood something from your initial description, everything other than the code I suggested can be deleted. i.e. you should just need this:
if expInfo['session'] == 1:
selected_rows = [0, 20]
else:
selected_rows = [20, 40]
# record that for checking in the data file:
thisExp.addData('selected_rows', selected_rows)
Now maybe your original code was doing something else but I canât really interpret it. Iâm just going off your original description, which is a bit ambiguous.
Note there was a typo before, and this:
if expInfo['seed'] == 1:
should have been:
if expInfo['session'] == 1:
assuming you have a field called âsessionâ in the info dialog.
You can put that code in the same âbegin experimentâ tab.
No, a builder loop imports an Excel file for you automatically. Just navigate to the file using the âconditionsâ field.
All we need to do is control the rows used in each session. And thatâs where I put you wrong, because a Builder loop selects the rows before applying the randomisation. So the code I gave above would mean that every subject got the first 20 rows in the first session, although the order would be randomised. So instead, scrap the code I gave above and use this:
np.random.seed(expInfo['seed']) # fixed order per subject
row_numbers = list(range(40))
shuffle(row_numbers)
if expInfo['session'] == '001':
selected_rows = row_numbers[0:20]
else:
selected_rows = row_numbers[20:40]
and once again just put $selected_rows in the selected rows field of your loop stimulus. Delete whatever was in the âseedâ field, as that is now being handled in code.
Please use ``` before and after all code, or indent individual code lines with four spaces. Otherwise, we canât read the code formatted properly - e.g. above it looks like curly quotes got into your code.
No.
Do you have a field called that in your experiment info dialog, and have a number in it?
np.random.seed(expInfo['seed']) # fixed order per subject
File "mtrand.pyx", line 244, in numpy.random.mtrand.RandomState.seed
File "_mt19937.pyx", line 166, in numpy.random._mt19937.MT19937._legacy_seeding
File "_mt19937.pyx", line 186, in numpy.random._mt19937.MT19937._legacy_seeding
TypeError: Cannot cast array from dtype('<U1') to dtype('int64') according to the rule 'safe'
Okay so this is the new error after doing so. There is now also a prompt to enter a seed number when I run my code - does this mean that when a new seed number is put in, itâll be different each time?
As above, you are responsible for this. You need to maintain a list of integers, one per subject, and enter one at the start of the session. This is how you ensure constant randomisation across sessions for each subject (by using the same seed for each session), while ensuring different randomisation for each subject (by using a different seed for each subject).
We want PsychoPy to interpret what you entered as an integer, but it seems to be read as something else for some reason.