Repository navigation
Conversation
compute_label_bounding_boxes used scipy.ndimage.find_objects when SciPy was installed and per-label voxel coordinates otherwise. The SciPy path mapped the exclusive slice stop to RAS, so its boxes were one voxel larger along each image axis, and it transformed only two corners, which is wrong for affines that are not diagonal. Relative terms selected different tracts depending on an undeclared optional dependency. Keep a single NumPy implementation with the semantics of the fallback, which is the one tested in CI: the box of a label spans the RAS coordinates of its voxel centres. Group the voxels by label with one sort instead of scanning the image once per label. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 4, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
compute_label_bounding_boxeshad two code paths (see #100):ndimage.find_objectsslices were mapped to RAS with their exclusivestop, so every box was one voxel larger along each image axis; it also transformed only the two corner points, which is wrong for an affine that is not diagonal;The relative terms (
anterior_of,superior_of,medial_of, ...) therefore depended on an undeclared optional dependency.The change
A single NumPy implementation with the semantics of the former fallback: the box of a label spans the RAS coordinates of its voxel centres. Non-zero voxels are grouped by label with one sort and
np.minimum.reduceat/np.maximum.reduceat. Label keys are plainint. The SciPy branch is removed.Behaviour change
Users who had SciPy installed will get slightly different results for relative terms: their label boxes shrink by one voxel on one side per axis. On the test atlas (
IIT3mean_desikan_2009.nii.gz, 1 mm voxels, affine x axis negative) the SciPy boxes were exactly 1 mm larger on the left, anterior and superior sides of every one of the 183 labels; the other three sides were identical.Measured on the test dataset (6783 tracts):
cortico_spinal.left385/385/385,cortico_spinal.right0/0/0,uncinate.left102/102/102 (it usesanterior_of(amygdala.side)),uncinate.right0/0/0,all_commissural3/3/3.anterior_ofdiffers for 165 labels (median 41, max 138 tracts),superior_offor 165 labels (median 69, max 138),lateral_of.left/medial_of.rightfor 92 labels (median 88, max 382);posterior_of,inferior_of,medial_of.left/lateral_of.rightare unchanged. So whole queries that combine a relative term with other terms may or may not change; single relative terms on their own do.Speed of
compute_label_bounding_boxesalone on the test atlas (182×218×182, 183 labels, min of 3): old SciPy path 0.10 s, old fallback 9.0 s, new 0.35 s.Testing
tract_querier/tests/test_label_bounding_boxes.py: the example of BUG: label bounding boxes differ depending on whether SciPy is installed #100 (affinediag(-2, 2, 2), expected[-6, 4, 4, -4, 6, 6]); a random atlas with negative labels and a non-diagonal affine compared with per-label min/max of the voxel coordinates; an all-zero image. With SciPy installed, the first two fail on master.python -m pytest -q -p no:cacheprovider tract_querier(with SciPy installed in the venv for the comparison): 45 passed, 1 skipped.Merge order
Independent of #122 and #129 (a trial merge with them has no conflict). #140 (#117, same file) is meant to be merged after this one.
Closes #100
🤖 Generated with Claude Code