MultiTaskBattery 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- MultiTaskBattery/__init__.py +4 -0
- MultiTaskBattery/battery.py +223 -0
- MultiTaskBattery/experiment_block.py +340 -0
- MultiTaskBattery/fetch.py +77 -0
- MultiTaskBattery/screen.py +152 -0
- MultiTaskBattery/task_blocks.py +1703 -0
- MultiTaskBattery/task_details.json +1047 -0
- MultiTaskBattery/task_file.py +1833 -0
- MultiTaskBattery/task_table.tsv +23 -0
- MultiTaskBattery/ttl_clock.py +73 -0
- MultiTaskBattery/utils.py +201 -0
- multitaskbattery-1.3.0.dist-info/METADATA +92 -0
- multitaskbattery-1.3.0.dist-info/RECORD +17 -0
- multitaskbattery-1.3.0.dist-info/WHEEL +5 -0
- multitaskbattery-1.3.0.dist-info/entry_points.txt +2 -0
- multitaskbattery-1.3.0.dist-info/licenses/LICENSE +21 -0
- multitaskbattery-1.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name task_class descriptive_name code
|
|
2
|
+
rest Rest rest rest
|
|
3
|
+
motor_localizer MotorLocalizer motor localizer motloc
|
|
4
|
+
toe_movement FlexionExtension toe flexexten
|
|
5
|
+
finger_sequence FingerSequence finger_sequence fingseq
|
|
6
|
+
serial_reaction_time SerialReactionTime serial_reaction_time srt
|
|
7
|
+
tongue_movement TongueMovement tongue tongue
|
|
8
|
+
finger_rhythmic FingerRhythmic finger_rhythmic fingrhytm
|
|
9
|
+
time_perception TimePerception time_perception timeperc
|
|
10
|
+
visual_search VisualSearch search visrchsml
|
|
11
|
+
action_observation ActionObservation knot actobserv
|
|
12
|
+
n_back NBack memory nbko
|
|
13
|
+
demand_grid DemandGrid grid dmgrd
|
|
14
|
+
oddball OddBall oddball odbal
|
|
15
|
+
passage_listening PassageListening listen pssglisten
|
|
16
|
+
reading Reading read read
|
|
17
|
+
semantic_prediction SemanticPrediction complete sempred
|
|
18
|
+
verb_generation VerbGeneration verb vrbgen
|
|
19
|
+
movie Movie movie mov
|
|
20
|
+
auditory_narrative AuditoryNarrative radio audnarr
|
|
21
|
+
spatial_navigation SpatialNavigation imagine spatialnav
|
|
22
|
+
affective Affective affective affect
|
|
23
|
+
theory_of_mind TheoryOfMind story tom
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Created 2023: Bassel Arafat, Jorn Diedrichsen, Ince Husain
|
|
2
|
+
from psychopy import core, event
|
|
3
|
+
|
|
4
|
+
class TTLClock:
|
|
5
|
+
|
|
6
|
+
def __init__(self):
|
|
7
|
+
"""
|
|
8
|
+
TTLClock class is used for counting the number of TTL pulses and the time of the last TTL pulse
|
|
9
|
+
"""
|
|
10
|
+
self.clock = core.Clock() #
|
|
11
|
+
self.ttl_count = 0 # the number of ttl pulses
|
|
12
|
+
self.ttl_time = 0 # time stamp of the last incoming ttl pulse
|
|
13
|
+
self.ttl_button = 't' # the button used for simulating a ttl pulse
|
|
14
|
+
|
|
15
|
+
def reset(self, start_time=0):
|
|
16
|
+
""" resets the clock and ttl-counter
|
|
17
|
+
Args:
|
|
18
|
+
start_time (float):
|
|
19
|
+
the time in seconds to start the clock from
|
|
20
|
+
"""
|
|
21
|
+
self.clock.reset(start_time)
|
|
22
|
+
self.ttl_count = 0
|
|
23
|
+
self.ttl_time = 0
|
|
24
|
+
|
|
25
|
+
def wait_for_first_ttl(self, wait = True):
|
|
26
|
+
""" This function waits for the first TTL and then resets the clock appropriately
|
|
27
|
+
Args:
|
|
28
|
+
wait (bool):
|
|
29
|
+
if True, the function will wait for the first TTL
|
|
30
|
+
"""
|
|
31
|
+
if wait:
|
|
32
|
+
print('Waiting for first TTL...')
|
|
33
|
+
while self.ttl_count == 0:
|
|
34
|
+
self.update()
|
|
35
|
+
self.clock.reset()
|
|
36
|
+
self.ttl_time = 0
|
|
37
|
+
|
|
38
|
+
def wait_until(self,time):
|
|
39
|
+
"""waits until the given time since the beginning of the run
|
|
40
|
+
Args:
|
|
41
|
+
time (float):
|
|
42
|
+
time in seconds
|
|
43
|
+
Returns:
|
|
44
|
+
real_time (float):
|
|
45
|
+
time that the real start occurs
|
|
46
|
+
start_ttl (int):
|
|
47
|
+
Number of TRs recorded since the beginning of the run
|
|
48
|
+
start_ttl_time (float):
|
|
49
|
+
Time since the last TR """
|
|
50
|
+
while self.clock.getTime() < time:
|
|
51
|
+
self.update()
|
|
52
|
+
return self.clock.getTime(), self.ttl_count, self.clock.getTime()-self.ttl_time
|
|
53
|
+
|
|
54
|
+
def get_time(self):
|
|
55
|
+
"""returns the current time of the clock
|
|
56
|
+
Returns:
|
|
57
|
+
time (float):
|
|
58
|
+
the current time of the clock
|
|
59
|
+
"""
|
|
60
|
+
return self.clock.getTime()
|
|
61
|
+
|
|
62
|
+
def update(self):
|
|
63
|
+
""" updates the ttl count and time of the last ttl pulse
|
|
64
|
+
"""
|
|
65
|
+
# get all the ttl pulses in the buffer (ttl_button is one key or a list of keys)
|
|
66
|
+
ttl_keys = [self.ttl_button] if isinstance(self.ttl_button, str) else list(self.ttl_button)
|
|
67
|
+
keys = event.getKeys(ttl_keys, timeStamped=self.clock)
|
|
68
|
+
|
|
69
|
+
# checks if the pressed key is the key used as the ttl pulse
|
|
70
|
+
for k in keys:
|
|
71
|
+
self.ttl_count += 1 # each time a ttl button is pressed, ttl count increases
|
|
72
|
+
self.ttl_time = k[1] # the time when the ttl button has been pressed
|
|
73
|
+
print(f"TR count: {self.ttl_count} - TR time: {self.ttl_time} (key '{k[0]}')", end = "\r")
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Created 2023: Bassel Arafat, Jorn Diedrichsen, Ince Hussain
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import MultiTaskBattery.task_blocks as tasks
|
|
6
|
+
import MultiTaskBattery.task_file as task_files
|
|
7
|
+
from MultiTaskBattery.fetch import CACHE_DIR
|
|
8
|
+
|
|
9
|
+
# DEPRECATED: kept for backwards compatibility with external user scripts.
|
|
10
|
+
# make_files.py no longer consults this list — instead it inspects each task's
|
|
11
|
+
# make_task_file signature for a run_number parameter. To opt your task out of
|
|
12
|
+
# receiving a run_number, simply omit it from the signature.
|
|
13
|
+
tasks_without_run_number = ['n_back', 'verb_generation', 'rest', 'tongue_movement',
|
|
14
|
+
'oddball', 'demand_grid', 'demand_grid_easy_diff','finger_sequence', 'finger_sequence_surprise', 'flexion_extension',
|
|
15
|
+
'visual_search', 'serial_reaction_time', 'rest_surprise', 'rest_surprise_images', 'rest_surprise_sound_images','temp_deviant']
|
|
16
|
+
|
|
17
|
+
def dircheck(path2dir):
|
|
18
|
+
"""
|
|
19
|
+
Checks if a directory exists! if it does not exist, it creates it
|
|
20
|
+
Args:
|
|
21
|
+
dir_path (str, path)
|
|
22
|
+
path to the directory you want to be created
|
|
23
|
+
"""
|
|
24
|
+
if not os.path.exists(path2dir):
|
|
25
|
+
print(f"creating {path2dir}")
|
|
26
|
+
os.makedirs(path2dir)
|
|
27
|
+
|
|
28
|
+
def append_data_to_file(filename,data):
|
|
29
|
+
""" Appends a data frame to an (possibly) existing tsv file
|
|
30
|
+
Args:
|
|
31
|
+
filename (str):
|
|
32
|
+
path to the file
|
|
33
|
+
data (dataframe):
|
|
34
|
+
data to be appended to the file
|
|
35
|
+
"""
|
|
36
|
+
if os.path.isfile(filename):
|
|
37
|
+
old_data = pd.read_csv(filename, sep = '\t')
|
|
38
|
+
data = pd.concat([old_data,data],axis = 0)
|
|
39
|
+
data.to_csv(filename, sep = '\t', index = False)
|
|
40
|
+
|
|
41
|
+
def module_dirs(task_modules):
|
|
42
|
+
"""Folders holding the task modules: a task library keeps its
|
|
43
|
+
task_table.tsv and stimuli/ next to its code."""
|
|
44
|
+
return [Path(m.__file__).resolve().parent for m in (task_modules or [])]
|
|
45
|
+
|
|
46
|
+
def get_task_table(exp_dir=None, task_modules=None):
|
|
47
|
+
""" Reads the task_table.tsv files and concatenates them, avoiding duplicates.
|
|
48
|
+
Tables are read in order: next to each task module, then the experiment's,
|
|
49
|
+
then the package's; for a name in more than one table, the first one wins.
|
|
50
|
+
Args:
|
|
51
|
+
exp_dir (str, path, optional):
|
|
52
|
+
path to the experiment directory. If None, its table is not read.
|
|
53
|
+
task_modules (list, optional):
|
|
54
|
+
task modules (const.task_modules); a task_table.tsv next to a
|
|
55
|
+
module is read, e.g. from a task library outside the experiment.
|
|
56
|
+
Returns:
|
|
57
|
+
task_table (dataframe):
|
|
58
|
+
dataframe containing the task table
|
|
59
|
+
"""
|
|
60
|
+
tables = [d / 'task_table.tsv' for d in module_dirs(task_modules)]
|
|
61
|
+
if exp_dir is not None:
|
|
62
|
+
tables.append(Path(exp_dir) / 'task_table.tsv')
|
|
63
|
+
tables.append(Path(__file__).parent / 'task_table.tsv') # package table last, as fallback
|
|
64
|
+
task_table = pd.concat([pd.read_csv(t, sep='\t') for t in tables if os.path.isfile(t)], axis=0)
|
|
65
|
+
return task_table.drop_duplicates(subset='name').reset_index(drop=True)
|
|
66
|
+
|
|
67
|
+
def get_task_class(const, class_name):
|
|
68
|
+
""" Searches for the task class in the list of task modules and returns it
|
|
69
|
+
Args:
|
|
70
|
+
const (constant object):
|
|
71
|
+
constant.py object containing the list of task modules to search for the task class
|
|
72
|
+
class_name (str):
|
|
73
|
+
name of the task class to be searched for
|
|
74
|
+
Returns:
|
|
75
|
+
TaskClass (class):
|
|
76
|
+
the task class that was searched for
|
|
77
|
+
"""
|
|
78
|
+
# First tries to find the class in the custom list of task modules
|
|
79
|
+
if hasattr(const, 'task_modules'):
|
|
80
|
+
for module in const.task_modules:
|
|
81
|
+
if hasattr(module, class_name):
|
|
82
|
+
return getattr(module, class_name)
|
|
83
|
+
if hasattr(tasks, class_name):
|
|
84
|
+
return getattr(tasks, class_name)
|
|
85
|
+
else:
|
|
86
|
+
raise NameError(f"Task class {class_name} not found in any of the task modules, make sure to add the module to the list of task_modules in constants.py")
|
|
87
|
+
|
|
88
|
+
def get_task_file_class(const, class_name):
|
|
89
|
+
""" Searches for the TaskFile class in the list of task modules and returns it.
|
|
90
|
+
Mirrors get_task_class but for the file-generation side. Custom TaskFile
|
|
91
|
+
classes follow a '<class>File' naming convention so they can coexist with
|
|
92
|
+
their matching Task class in the same module (e.g. SilentWord and
|
|
93
|
+
SilentWordFile in my_tasks.py).
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
const (constant object):
|
|
97
|
+
constants.py object containing the task_modules list
|
|
98
|
+
class_name (str):
|
|
99
|
+
base class name from task_table.tsv (e.g. 'SilentWord')
|
|
100
|
+
Returns:
|
|
101
|
+
TaskFileClass (class):
|
|
102
|
+
the TaskFile class that was searched for
|
|
103
|
+
"""
|
|
104
|
+
# First tries '<class>File' in the custom list of task modules
|
|
105
|
+
if hasattr(const, 'task_modules'):
|
|
106
|
+
suffixed = class_name + 'File'
|
|
107
|
+
for module in const.task_modules:
|
|
108
|
+
if hasattr(module, suffixed):
|
|
109
|
+
return getattr(module, suffixed)
|
|
110
|
+
# Otherwise fall back to the framework's task_file module (bare class name)
|
|
111
|
+
if hasattr(task_files, class_name):
|
|
112
|
+
return getattr(task_files, class_name)
|
|
113
|
+
else:
|
|
114
|
+
raise NameError(f"TaskFile class {class_name} (or {class_name}File) not found in any task module, make sure to add the module to task_modules in constants.py")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# --- Stimulus resolution -------------------------------------------------
|
|
118
|
+
# Stimuli are resolved with the same local-first, package-fallback logic that
|
|
119
|
+
# task *classes* use (see get_task_class / get_task_file_class): each root is
|
|
120
|
+
# searched in order, and the package's own bundled stimuli are always appended
|
|
121
|
+
# as a final fallback. This lets a custom task keep its stimuli in the
|
|
122
|
+
# experiment folder while built-in tasks still resolve from the package.
|
|
123
|
+
# The package's stimuli live at <repo_root>/stimuli, i.e. one level up from this
|
|
124
|
+
# module's package directory. After those comes the stimulus cache that
|
|
125
|
+
# `mtb fetch` downloads into (see fetch.py).
|
|
126
|
+
_PACKAGE_STIM_DIR = Path(__file__).resolve().parents[1] / 'stimuli'
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def stim_roots(const):
|
|
130
|
+
"""Return the ordered list of stimulus root directories to search.
|
|
131
|
+
|
|
132
|
+
Searches the ``stimuli`` folder next to each module in ``const.task_modules``
|
|
133
|
+
first, then ``const.stim_dirs`` (a list of roots) if it is defined, otherwise
|
|
134
|
+
the single ``const.stim_dir``. The package's bundled ``stimuli`` folder is
|
|
135
|
+
appended next, then the stimulus cache filled by ``mtb fetch``
|
|
136
|
+
(deduplicated), so built-in tasks still resolve.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
const: the experiment constants module/object.
|
|
140
|
+
Returns:
|
|
141
|
+
list[Path]: roots to search, in priority order (local first, package last).
|
|
142
|
+
"""
|
|
143
|
+
roots = [d / 'stimuli' for d in module_dirs(getattr(const, 'task_modules', None))]
|
|
144
|
+
roots += getattr(const, 'stim_dirs', None) or [getattr(const, 'stim_dir', _PACKAGE_STIM_DIR)]
|
|
145
|
+
roots.append(_PACKAGE_STIM_DIR)
|
|
146
|
+
roots.append(CACHE_DIR)
|
|
147
|
+
return list(dict.fromkeys(Path(r).resolve() for r in roots))
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def find_stim(const, task_name, *parts, must_exist=True):
|
|
151
|
+
"""Resolve a single stimulus file for a task across the stimulus roots.
|
|
152
|
+
|
|
153
|
+
Searches ``<root>/<task_name>/<parts...>`` in each root (local first, package
|
|
154
|
+
last) and returns the first path that exists. Because the local roots are
|
|
155
|
+
searched first, appending the package fallback can never change a lookup that
|
|
156
|
+
already succeeds - it can only rescue one that would otherwise fail.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
const: the experiment constants module/object.
|
|
160
|
+
task_name (str): task subfolder name (usually ``self.name``).
|
|
161
|
+
*parts (str): path components under the task folder - a filename, or e.g.
|
|
162
|
+
``'clips', 'foo.mov'`` for a nested subfolder.
|
|
163
|
+
must_exist (bool): if True (default) raise ``FileNotFoundError`` when the
|
|
164
|
+
file is in none of the roots; if False, return the path under the
|
|
165
|
+
first root (useful when writing a file rather than reading one).
|
|
166
|
+
Returns:
|
|
167
|
+
Path: the resolved stimulus path.
|
|
168
|
+
"""
|
|
169
|
+
roots = stim_roots(const)
|
|
170
|
+
for r in roots:
|
|
171
|
+
p = r.joinpath(task_name, *parts)
|
|
172
|
+
if p.exists():
|
|
173
|
+
return p
|
|
174
|
+
if must_exist:
|
|
175
|
+
sub = str(Path(*parts)) if parts else ''
|
|
176
|
+
raise FileNotFoundError(
|
|
177
|
+
f"Stimulus '{task_name}/{sub}' not found in any stimulus root: "
|
|
178
|
+
f"{[str(r) for r in roots]}. If it is a built-in task, run `mtb fetch {task_name}`.")
|
|
179
|
+
return roots[0].joinpath(task_name, *parts)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def find_stim_dir(const, task_name):
|
|
183
|
+
"""Resolve a task's stimulus *directory* across the stimulus roots.
|
|
184
|
+
|
|
185
|
+
Returns the first ``<root>/<task_name>`` that is an existing directory. Use
|
|
186
|
+
this for the cases that operate on the folder itself (e.g. globbing for a set
|
|
187
|
+
of files) rather than resolving one named file. If no root has the folder,
|
|
188
|
+
the path under the first root is returned so callers get a sensible location
|
|
189
|
+
for error messages.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
const: the experiment constants module/object.
|
|
193
|
+
task_name (str): task subfolder name (usually ``self.name``).
|
|
194
|
+
Returns:
|
|
195
|
+
Path: the resolved task stimulus directory.
|
|
196
|
+
"""
|
|
197
|
+
for r in stim_roots(const):
|
|
198
|
+
d = r / task_name
|
|
199
|
+
if d.is_dir():
|
|
200
|
+
return d
|
|
201
|
+
return stim_roots(const)[0] / task_name
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: MultiTaskBattery
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: A flexible Python toolbox for running multi-domain cognitive and motor tasks during fMRI sessions, built on PsychoPy.
|
|
5
|
+
Author: Diedrichsenlab
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/diedrichsenlab/MultiTaskBattery
|
|
8
|
+
Project-URL: Documentation, https://multitaskbattery.readthedocs.io/
|
|
9
|
+
Project-URL: Issues, https://github.com/diedrichsenlab/MultiTaskBattery/issues
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering
|
|
14
|
+
Requires-Python: <3.13,>=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: psychopy==2026.2.5
|
|
18
|
+
Requires-Dist: pandas
|
|
19
|
+
Requires-Dist: numpy>=1.26.4
|
|
20
|
+
Requires-Dist: scipy
|
|
21
|
+
Requires-Dist: moviepy
|
|
22
|
+
Requires-Dist: imageio
|
|
23
|
+
Requires-Dist: ffmpeg-python
|
|
24
|
+
Requires-Dist: sounddevice
|
|
25
|
+
Requires-Dist: soundfile
|
|
26
|
+
Requires-Dist: pyyaml
|
|
27
|
+
Requires-Dist: questplus
|
|
28
|
+
Requires-Dist: pooch
|
|
29
|
+
Requires-Dist: numba
|
|
30
|
+
Requires-Dist: nibabel
|
|
31
|
+
Requires-Dist: psychopy-sounddevice
|
|
32
|
+
Provides-Extra: docs
|
|
33
|
+
Requires-Dist: numpy; extra == "docs"
|
|
34
|
+
Requires-Dist: sphinx>=1.4; extra == "docs"
|
|
35
|
+
Requires-Dist: sphinxcontrib-bibtex; extra == "docs"
|
|
36
|
+
Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
37
|
+
Requires-Dist: pandas; extra == "docs"
|
|
38
|
+
Requires-Dist: matplotlib; extra == "docs"
|
|
39
|
+
Requires-Dist: ipykernel; extra == "docs"
|
|
40
|
+
Requires-Dist: nbsphinx; extra == "docs"
|
|
41
|
+
Requires-Dist: scipy; extra == "docs"
|
|
42
|
+
Requires-Dist: seaborn; extra == "docs"
|
|
43
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
44
|
+
Requires-Dist: sphinx-design; extra == "docs"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<img src="https://raw.githubusercontent.com/DiedrichsenLab/MultiTaskBattery/main/docs/assets/icon_MTB.png" alt="MTB Logo" width="200">
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
# Multi Task Battery (MTB)
|
|
52
|
+
|
|
53
|
+
A flexible Python toolbox for running multi-domain cognitive and motor tasks during fMRI sessions — all within a single scanning run. Built on [PsychoPy](https://www.psychopy.org/)
|
|
54
|
+
|
|
55
|
+
[](https://multitaskbattery.readthedocs.io/)
|
|
56
|
+
[](https://diedrichsenlab.github.io/MultiTaskBattery/mds/)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
This project runs multi-task batteries developed by the diedrichsenlab.
|
|
60
|
+
#### Authors: Diedrichsenlab (Bassel Arafat, Caroline Nettekoven, Ince Husain, Ladan Shahshahani, Suzanne Witt, Maedbh King, Jorn Diedrichsen)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
## Documentation
|
|
64
|
+
|
|
65
|
+
Full documentation is hosted at:
|
|
66
|
+
https://multitaskbattery.readthedocs.io/
|
|
67
|
+
|
|
68
|
+
Covers:
|
|
69
|
+
- Installation and setup
|
|
70
|
+
- Task and run configuration
|
|
71
|
+
- Optimal battery selection
|
|
72
|
+
- Data output
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT License © 2024 Joern Diedrichsen
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Contributing
|
|
83
|
+
|
|
84
|
+
Open to issues and pull requests. If you use MTB in your research.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Citation
|
|
89
|
+
|
|
90
|
+
If you use the toolbox please cite the following reference:
|
|
91
|
+
|
|
92
|
+
Arafat, B., Nettekoven, C., Xiang, J. D., & Diedrichsen, J. (2026). Multi-Task Batteries for Precision Functional Mapping. *eLife*, 15, RP111868. https://doi.org/10.7554/eLife.111868.1
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
MultiTaskBattery/__init__.py,sha256=7jB7NL8qDIauzVTg1zOzIiQSsE5TqfZ-zqqMZTrbpg0,149
|
|
2
|
+
MultiTaskBattery/battery.py,sha256=4s4Q1DVA7UbRmezgZgOGRh735KgRTodNWUjmRXQbUJQ,8070
|
|
3
|
+
MultiTaskBattery/experiment_block.py,sha256=4m8NolckTj0wpa1jIVcq57StjSLyLMu-EGPGaeTKv_M,15945
|
|
4
|
+
MultiTaskBattery/fetch.py,sha256=Q-4TS9XOHOu-RHrhichkTC1ED90ZK8-aBmMhBbwrRfM,3021
|
|
5
|
+
MultiTaskBattery/screen.py,sha256=Inf5XR_yJAw1NXBclZ_bwi7SESB04_JFMRlfslgvpDc,5760
|
|
6
|
+
MultiTaskBattery/task_blocks.py,sha256=mQibCR2WqEWs8dVIZivcGyc3-oBm0RwKmnhXJ3t10lk,74441
|
|
7
|
+
MultiTaskBattery/task_details.json,sha256=UxX2ZwrH8O6FmbDR-j5oD1pft16fWN0W_2rcAbfyVEE,59150
|
|
8
|
+
MultiTaskBattery/task_file.py,sha256=gSRzX0VDjPlpB8JEWDsjXCIKieKDr-6EoZ5O7CkkAuc,77438
|
|
9
|
+
MultiTaskBattery/task_table.tsv,sha256=HWyMpUkQinfYSXeBj2XWY-qcm1WQ5Y182FxhjdpN9dI,1024
|
|
10
|
+
MultiTaskBattery/ttl_clock.py,sha256=j-gS9RTec8RvsszP1eqFp-7P20hSsKdx_tpZCdNqXWg,2787
|
|
11
|
+
MultiTaskBattery/utils.py,sha256=SGmYP6OtRNYSm3SyspiGAT4hggKdYGN83cvD2v8amS8,9285
|
|
12
|
+
multitaskbattery-1.3.0.dist-info/licenses/LICENSE,sha256=jJJvF_95za41k5Fhb5e1O4E8cRdmFcL4FT0G6-Ll8NY,1074
|
|
13
|
+
multitaskbattery-1.3.0.dist-info/METADATA,sha256=TK6n7aykg3r6zohq1nDShqU9kQ_loHETJW0pXJW_rHA,3149
|
|
14
|
+
multitaskbattery-1.3.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
15
|
+
multitaskbattery-1.3.0.dist-info/entry_points.txt,sha256=jNF1OcHTqnbjILkUMoP9kenlcThpsf71IfNAErfJU4M,52
|
|
16
|
+
multitaskbattery-1.3.0.dist-info/top_level.txt,sha256=X9uviKkeqfHhUbRcbTsvr2bPR2HLhdLVX2HHFfoo8X4,17
|
|
17
|
+
multitaskbattery-1.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Joern Diedrichsen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MultiTaskBattery
|