Hello everyone!
I’m reaching out to ask for your help, if you have some time. I started learning about psychopy this year.
I’ve developed a code in Psychopy Coder to run a task presenting two stimuli,each associated with a slider, text. One of the two stimulus is associated with a sound in 50% of the presentations.
We’re trying to make sure that the same stimulus isn’t presented more than three times in a row, both within a single block and across different blocks.
Despite my attempts to fix it, I’m still having trouble with this issue, and sometimes four presentations occur consecutively.
You might be able to quickly point out the problem (unlike me :/)
I’d really appreciate your help!
Thank you very much!
Best regards
``
Initialize Routine “rec”
Initialize Routine “instruct_us_exp”
instruct_us_exp = visual.TextStim(win=win, name=‘instruct_us_exp’,
text=‘Rate your expectancy of the sound.’, font=‘Arial’, pos=(0, 0), height=0.07, color=‘white’)
instruct_frame.draw()
instruct_us_exp.draw()
win.flip()
instruct_us_exp_duration = 2
core.wait(instruct_us_exp_duration)
check_exit_key()
#US Expectancy rating
US_exp = visual.Slider(win=win, name=‘US_exp’,
startValue=None, size=(0.8, 0.13), pos=(0.0, -0.6), units=win.units,
labels=(‘Not at All’, ‘Very Much’), ticks=(0, 100), granularity=0.0,
style=‘rating’, opacity=1,
labelColor=‘White’, markerColor=None, lineColor=‘White’, colorSpace=‘rgb’,
font=‘Arial’, labelHeight=0.06,
flip=False, ori=0.0, depth=0, readOnly=False)
US_exp_text = visual.TextStim(win=win, name=‘US_exp_text’,
text=‘To what extent do you expect the sound?’,
font=‘Arial’,
pos=(0, -0.4), height=0.07, wrapWidth=None, ori=0.0,
color=‘white’, colorSpace=‘rgb’, opacity=None,
languageStyle=‘LTR’,
depth=-1.0);
def draw_ticks(slider, tick_positions, tick_labels):
for tick_position, tick_label in zip(tick_positions, tick_labels):
tick_text = visual.TextStim(win=win, text=str(tick_label), font=‘Arial’, height=0.07,
pos=(slider.pos[0] + slider.size[0] * ((tick_position - slider.ticks[0]) / (slider.ticks[-1] - slider.ticks[0])), slider.pos[1] + 0.13),
color=‘white’)
tick_text.draw()
tick_positions = [-50, 50]
tick_labels = [0, 100]
check_exit_key()
Define stimuli
cs_plus = visual.ImageStim(win, image=‘C:/Users/marie/Documents/UM/Master 2/Internship/Psychopy/round.png’, pos=(0, 170), units=‘pix’, size=(600, 600))
cs_minus = visual.ImageStim(win, image=‘C:/Users/marie/Documents/UM/Master 2/Internship/Psychopy/triangle.png’, pos=(0, 170), units=‘pix’, size=(600, 600))
us_image = visual.ImageStim(win, image=‘C:/Users/marie/Documents/UM/Master 2/Internship/Psychopy/sound.png’, pos=(0, 170), units=‘pix’, size=(600, 600))
us_sound = sound.Sound(‘C:/Users/marie/Documents/UM/Master 2/Internship/Psychopy/us.wav’, stereo=True)
#Routine “complete”
sliders_and_texts_and_stimuli_and_sounds = [
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, us_sound),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_plus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
(US_exp, US_exp_text, cs_minus, None),
]
random.shuffle(sliders_and_texts_and_stimuli_and_sounds)
sound_component = None
response_data_list =
reaction_time = None
previous_stimulus = None
all_stimuli =
Define some initial variables
for i in range(4): # Loop for 4 blocks
presentations_per_block = {
(US_exp, US_exp_text, cs_plus, us_sound): 8 // 4,
(US_exp, US_exp_text, cs_plus, None): 8 // 4,
(US_exp, US_exp_text, cs_minus, None): 16 // 4
}
block_stimuli =
for slider, text, stimulus, sound in presentations_per_block:
presentations = presentations_per_block[(slider, text, stimulus, sound)]
block_stimuli.extend([(slider, text, stimulus, sound)] * presentations_per_block[(slider, text, stimulus, sound)])
consecutive_count = 0
all_stimuli.extend(sliders_and_texts_and_stimuli_and_sounds)
np.random.shuffle(all_stimuli)
for slider, text, stimulus, sound in sliders_and_texts_and_stimuli_and_sounds:
if stimulus == previous_stimulus:
# Increment the consecutive count
consecutive_count += 1
else:
# If the current stimulus is different, reset the consecutive count
consecutive_count = 0
if consecutive_count >= 2:
# If the limit is reached, choose a random tuple with a different stimulus
other_stimulus = cs_plus if stimulus == cs_minus else cs_minus
# Filter out tuples with the different stimulus
valid_tuples = [(s, t, st, so) for s, t, st, so in block_stimuli if st == other_stimulus]
# Choose a random tuple from the valid ones
if valid_tuples:
new_tuple = random.choice(valid_tuples)
# Swap the current tuple with the new one
all_stimuli[all_stimuli.index((slider, text, stimulus, sound))] = new_tuple
previous_stimulus = stimulus
``
# Mélanger la liste des stimuli pour chaque bloc
np.random.shuffle(block_stimuli)
for item in block_stimuli:
slider, text, stimulus, sound = item[:4]
current_stimulus = (slider, text, stimulus, sound)
marqueur = visual.Rect(win=win, width=0.03, height=0.05, fillColor=‘red’, lineColor=None)
stimulus_type = ‘cs_plus’ if stimulus == cs_plus and sound is None else ‘cs_us’ if stimulus == cs_plus and sound == us_sound else ‘cs_minus’
event.Mouse().setPos((0, -0.2))
non_marker = (0, -0.2)
onset_time = experiment_clock.getTime()
sound_onset = None
response_value = None
# Onset timing of slider, text, stimulus and sound
while experiment_clock.getTime() - onset_time < 10.5:
loop_time = experiment_clock.getTime() - onset_time
# Draw stimulus, text, and slider
if loop_time < 2.5:
stimulus.draw()
sound_playing = False
if stimulus == cs_plus and sound is not None:
if loop_time >= 1 and sound_onset is None:
sound_onset = onset_time + 1
if sound_component is not None:
sound_component.stop()
sound.play(when=sound_onset)
sound_component = sound
sound_playing = True
check_exit_key()
if loop_time <= 1 and response_value is None:
slider.draw()
text.draw()
draw_ticks(slider, tick_positions, tick_labels)
mouse_pos = event.Mouse().getPos()
if mouse_pos[0] != non_marker[0] or mouse_pos[1] != non_marker[1]:
marqueur_pos = max(min(mouse_pos[0] - slider.pos[0], slider.size[0] / 2), -slider.size[0] / 2)
marqueur.pos = (slider.pos[0] + marqueur_pos, slider.pos[1])
marqueur.draw()
# Restrict the mouse click to the slider region
if event.Mouse().getPressed()[0]:
mouse_pos = event.Mouse().getPos()
scale_pos = slider.pos
scale_size = slider.size[0]
if (
scale_pos[0] - scale_size / 2 < mouse_pos[0] < scale_pos[0] + scale_size / 2 and
scale_pos[1] - slider.size[1] / 2 < mouse_pos[1] < scale_pos[1] + slider.size[1] / 2
):
response_value = (mouse_pos[0] - scale_pos[0] + scale_size / 2) / scale_size * 100
response_value_onset = experiment_clock.getTime()
reaction_time = response_value_onset - onset_time
check_exit_key()
win.flip()
#Draw intertrial interval
else:
us_image.draw()
win.flip()
check_exit_key()
# Record response data
response_data_list.append({
“Subject ID”: participant_info[‘Subject ID’],
f"{slider.name}_onset_time": onset_time,
f"{slider.name}_reaction_time": reaction_time,
f"{slider.name}_response": response_value,
“Stimulus Type”: stimulus_type,
“US onset”: sound_onset,
})
check_exit_key()
check_exit_key()
Create a DataFrame from the list of responses
response_df = pd.DataFrame(response_data_list)
response_file_path = os.path.join(output_dir, f’{participant_info[“Subject ID”]}_rating_responses_day1.xlsx’)
if os.path.isfile(response_file_path):
existing_df = pd.read_excel(response_file_path)
updated_df = pd.concat([existing_df, response_df], ignore_index=True)
updated_df.to_excel(response_file_path, index=False)
else:
response_df.to_excel(response_file_path, index=False)
print(f"{slider.name} response has been written to {response_file_path}")
Close the window at the end
previous_stimulus = stimulus
win.flip()