Delineating cerebellar peduncles#
The cerebellar peduncles are white matter tracts that connect the cerebellum to the brainstem and cortex. In this example, we show how to delineate the cerebellar peduncles using a subject from the Healthy Brain Network dataset.
This how-to will focus on the definition of the Cerebellar Peduncles (CP) based on [1]_, [2].
import AFQ.data.fetch as afd
import AFQ.api.bundle_dict as abd
from AFQ.api.group import GroupAFQ
from AFQ.definitions.image import RoiImage, ImageFile
"""
We will use a subject from the HBN dataset. When considering the data
for this operation, look to see whether the acquisition volume includes the
cerbellum. If it does not, it will be hard to delineate the CPs.
"""
bids_path = afd.fetch_hbn_afq(["NDARAA948VFH"])[1]
"""
The next line downloads the cerebellar peduncle templates from `Figshare <https://figshare.com/articles/dataset/Regions_of_interest_for_automated_fiber_quantification_of_cerebellar_bundles/23201630>`_.
"""
cp_rois = afd.read_cp_templates()
"""
The following line defines a bundle dictionary for the cerebellar
peduncles. There are three CPs: The ICP, the MCP, and the SCP. Each CP is
defined by two inclusion ROIs and one exclusion ROI. The Inferior CPs are
defined by inclusion ROIs. They do not decussate, so "cross_midline" is set to
False. The Superior CPs are defined by two inclusion ROIs and an exclusion ROI,
where each SCP's most superior inclusion ROI is the other SCP's exclusion ROI.
They decussate, so "cross_midline" is set to True. The Middle CPs are defined
by two inclusion ROIs and they use the SCP intermediate ROIs as exclusion ROIs.
"""
cp_bundles = abd.cerebellar_bd()
"""
The bundle dict has been defined, and now we are ready to run the AFQ pipeline.
Next, we define a GroupAFQ object. In this case, the tracking parameters
focus specifically on the CP, by using the ``RoiImage`` class to define the
seed region. We seed extensively in the ROIs that define the CPs.
"""
cp_afq = GroupAFQ(
name="cp_afq",
bids_path=bids_path,
dwi_preproc_pipeline="qsiprep",
tracking_params={
"n_seeds": 4,
"directions": "prob",
"odf_model": "CSD",
"seed_mask": RoiImage()},
clip_edges=True,
bundle_info=cp_bundles)
"""
The call to `export("bundles")` triggers the execution of the full pipeline.
"""
cp_afq.export("bundles")
"""
References
----------
.. [1] S. Jossinger, A. Sares, A. Zislis, D. Sury, V. Gracco, M. Ben-Shachar (2022)
White matter correlates of sensorimotor synchronization in persistent
developmental stuttering, Journal of Communication Disorders, 95.
.. [2] S. Jossinger, M. Yablonski, O. Amir, M. Ben-Shachar (2023). The
contributions of the cerebellar peduncles and the frontal aslant tract
in mediating speech fluency. Neurobiology of Language 2023;
doi: https://doi.org/10.1162/nol_a_00098
"""
/opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
2026-05-26 22:54:31,864 INFO util.py:154 -- Missing packages: ['ipywidgets']. Run `pip install -U ipywidgets`, then restart the notebook server for rich notebook output.
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/2 MB [00:00]
100%|██████████| 2/2 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/2 MB [00:00]
100%|██████████| 2/2 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/2 MB [00:00]
100%|██████████| 2/2 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/2 MB [00:00]
100%|██████████| 2/2 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/1 MB [00:00]
100%|██████████| 1/1 MB [00:00]
0%| | 0/2 MB [00:00]
100%|██████████| 2/2 MB [00:00]
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
Cell In[1], line 34
30 They decussate, so "cross_midline" is set to True. The Middle CPs are defined
31 by two inclusion ROIs and they use the SCP intermediate ROIs as exclusion ROIs.
32 """
33
---> 34 cp_bundles = abd.cerebellar_bd()
35
36 """
37 The bundle dict has been defined, and now we are ready to run the AFQ pipeline.
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/AFQ/api/bundle_dict.py:1047, in cerebellar_bd()
1045 def cerebellar_bd():
1046 cp_rois = afd.read_cp_templates()
-> 1047 return BundleDict(
1048 {
1049 "Left Inferior Cerebellar Peduncle": {
1050 "include": [
1051 cp_rois["ICP_L_inferior_prob"],
1052 cp_rois["ICP_L_superior_prob"],
1053 ],
1054 "cross_midline": False,
1055 },
1056 "Right Inferior Cerebellar Peduncle": {
1057 "include": [
1058 cp_rois["ICP_R_inferior_prob"],
1059 cp_rois["ICP_R_superior_prob"],
1060 ],
1061 "cross_midline": False,
1062 },
1063 "Left Middle Cerebellar Peduncle": {
1064 "include": [
1065 cp_rois["MCP_L_inferior_prob"],
1066 cp_rois["MCP_R_superior_prob"],
1067 ],
1068 "exclude": [
1069 cp_rois["SCP_L_inter_prob"],
1070 ],
1071 "cross_midline": True,
1072 },
1073 "Right Middle Cerebellar Peduncle": {
1074 "include": [
1075 cp_rois["MCP_R_inferior_prob"],
1076 cp_rois["MCP_L_superior_prob"],
1077 ],
1078 "exclude": [
1079 cp_rois["SCP_R_inter_prob"],
1080 ],
1081 "cross_midline": True,
1082 },
1083 "Left Superior Cerebellar Peduncle": {
1084 "include": [
1085 cp_rois["SCP_L_inferior_prob"],
1086 cp_rois["SCP_L_inter_prob"],
1087 cp_rois["SCP_R_superior_prob"],
1088 ],
1089 "exclude": [
1090 cp_rois["SCP_L_superior_prob"],
1091 ],
1092 "cross_midline": True,
1093 },
1094 "Right Superior Cerebellar Peduncle": {
1095 "include": [
1096 cp_rois["SCP_R_inferior_prob"],
1097 cp_rois["SCP_R_inter_prob"],
1098 cp_rois["SCP_L_superior_prob"],
1099 ],
1100 "exclude": [
1101 cp_rois["SCP_R_superior_prob"],
1102 ],
1103 "cross_midline": True,
1104 },
1105 },
1106 citations={"Jossinger2022"},
1107 )
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/AFQ/api/bundle_dict.py:1240, in BundleDict.__init__(self, bundle_info, resample_to, resample_subject_to, keep_in_memory, citations, criteria_for_all)
1236 raise TypeError(
1237 (f"bundle_info must be a dict, currently a {type(bundle_info)}")
1238 )
1239 if resample_to is None:
-> 1240 resample_to = afd.read_mni_template()
1241 self.resample_to = resample_to
1242 self.resample_subject_to = resample_subject_to
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/AFQ/data/fetch.py:2119, in read_mni_template(resolution, mask, weight)
2092 def read_mni_template(resolution=1, mask=True, weight="T2w"):
2093 """
2094
2095 Reads the MNI T1w or T2w template
(...) 2115
2116 """
2117 template_img = nib.load(
2118 str(
-> 2119 tflow.get(
2120 "MNI152NLin2009cAsym",
2121 desc=None,
2122 resolution=resolution,
2123 suffix=weight,
2124 extension="nii.gz",
2125 )
2126 )
2127 )
2128 if not mask:
2129 return template_img
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/templateflow/client.py:231, in TemplateFlowClient.get(self, template, raise_empty, **kwargs)
174 """
175 Pull files pertaining to one or more templates down.
176
(...) 228
229 """
230 # List files available
--> 231 out_file = self.ls(template, **kwargs)
233 if raise_empty and not out_file:
234 raise Exception('No results found')
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/templateflow/client.py:168, in TemplateFlowClient.ls(self, template, **kwargs)
163 if 'extension' in kwargs:
164 kwargs['extension'] = _normalize_ext(kwargs['extension'])
166 return [
167 Path(p)
--> 168 for p in self.cache.layout.get(
169 template=Query.ANY if template is None else template, return_type='file', **kwargs
170 )
171 ]
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/functools.py:1025, in cached_property.__get__(self, instance, owner)
1023 val = cache.get(self.attrname, _NOT_FOUND)
1024 if val is _NOT_FOUND:
-> 1025 val = self.func(instance)
1026 try:
1027 cache[self.attrname] = val
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/templateflow/conf/cache.py:148, in TemplateFlowCache.layout(self)
145 from .bids import Layout
147 self.ensure()
--> 148 return Layout(
149 self.config.root,
150 validate=False,
151 config='templateflow',
152 indexer=BIDSLayoutIndexer(
153 validate=False,
154 ignore=(re.compile(r'scripts/'), re.compile(r'/\.'), re.compile(r'^\.')),
155 ),
156 )
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/bids/layout/layout.py:188, in BIDSLayout.__init__(self, root, validate, absolute_paths, derivatives, config, sources, regex_search, database_path, reset_database, indexer, is_derivative, **indexer_kwargs)
183 # Do not overwrite indexer variable, so the same configuration is passed to
184 # add_derivatives() below
185 _indexer = indexer or BIDSLayoutIndexer(
186 validate=validate and not is_derivative,
187 )
--> 188 _indexer(self)
190 # Add derivatives if any are found
191 if derivatives:
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/bids/layout/index.py:159, in BIDSLayoutIndexer.__call__(self, layout)
156 self.session.commit()
158 if self.index_metadata:
--> 159 self._index_metadata()
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/bids/layout/index.py:318, in BIDSLayoutIndexer._index_metadata(self)
313 # If key/value pairs in JSON files duplicate ones extracted from files,
314 # we can end up with Tag collisions in the DB. To prevent this, we
315 # store all filename/entity pairs and the value, and then check against
316 # that before adding each new Tag.
317 all_tags = {}
--> 318 for t in self.session.query(Tag).all():
319 key = '{}_{}'.format(t.file_path, t.entity_name)
320 all_tags[key] = str(t.value)
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/sqlalchemy/orm/query.py:2711, in Query.all(self)
2689 def all(self) -> List[_T]:
2690 """Return the results represented by this :class:`_query.Query`
2691 as a list.
2692
(...) 2709 :meth:`_engine.Result.scalars` - v2 comparable method.
2710 """
-> 2711 return self._iter().all()
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/sqlalchemy/engine/result.py:1799, in ScalarResult.all(self)
1791 def all(self) -> Sequence[_R]:
1792 """Return all scalar values in a sequence.
1793
1794 Equivalent to :meth:`_engine.Result.all` except that
(...) 1797
1798 """
-> 1799 return self._allrows()
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/sqlalchemy/engine/result.py:560, in ResultInternal._allrows(self)
556 post_creational_filter = self._post_creational_filter
558 make_row = self._row_getter
--> 560 rows = self._fetchall_impl()
561 made_rows: List[_InterimRowType[_R]]
562 if make_row:
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/sqlalchemy/engine/result.py:1706, in FilterResult._fetchall_impl(self)
1705 def _fetchall_impl(self) -> List[_InterimRowType[Row[Any]]]:
-> 1706 return self._real_result._fetchall_impl()
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/sqlalchemy/engine/result.py:2310, in IteratorResult._fetchall_impl(self)
2308 self._raise_hard_closed()
2309 try:
-> 2310 return list(self.iterator)
2311 finally:
2312 self._soft_close()
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/sqlalchemy/orm/loading.py:220, in instances.<locals>.chunks(size)
218 break
219 else:
--> 220 fetch = cursor._raw_all_rows()
222 if single_entity:
223 proc = process[0]
File /opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/sqlalchemy/engine/result.py:553, in ResultInternal._raw_all_rows(self)
551 assert make_row is not None
552 rows = self._fetchall_impl()
--> 553 return [make_row(row) for row in rows]
KeyboardInterrupt: