[ENH] PyAFQ in the superficial white matter#103
Conversation
|
An example HBN subject results: |
|
Added an interesting output. For each bundle, you can see the distance to the nearest endpoint for every voxel in the gray matter. The distances are in millimeters. This could be thresholded to get a boolean endpoint mask for each bundle. endpoint_distance_visualization.mov |
There was a problem hiding this comment.
Pull Request Overview
This PR introduces modern multi-shell DWI processing capabilities to pyAFQ, along with improvements to tractography, segmentation, and bundle recognition workflows. The primary focus is enhancing analysis of superficial white matter through better seeding, tracking, and cleaning methods.
Key Changes:
- Require T1-weighted images: All workflows now require T1w data for tissue segmentation and interface generation
- Enhanced tracking defaults: Switch to PFT tracking with WM/GM interface seeding and ACT stopping criteria by default
- Improved bundle cleaning: Add IsolationForest cleaning as default for VOF and callosal bundles, plus enhanced Mahalanobis cleaning
Reviewed Changes
Copilot reviewed 43 out of 46 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| setup.cfg | Add scikit-learn, numba, and osqp dependencies |
| AFQ/tasks/data.py | Add T1w tissue segmentation, DAM fitting, MSMT CSD, and asymmetric ODF processing |
| AFQ/tasks/tractography.py | Update default tracking to PFT with WM/GM interface seeding |
| AFQ/recognition/cleaning.py | Add IsolationForest cleaning method and orientation-based Mahalanobis cleaning |
| AFQ/api/bundle_dict.py | Update VOF and callosal bundle definitions with new cleaning methods |
| AFQ/models/ | Add new models for MSMT, DAM fitting, asymmetric filtering, and WM/GM interface generation |
Comments suppressed due to low confidence (2)
AFQ/models/msmt.py:328
- [nitpick] The parameter name 'use_osqppy' is unclear. Consider renaming to 'use_osqp' to better reflect that it uses the OSQP solver.
use_osqppy=True,
|
@arokem right now I am just trying to get the documentation to finish without running out of memory, I think due to increases in parallelization. Anyways, this is otherwise ready for review! |
|
I am experiencing an interesting regression with this PR, where calling: proceeds to use only 4 seeds for tracking (as though I am passing |
|
This is not a regression, its a change in defaults. The old defaults were: New defaults are: I think this is more intuitive but old users might get confused initially. |
|
This old user certainly did 😆 |
|
Hey @36000 : when you get a chance, could you please rebase this on main? Thanks! |
|
Interestingly, with this branch, we found that installing pyAFQ into a clean environment doesn't work (under some circumstances?). Instead, both @johndromero and I see this: I think that it's related to changes in setup/pyproject, but not sure. If I try to install this on top of an already-existing installation (i.e., in an environment where pyAFQ was previously installed) then no such issue. Not sure why this works in the CI and not locally, but thought I'd raise this here so we can debug. |
ea5ed84 to
a756209
Compare
…fix BIDS finding relative to t1 and t1 resampling
| num_chunks=True) | ||
| rng_seed=2025, | ||
| odf_model="csd_aodf", | ||
| trx=False) |
There was a problem hiding this comment.
Why is trx switched off? Do we want to add some text explaining these settings (particularly the "aodf" part)?
There was a problem hiding this comment.
It should be on, and odf_model="csd_aodf" is no longer necessary (it is the default). I must have changed this during testing at some point
|
The first tutorial example now runs on my primitive mac (no onnxruntime), but I end up with this: |
|
@arokem try again. I introduced a bug in the last commit while I was trying to fix other things with PVE resampling. Now it should be working |
AFQ/tasks/data.py
Outdated
| sh_coeff = nib.load(csd_params).get_fdata() | ||
|
|
||
| logger.info("Applying unified filtering to generate " | ||
| "asymmetric CSD CSD ODFs...") |
There was a problem hiding this comment.
| "asymmetric CSD CSD ODFs...") | |
| "asymmetric CSD ODFs...") |
|
Yep, I can run the first example! I did notice that the html output no longer has an anatomical image embedded in it. I think that we had the T1 in there at some point? |
|
I guess we can sort that out on a separate PR after we merge this one. Looks like there are still some test failures on the CI, though. |
|
@arokem I think I fixed the T1 not showing up |
|
Yep! It works now. I think we might be ready to merge this PR. WDYT? |
|
Oh sorry, I think I am still running into some issues. In particular, I tried to run the pyafq2 example and running into some errors. I'll work to figure out what these errors and report back. |
|
OK - looks like when I run things in the "pyAFQ2" mode I get the onnxruntime errors, unless I also provide a brain_mask_definition. I think that's probably fine, but I might suggest to use the HBN data, and to add the |
|
Or potentially at least as a commented-out block of code: |
|
@arokem I made it so the pyafq 2 example uses a brain mask based on the freesurfer segmentation. This excludes the CSF, but seems to work. |
|
This is now ready to be merged, I believe. We'll continue to polish and work on remaining items for version 3.0 on separate PRs. |



This is a few things I have been trying out to modernize pyAFQ on multi-shell images, as well as some random things.
These are used: