Callosal bundles using AFQ API#
An example using the AFQ API to find callosal bundles using the templates from: http://hdl.handle.net/1773/34926
import os.path as op
import matplotlib.pyplot as plt
import nibabel as nib
import plotly
from AFQ.api.group import GroupAFQ
import AFQ.api.bundle_dict as abd
from AFQ.definitions.image import RoiImage
import AFQ.data.fetch as afd
2026-05-19 00:55:40,679 INFO util.py:154 -- Missing packages: ['ipywidgets']. Run `pip install -U ipywidgets`, then restart the notebook server for rich notebook output.
Get some example data#
Retrieves Stanford HARDI dataset.
afd.organize_stanford_data(clear_previous_afq="track")
Set tractography parameters (optional)#
We make this tracking_params which we will pass to the GroupAFQ object which specifies that we want 100,000 seeds randomly distributed in the ROIs of every bundle.
We only do this to make this example faster and consume less space.
tracking_params = dict(seed_mask=RoiImage(),
n_seeds=25000,
random_seeds=True,
rng_seed=42)
Set segmentation parameters (optional)#
We make this segmentation_params which we will pass to the GroupAFQ object which specifies that we want to clip the extracted tract profiles to only be between the two ROIs.
We do this because tract profiles become less reliable as the bundles approach the gray matter-white matter boundary. On some of the non-callosal bundles, ROIs are not in a good position to clip edges. In these cases, one can remove the first and last nodes in a tract profile.
segmentation_params = {"clip_edges": True}
Initialize a GroupAFQ object:#
We specify bundle_info as the callosal bundles only
(abd.callosal_bd). If we want to segment both the callosum
and the other bundles, we would pass
abd.callosal_bd() + abd.default_bd()
instead. This would tell the GroupAFQ object to use bundles from both
the standard and callosal templates.
myafq = GroupAFQ(
bids_path=op.join(afd.afq_home, 'stanford_hardi'),
dwi_preproc_pipeline='vistasoft',
t1_preproc_pipeline='freesurfer',
bundle_info=abd.callosal_bd(),
tracking_params=tracking_params,
segmentation_params=segmentation_params,
viz_backend_spec='plotly_no_gif')
# Calling export all produces all of the outputs of processing, including
# tractography, scalar maps, tract profiles and visualizations:
myafq.export_all()
INFO:bidsschematools:No schema path specified, defaulting to the bundled schema, `/opt/hostedtoolcache/Python/3.13.13/x64/lib/python3.13/site-packages/bidsschematools/data/schema.json`.
INFO:AFQ:Using the following files for subject 01 and session 01:
INFO:AFQ: DWI: /home/runner/AFQ_data/stanford_hardi/derivatives/vistasoft/sub-01/ses-01/dwi/sub-01_ses-01_dwi.nii.gz
INFO:AFQ: BVAL: /home/runner/AFQ_data/stanford_hardi/derivatives/vistasoft/sub-01/ses-01/dwi/sub-01_ses-01_dwi.bval
INFO:AFQ: BVEC: /home/runner/AFQ_data/stanford_hardi/derivatives/vistasoft/sub-01/ses-01/dwi/sub-01_ses-01_dwi.bvec
INFO:AFQ: T1: /home/runner/AFQ_data/stanford_hardi/derivatives/freesurfer/sub-01/ses-01/anat/sub-01_ses-01_T1w.nii.gz
WARNING:AFQ:It is recommended to provide CSF/GM/WM segmentations using PVEImage or PVEImages in AFQ.definitions.image. Otherwise, SynthSeg2 will be used
INFO:AFQ:Calculating _b0ref.nii.gz...
INFO:AFQ:_b0ref.nii.gz completed. Saving to /home/runner/AFQ_data/stanford_hardi/derivatives/afq/sub-01/ses-01/dwi/sub-01_ses-01_b0ref.nii.gz
INFO:AFQ:Calculating _desc-brain_mask.nii.gz...
2026-05-19 00:56:05.194961923 [W:onnxruntime:Default, device_discovery.cc:133 GetPciBusId] Skipping pci_bus_id for PCI path at "/sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0004:00/MSFT1000:00/5620e0c7-8062-4dce-aeb7-520c7ef76171" because filename "5620e0c7-8062-4dce-aeb7-520c7ef76171" did not match expected pattern of [0-9a-f]+:[0-9a-f]+:[0-9a-f]+[.][0-9a-f]+
INFO:AFQ:Calculating _desc-T1w_mask.nii.gz...
0%| | 0/23 MB [00:00]
9%|▊ | 2/23 MB [00:00]
17%|█▋ | 4/23 MB [00:00]
30%|███ | 7/23 MB [00:00]
43%|████▎ | 10/23 MB [00:00]
65%|██████▌ | 15/23 MB [00:00]
87%|████████▋ | 20/23 MB [00:00]
100%|██████████| 23/23 MB [00:00]
0%| | 0/36 MB [00:00]
6%|▌ | 2/36 MB [00:00]
14%|█▍ | 5/36 MB [00:00]
28%|██▊ | 10/36 MB [00:00]
39%|███▉ | 14/36 MB [00:00]
56%|█████▌ | 20/36 MB [00:00]
81%|████████ | 29/36 MB [00:00]
100%|██████████| 36/36 MB [00:00]
0%| | 0/2 MB [00:00]
100%|██████████| 2/2 MB [00:00]
100%|██████████| 2/2 MB [00:00]
0%| | 0/48 MB [00:00]
4%|▍ | 2/48 MB [00:00]
10%|█ | 5/48 MB [00:00]
19%|█▉ | 9/48 MB [00:00]
27%|██▋ | 13/48 MB [00:00]
42%|████▏ | 20/48 MB [00:00]
58%|█████▊ | 28/48 MB [00:00]
73%|███████▎ | 35/48 MB [00:00]
90%|████████▉ | 43/48 MB [00:00]
100%|██████████| 48/48 MB [00:00]
INFO:AFQ:Running mindgrab...
Create Group Density Maps:#
pyAFQ can make density maps of streamline counts per subject/session
by calling myafq.export("density_map"). When using GroupAFQ, you can also
combine these into one file by calling myafq.export_group_density().
group_density = myafq.export_group_density()
group_density = nib.load(group_density).get_fdata()
fig, ax = plt.subplots(1)
ax.matshow(
group_density[:, :, group_density.shape[-1] // 2, 0],
cmap='viridis')
ax.axis("off")
Visualizing bundles and tract profiles:#
This would run the script and visualize the bundles using the plotly interactive visualization, which should automatically open in a new browser window.
bundle_html = myafq.export("all_bundles_figure")
plotly.io.show(bundle_html["01"][0])