Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
156 commits
Select commit Hold shift + click to select a range
1df8b83
Stimuli changes
SaraMilosevska Nov 7, 2025
c5a3141
Removed .idea folder
carobellum Nov 18, 2025
af6ece6
Update .gitignore
carobellum Nov 18, 2025
6ae8845
Update task_file.py
carobellum Nov 18, 2025
300ea60
Update task_file.py
carobellum Nov 18, 2025
26cac63
Merge branch 'sara_dev' into caro
carobellum Jan 25, 2026
d829ff3
Update task_file.py
carobellum Jan 25, 2026
6cfccdd
Rebased task file to og version
carobellum Jan 25, 2026
8d72520
Added new tasks back in
carobellum Jan 25, 2026
3bed9dc
Update task_blocks.py
carobellum Jan 25, 2026
bf2b2cb
Update task_blocks.py
carobellum Jan 26, 2026
843d03c
Update task_blocks.py
carobellum Jan 26, 2026
a0aa338
Update task_blocks.py
carobellum Jan 26, 2026
a7e6a9b
Update task_blocks.py
carobellum Jan 26, 2026
727b116
Update task_blocks.py
carobellum Jan 26, 2026
31ecdcb
Merge pull request #60 from carobellum/caro
Barafat2 Jan 26, 2026
f6f6abf
Update task_blocks.py
carobellum Jan 26, 2026
a43fb4e
Update task_blocks.py
carobellum Jan 26, 2026
9610d40
Update task_blocks.py
carobellum Jan 26, 2026
c3646ab
Update task_blocks.py
carobellum Jan 26, 2026
2e13dc5
Update task_file.py
carobellum Jan 26, 2026
338bb4a
Update task_file.py
carobellum Jan 26, 2026
a52027c
Update task_blocks.py
carobellum Jan 27, 2026
db37879
Update task_blocks.py
carobellum Jan 27, 2026
05a05c3
Update task_blocks.py
carobellum Jan 27, 2026
3b9a344
Update task_blocks.py
carobellum Jan 27, 2026
93069fc
Update task_blocks.py
carobellum Jan 27, 2026
a1a3cf2
Update task_blocks.py
carobellum Jan 27, 2026
9a3230d
Update task_blocks.py
carobellum Jan 27, 2026
e79e472
Update task_blocks.py
carobellum Jan 27, 2026
287ba23
Added short fixation wait time and jitter
carobellum Jan 27, 2026
35f80ed
Added short fixation wait time and jitter
carobellum Jan 27, 2026
1854212
randomize iois
carobellum Jan 27, 2026
72091c8
randomize iois
carobellum Jan 27, 2026
f28f0d0
Update task_blocks.py
carobellum Jan 28, 2026
9c8f84b
Update task_blocks.py
carobellum Jan 28, 2026
8738217
Update task_table.tsv
carobellum Jan 28, 2026
a69b462
Update task_table.tsv
carobellum Jan 28, 2026
0c3f080
Update experiment_block.py
carobellum Jan 28, 2026
2d7282c
Update experiment_block.py
carobellum Jan 28, 2026
16adb29
Update experiment_block.py
carobellum Jan 28, 2026
ff98fb9
Update experiment_block.py
carobellum Jan 28, 2026
f2b38b4
Merge remote-tracking branch 'upstream/main' into caro
carobellum Jan 28, 2026
f90f737
Merge remote-tracking branch 'upstream/main' into caro
carobellum Jan 28, 2026
340bacf
Added semantic switching
carobellum Feb 24, 2026
572a782
Added semantic switching
carobellum Feb 24, 2026
24d7104
Added semantic switching
carobellum Feb 24, 2026
aa41970
Merge branch 'main' into dev
Barafat2 Feb 26, 2026
88982eb
SRT task
Barafat2 Feb 26, 2026
3514e72
srt doc
Barafat2 Feb 26, 2026
48e1e89
automatic task document
Barafat2 Feb 26, 2026
ddd42ea
srt task mod
Barafat2 Feb 26, 2026
5728a12
optimal battery zenodo
Barafat2 Feb 26, 2026
1dc4e5a
Update README.md
Barafat2 Feb 26, 2026
a5f71db
Update conf.py
Barafat2 Feb 26, 2026
9d93da2
documenation
Barafat2 Feb 26, 2026
86ab74e
Update battery.py
Barafat2 Feb 27, 2026
ced425b
documentation fix
Barafat2 Feb 27, 2026
59782a4
doc
Barafat2 Feb 27, 2026
6d140c5
documenation
Barafat2 Feb 27, 2026
f703753
doc cleanup
Barafat2 Feb 27, 2026
bd49d19
clean up
Barafat2 Feb 27, 2026
c1a0954
Update task_details.json
Barafat2 Feb 27, 2026
5125471
Added session randomization
carobellum Mar 6, 2026
436ef8e
Added session randomization
carobellum Mar 6, 2026
a2683cb
Added session randomization
carobellum Mar 6, 2026
bec44e9
Added balancing of conditions
carobellum Mar 6, 2026
0a97d78
Added balancing of conditions
carobellum Mar 6, 2026
795435e
Added balancing of conditions
carobellum Mar 6, 2026
9bd2670
Merge remote-tracking branch 'upstream/main' into caro
carobellum Mar 6, 2026
47c84aa
Merge remote-tracking branch 'upstream/main' into caro
carobellum Mar 6, 2026
9c48b23
Merge remote-tracking branch 'upstream/main' into caro
carobellum Mar 6, 2026
c024547
Update task_file.py
carobellum Mar 6, 2026
5ff935e
Update task_file.py
carobellum Mar 6, 2026
37b75a5
Update task_file.py
carobellum Mar 6, 2026
3757587
Update task_file.py
carobellum Mar 6, 2026
d9c65be
Update task_file.py
carobellum Mar 6, 2026
fb64b4e
Update task_file.py
carobellum Mar 6, 2026
78d5578
typo in faux pas stimuli
carobellum Mar 6, 2026
be9c091
typo in faux pas stimuli
carobellum Mar 6, 2026
79dd54d
typo in faux pas stimuli
carobellum Mar 6, 2026
b677aa9
Update task_file.py
carobellum Mar 6, 2026
47f9049
Update task_file.py
carobellum Mar 6, 2026
cfe79b3
Update task_file.py
carobellum Mar 6, 2026
cae8d42
Update task_file.py
carobellum Mar 6, 2026
6df99a6
Update task_file.py
carobellum Mar 6, 2026
67f541a
Update task_file.py
carobellum Mar 6, 2026
54444de
Merge branch 'caro' of https://github.com/carobellum/MultiTaskBattery…
carobellum Mar 7, 2026
f13791e
Removed semantic switching stimuli
carobellum Mar 7, 2026
cc70172
Merge pull request #6 from carobellum/caro
carobellum Mar 7, 2026
2311bab
Merge upstream/main (allow unrelated histories after repo rewrite)
carobellum Mar 7, 2026
1f95c9c
Update faux_pas.csv
carobellum Mar 7, 2026
4744d76
Update task_table.tsv
carobellum Mar 7, 2026
d48393d
Update task_file.py
carobellum Mar 7, 2026
31ac8d7
Update experiment_block.py
carobellum Mar 7, 2026
d1350bc
Update task_blocks.py
carobellum Mar 7, 2026
df929cc
Update task_blocks.py
carobellum Mar 7, 2026
195a7ca
Update task_blocks.py
carobellum Mar 7, 2026
ddbbc38
Merge pull request #7 from carobellum/caro
carobellum Mar 7, 2026
c2fb12d
Update .gitignore
carobellum Mar 7, 2026
7e59694
Update .gitignore
carobellum Mar 7, 2026
b119422
Update task_file.py
carobellum Mar 8, 2026
c86286d
Update task_file.py
carobellum Mar 8, 2026
b63132d
Update task_file.py
carobellum Mar 9, 2026
47fa516
Update task_file.py
carobellum Mar 9, 2026
b03cacc
Update task_table.tsv
carobellum Mar 9, 2026
4497309
Update task_table.tsv
carobellum Mar 9, 2026
047cebd
Merge branch 'caro' of https://github.com/carobellum/MultiTaskBattery…
carobellum Mar 10, 2026
0335da2
Merge branch 'caro' of https://github.com/carobellum/MultiTaskBattery…
carobellum Mar 10, 2026
3d02574
Update task_file.py
carobellum Mar 10, 2026
60a0d76
Update task_file.py
carobellum Mar 10, 2026
15db3aa
Merge branch 'caro' of https://github.com/carobellum/MultiTaskBattery…
carobellum Mar 10, 2026
803b092
Merge branch 'caro' of https://github.com/carobellum/MultiTaskBattery…
carobellum Mar 10, 2026
0e15c82
Update .gitignore
carobellum Mar 10, 2026
ae9cd41
Update .gitignore
carobellum Mar 10, 2026
1259644
Updated git ignore
carobellum Mar 10, 2026
631dd49
Merge branch 'caro' of https://github.com/carobellum/MultiTaskBattery…
carobellum Mar 10, 2026
5585117
Added nback picture scaling parameter
carobellum Mar 10, 2026
c12c132
Corrected mapping for semantic prediction and semantic switching (tru…
carobellum Mar 10, 2026
b6fd9d5
Delete semantic_switching.csv
carobellum Mar 10, 2026
cf51e29
Update task_file.py
carobellum Mar 10, 2026
cd7ad4c
Update task_blocks.py
carobellum Mar 11, 2026
b0cbf38
Update task_blocks.py
carobellum Mar 11, 2026
8bb8276
Update task_blocks.py
carobellum Mar 11, 2026
fa6056d
Update task_blocks.py
carobellum Mar 11, 2026
bd57846
Update task_blocks.py
carobellum Mar 11, 2026
0a1ffbf
Update experiment_block.py
carobellum Mar 11, 2026
c9ee7f5
Update task_blocks.py
carobellum Mar 11, 2026
a2569b8
Update task_file.py
carobellum Mar 11, 2026
40beb8b
Update task_file.py
carobellum Mar 12, 2026
bec5020
Update task_table.tsv
carobellum Mar 12, 2026
fd50c84
Corrected semantic prediction and semantic switching feedback
carobellum Mar 15, 2026
4c2b7b0
Merge remote-tracking branch 'upstream/main' into caro
carobellum Mar 15, 2026
a2696c9
Merge pull request #8 from carobellum/caro
carobellum Mar 15, 2026
c31f980
Delete build_semantic_switching_tsv.py
carobellum Mar 17, 2026
dc87377
Merge pull request #9 from carobellum/caro
carobellum Mar 17, 2026
cb36616
Create semantic_prediction_practice.csv
carobellum Mar 17, 2026
c792524
Update task_file.py
carobellum Mar 17, 2026
d377ca3
Update task_file.py
carobellum Mar 17, 2026
6f1c2e9
Merge remote-tracking branch 'upstream/main' into caro
carobellum Mar 17, 2026
1881d3f
Merge branch 'main' into caro
carobellum Mar 17, 2026
102e768
Merge pull request #10 from carobellum/caro
carobellum Mar 17, 2026
af01155
Update .gitignore
carobellum Mar 17, 2026
351a0e9
Update faux_pas.csv
carobellum Mar 17, 2026
cbfef4f
updated stimuli
carobellum Mar 18, 2026
f0d03d7
Documented and moved task-specific constants
carobellum Mar 18, 2026
3ce124a
Removed semantic switching
carobellum Mar 18, 2026
889758b
exclude unshareable stimuli
carobellum Mar 18, 2026
964e6f0
Merge remote-tracking branch 'upstream/main' into pr-for-upstream
carobellum Mar 18, 2026
db4bc92
Update task_table.tsv
carobellum Mar 18, 2026
dd63ae3
Updated faux pas practice
carobellum Mar 20, 2026
6242f54
Merge pull request #11 from carobellum/caro
carobellum Mar 20, 2026
aee78c5
Added timestamp option
carobellum Mar 21, 2026
0012507
Merge remote-tracking branch 'upstream/main' into pr-for-upstream
carobellum Mar 21, 2026
a3a365c
Merge branch 'main' into pr-for-upstream
carobellum Mar 21, 2026
38cb9bc
Merge branch 'main' into pr-for-upstream
carobellum Mar 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ stimuli/landscapeMovie
stimuli/movie/misc/natureClip.mov
stimuli/movie/clips
# Confidential
stimuli/picture_sequence/pictures/
stimuli/picture_sequence/eprime_demo/
stimuli/story_sequence/story_sequence.csv
stimuli/action_prediction/clips
stimuli/action_prediction/archive/
stimuli/frith_happe/clips
Expand All @@ -24,3 +27,4 @@ stimuli/liking/clips

.idea/

stimuli/faux_pas/faux_pas.csv
10 changes: 9 additions & 1 deletion MultiTaskBattery/experiment_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pandas as pd
import sys
import numpy as np
from datetime import datetime

from psychopy import visual, gui, event
import MultiTaskBattery.utils as ut
Expand Down Expand Up @@ -129,6 +130,7 @@ def run(self):
self.ttl_clock.reset()
self.ttl_clock.wait_for_first_ttl(wait = self.wait_ttl)
run_data = []
run_end_timestamp = None

# Start the eyetracker
if self.const.eye_tracker:
Expand Down Expand Up @@ -162,6 +164,8 @@ def run(self):

# Add the end time of the task
r_data['real_end_time'] = self.ttl_clock.get_time()
if getattr(self.const, 'record_run_end_timestamp', False) and t_num == len(self.task_obj_list) - 1:
run_end_timestamp = datetime.now().isoformat()
run_data.append(r_data)
self.screen.fixation_cross()

Expand All @@ -178,6 +182,8 @@ def run(self):
run_data = pd.DataFrame(run_data)
# save the run data to the run file
run_data.insert(0,'run_num',[self.run_number]*len(run_data))
if getattr(self.const, 'record_run_end_timestamp', False) and run_end_timestamp is not None:
run_data['run_end_timestamp'] = run_end_timestamp
ut.append_data_to_file(self.run_data_file, run_data )


Expand Down Expand Up @@ -214,7 +220,9 @@ def display_run_feedback(self, run_data):
scores.append([task_name, accuracy, rt])

# Display settings
height = 1.3 # Height of the text elements
# Height of the text elements: allow experiment-specific override via
# const.scoreboard_text_height; fall back to original default (1.3 deg).
height = getattr(self.const, 'scoreboard_text_height', None) or 1.3
gap = [8,1.6] # Gap between entries for the score column [gap_between_columns, gap_between_rows]
cols=len(scores[0])
rws=len(scores)
Expand Down
197 changes: 60 additions & 137 deletions MultiTaskBattery/task_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,14 @@ def init_task(self):
"""
trial_info_file = self.const.task_dir / self.name / self.task_file
self.trial_info = pd.read_csv(trial_info_file, sep='\t')
self.stim=[]
self.stim = []
picture_scale = self.trial_info['picture_scale'].iloc[0] if 'picture_scale' in self.trial_info.columns else 1.0
for stim in self.trial_info['stim']:
stim_path = self.const.stim_dir / self.name / stim
self.stim.append(visual.ImageStim(self.window, str(stim_path)))
self.corr_key = [self.trial_info['key_nomatch'].iloc[0],self.trial_info['key_match'].iloc[0]]
img = visual.ImageStim(self.window, str(stim_path))
img.size = img.size * picture_scale
self.stim.append(img)
self.corr_key = [self.trial_info['key_nomatch'].iloc[0], self.trial_info['key_match'].iloc[0]]

def display_instructions(self):
"""
Expand Down Expand Up @@ -476,8 +479,7 @@ def run_trial(self, trial):

event.clearEvents()

# Set text height according to constants or default value
height = getattr(self.const, 'theory_of_mind_text_height', None) or 1.25
height = trial.get('text_height', 1.25)
wrapWidth=25

# Display story
Expand Down Expand Up @@ -1057,7 +1059,7 @@ def init_task(self):
Initialize task - default is to read the target information into the trial_info dataframe
"""
self.trial_info = pd.read_csv(self.const.task_dir / self.name / self.task_file, sep='\t')
self.corr_key = [self.trial_info['key_false'].iloc[0],self.trial_info['key_true'].iloc[0]]
self.corr_key = [self.trial_info['key_false'].iloc[0], self.trial_info['key_true'].iloc[0]]

def display_instructions(self):
"""
Expand Down Expand Up @@ -1112,109 +1114,6 @@ def run_trial(self, trial):

return trial

class SemanticSwitching(Task):
"""
Read a sentence and decide if the last word of the sentence makes sense.
Click "3" if the last word makes sense; click "4" if not. Be as accurate
and fast as possible.
"""

def __init__(self, info, screen, ttl_clock, const, subj_id):
super().__init__(info, screen, ttl_clock, const, subj_id)
self.feedback_type = 'acc+rt'

def init_task(self):
"""
Initialize task - default is to read the target information into the
trial_info dataframe.
"""
self.trial_info = pd.read_csv(
self.const.task_dir / self.name / self.task_file, sep='\t'
)
self.corr_key = [
self.trial_info['key_false'].iloc[0],
self.trial_info['key_true'].iloc[0],
]

def display_instructions(self):
"""
Display instructions for the semantic switching task.
"""
str1 = "You will read a sentence and decide if the last word makes sense."
str2 = f"If it makes sense, press {self.corr_key[1]}"
str3 = f"If it doesn't make sense, press {self.corr_key[0]}"
self.instruction_text = (
f"{self.descriptive_name} Task\n\n {str1} \n {str2} \n {str3}"
)
instr_visual = visual.TextStim(
self.window,
text=self.instruction_text,
height=self.const.instruction_text_height,
color=[-1, -1, -1],
)
instr_visual.draw()
self.window.flip()

def run_trial(self, trial):
"""Runs a single trial of the semantic switching task."""
height_word = 2

event.clearEvents()

# Sentence is stored with '|' delimiters
sentence = trial['sentence']
words = sentence.split('|')

# Show words sequentially, 800 ms each
for word in words:
word_stim = visual.TextStim(
self.window,
text=word,
pos=(0.0, 0.0),
color=(-1, -1, -1),
units='deg',
height=height_word,
)
word_stim.draw()
self.window.flip()
self.ttl_clock.wait_until(self.ttl_clock.get_time() + 0.8)

event.clearEvents()

# Fixation cross
self.screen.fixation_cross()
self.ttl_clock.wait_until(self.ttl_clock.get_time() + 0.5)
event.clearEvents()

# Display last word
last_word_stim = visual.TextStim(
self.window,
text=trial['last_word'],
pos=(0.0, 0.0),
color=(-1, -1, -1),
units='deg',
height=height_word,
wrapWidth=30,
)
last_word_stim.draw()
self.window.flip()

event.clearEvents()

# Collect response
trial['response'], trial['rt'] = self.wait_response(
self.ttl_clock.get_time(),
trial['sentence_dur'],
)
trial['correct'] = (trial['response'] == self.corr_key[trial['trial_type']])

# Feedback
self.display_trial_feedback(
trial['display_trial_feedback'],
trial['correct'],
)

return trial

class VisualSearch(Task):

Expand Down Expand Up @@ -1375,42 +1274,66 @@ def run_trial(self, trial):
picture_path = Path(self.const.stim_dir) / self.name / 'pictures' / picture_file_name
# Convert Pathself object to string for compatibility
picture_path_str = str(picture_path)
# Create an ImageStim object
picture = visual.ImageStim(self.window, str(picture_path_str))
# Create an ImageStim object, explicitly centered so that the four answer
# options (placed symmetrically above and below) straddle the image.
picture = visual.ImageStim(self.window, str(picture_path_str), pos=(0, 0))
# Make the picture smaller
picture_scale = getattr(self.const, 'rmet_picture_scale', None) or 0.7
picture.size = picture.size * picture_scale



# --- Answers ---
# Get the answer options
answer_options = trial['options']
# Separate them into four strings
answer_options = answer_options.split(',')
# Create TextStim objects for each answer option
# Get the answer options and split into four strings
answer_options = str(trial['options']).split(',')

# Create TextStim objects for each answer option with a colored index and
# black option text. The spatial layout and string breakup are preserved:
# only formatting (height and color) is controlled here.
answer_stims = []
option_height = trial.get('option_text_height', 1.2)
index_height = option_height * 0.85
pos_scale = trial.get('option_position_scale', 1.0)

# Small horizontal offset so that, visually, the options sit slightly
# closer to the centre and the eye picture looks better centered between
# them on wide screens.
x_offset = -1.0

for i, option in enumerate(answer_options):
# 0 and 1 should be on the left and right of the top line (y position 7 and x positions -7 and 7)
# 2 and 3 should be on the left and right of the bottom line (y position -7 and x positions -7 and 7)
x = -8 if i % 2 == 0 else 6
y = 5 if i < 2 else -5

if len (option) < 3:
tabs = 2
elif len(option) < 9:
tabs = 3
else:
tabs = 4
tab_string = ''.join(["\t"] * tabs)
answer_stim = visual.TextStim(self.window, text=f'{i+1}.{tab_string}',
pos=(x, y-0.04), color='blue', height=1, alignHoriz='center')
# 0 and 1 on top left/right; 2 and 3 on bottom left/right.
base_x = -8 if i % 2 == 0 else 6
base_y = 5 if i < 2 else -5
x = base_x * pos_scale + x_offset
y = base_y * pos_scale

option_str = option.strip()
index_label = f'{i+1}.'
text_label = f' {option_str}'

# Draw the numeric index in a distinct color (blue-ish) to visually
# separate it from the age/feeling text.
index_stim = visual.TextStim(
self.window,
text=index_label,
pos=(x, y),
color=[-1, -1, 1], # blue index on grey/white background
height=index_height,
alignHoriz='left',
)

answer_stims.append(answer_stim)
tab_string = ''.join(["\t"] * (tabs-1))
answer_stim = visual.TextStim(self.window, text=f'{tab_string}{option}',
pos=(x, y), color=[-1, -1, -1], height=1.4, alignHoriz='center')
answer_stims.append(answer_stim)
# Draw the actual answer text in standard black, slightly to the right
# of the index so the combined appearance matches "1. option".
text_stim = visual.TextStim(
self.window,
text=text_label,
pos=(x + 0.8, y),
color=[-1, -1, -1],
height=option_height,
alignHoriz='left',
)

answer_stims.extend([index_stim, text_stim])

# Display stimuli
picture.draw()
Expand Down Expand Up @@ -1979,7 +1902,7 @@ def run_trial(self, trial):

event.clearEvents()

height = getattr(self.const, 'faux_pas_text_height', None) or 1.25
height = trial.get('text_height', 1.25)
# Display story
story = trial['story']
# story = '.\n'.join(story.split('. '))
Expand Down Expand Up @@ -2866,4 +2789,4 @@ def run_trial(self, trial):
self.window.flip()
self.ttl_clock.update()

return trial
return trial
Loading