Skip to content

Commit f05769e

Browse files
authored
Merge pull request #1369 from jhlegarreta/RemoveRedundantDIPYMethod
ENH: Remove redundant DIPY function
2 parents d3e78a4 + 8ad9e49 commit f05769e

File tree

10 files changed

+23
-94
lines changed

10 files changed

+23
-94
lines changed

.github/workflows/pythonpackage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
runs-on: ubuntu-latest
2424
strategy:
2525
matrix:
26-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
26+
python-version: ['3.9', '3.10', '3.11', '3.12']
2727

2828
steps:
2929
- uses: actions/checkout@v4

mriqc/bin/labeler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def main():
5454
finished[j - 1] = finished[j - 1] + 1
5555
hold[j - 1, i - 1] = int(file[i][j])
5656
finished = np.divide(np.round(np.divide(finished, total) * 1000), 10)
57-
print(f"Completed: {' '.join(['%g%%' % f for f in finished])}")
57+
print(f'Completed: {" ".join(["%g%%" % f for f in finished])}')
5858
print(f'Total: {np.round(np.divide(np.sum(finished), 3))}%')
5959
input('Waiting: [enter]')
6060

mriqc/cli/parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -603,8 +603,8 @@ def parse_args(args=None, namespace=None):
603603
selected_label = set(config.execution.participant_label)
604604
if missing_subjects := selected_label - set(participant_label):
605605
parser.error(
606-
"One or more participant labels were not found in the BIDS directory: "
607-
f"{', '.join(missing_subjects)}."
606+
'One or more participant labels were not found in the BIDS directory: '
607+
f'{", ".join(missing_subjects)}.'
608608
)
609609
participant_label = selected_label
610610

mriqc/instrumentation/resources.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ def run(self, *args, **kwargs):
175175

176176
# Write headers (comment trace + header row)
177177
_header = [
178-
f"# MRIQC Resource recorder started tracking PID {self._pid} "
179-
f"{datetime.now(tz=UTC).strftime('(%Y/%m/%d; %H:%M:%S)')}",
178+
f'# MRIQC Resource recorder started tracking PID {self._pid} '
179+
f'{datetime.now(tz=UTC).strftime("(%Y/%m/%d; %H:%M:%S)")}',
180180
'\t'.join(('timestamp', *SAMPLE_ATTRS)).replace(
181181
'memory_info', 'mem_rss_mb\tmem_vsm_mb'
182182
),
@@ -198,8 +198,8 @@ def run(self, *args, **kwargs):
198198
sample2file(self._pid, fd=_logfile, timestamp=wait_til)
199199
except psutil.NoSuchProcess:
200200
print(
201-
f"# MRIQC Resource recorder killed "
202-
f"{datetime.now(tz=UTC).strftime('(%Y/%m/%d; %H:%M:%S)')}",
201+
f'# MRIQC Resource recorder finished '
202+
f'{datetime.now(tz=UTC).strftime("(%Y/%m/%d; %H:%M:%S)")}',
203203
file=_logfile,
204204
)
205205
_logfile.flush()
@@ -216,6 +216,6 @@ def stop(self, *args):
216216
self._done.set()
217217
with Path(self._logfile).open('a') as f:
218218
f.write(
219-
f"# MRIQC Resource recorder finished "
220-
f"{datetime.now(tz=UTC).strftime('(%Y/%m/%d; %H:%M:%S)')}",
219+
f'# MRIQC Resource recorder finished '
220+
f'{datetime.now(tz=UTC).strftime("(%Y/%m/%d; %H:%M:%S)")}',
221221
)

mriqc/instrumentation/viz.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def plot(filename, param='mem_vsm_mb', mask_processes=(), out_file=None):
4545
for pid in pids:
4646
pid_info = data[data['pid'] == pid]
4747
try:
48-
label = f"{pid_info['name'].values[0]}"
48+
label = f'{pid_info["name"].values[0]}'
4949
except KeyError:
5050
label = f'{pid}'
5151

mriqc/interfaces/anatomical.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ def _run_interface(self, runtime): # pylint: disable=R0914,E1101
124124

125125
if np.sum(segdata > 0) < 1e3:
126126
raise RuntimeError(
127-
'Input segmentation data is likely corrupt. '
128-
'MRIQC failed to process this dataset.'
127+
'Input segmentation data is likely corrupt. MRIQC failed to process this dataset.'
129128
)
130129

131130
# Load air, artifacts and head masks

mriqc/interfaces/diffusion.py

Lines changed: 5 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import nibabel as nb
2828
import numpy as np
2929
import scipy.ndimage as nd
30+
from dipy.core.gradients import gradient_table
31+
from dipy.stats.qc import find_qspace_neighbors
3032
from nipype.interfaces.base import (
3133
BaseInterfaceInputSpec as _BaseInterfaceInputSpec,
3234
)
@@ -339,7 +341,9 @@ def _run_interface(self, runtime):
339341
bvecs = np.loadtxt(self._results['out_bvec_file']).T
340342
bvals = np.loadtxt(self._results['out_bval_file'])
341343

342-
self._results['qspace_neighbors'] = _find_qspace_neighbors(bvals, bvecs)
344+
gtab = gradient_table(bvals, bvecs=bvecs)
345+
346+
self._results['qspace_neighbors'] = find_qspace_neighbors(gtab)
343347
self._results['out_bmatrix'] = np.hstack((bvecs, bvals[:, np.newaxis])).tolist()
344348

345349
return runtime
@@ -1386,80 +1390,6 @@ def get_spike_mask(
13861390
return spike_mask
13871391

13881392

1389-
def _find_qspace_neighbors(bvals: np.ndarray, bvecs: np.ndarray) -> list[tuple[int, int]]:
1390-
"""
1391-
Create a mapping of dwi volume index to its nearest neighbor in q-space.
1392-
1393-
This function implements an approximate nearest neighbor search in q-space
1394-
(excluding delta encoding). It calculates the Cartesian distance between
1395-
q-space representations of each diffusion-weighted imaging (DWI) volume
1396-
(represented by b-values and b-vectors) and identifies the closest one
1397-
(excluding the volume itself and b=0 volumes).
1398-
1399-
Parameters
1400-
----------
1401-
bvals : :obj:`~numpy.ndarray`
1402-
List of b-values.
1403-
bvecs : :obj:`~numpy.ndarray`
1404-
Table of b-vectors.
1405-
1406-
Returns
1407-
-------
1408-
:obj:`list` of :obj:`tuple`
1409-
A list of 2-tuples indicating the nearest q-space neighbor
1410-
of each dwi volume.
1411-
1412-
Examples
1413-
--------
1414-
>>> _find_qspace_neighbors(
1415-
... np.array([0, 1000, 1000, 2000]),
1416-
... np.array([
1417-
... [1, 0, 0],
1418-
... [1, 0, 0],
1419-
... [0.99, 0.0001, 0.0001],
1420-
... [1, 0, 0]
1421-
... ]),
1422-
... )
1423-
[(1, 2), (2, 1), (3, 1)]
1424-
1425-
Notes
1426-
-----
1427-
This is a copy of DIPY's code to be removed (and just imported) as soon as
1428-
a new release of DIPY is cut including
1429-
`dipy/dipy#3156 <https://github.com/dipy/dipy/pull/3156>`__.
1430-
1431-
"""
1432-
from dipy.core.geometry import cart_distance
1433-
from dipy.core.gradients import gradient_table
1434-
1435-
gtab = gradient_table(bvals, bvecs)
1436-
1437-
dwi_neighbors: list[tuple[int, int]] = []
1438-
1439-
# Only correlate the b>0 images
1440-
dwi_indices = np.flatnonzero(~gtab.b0s_mask)
1441-
1442-
# Get a pseudo-qspace value for b>0s
1443-
qvecs = np.sqrt(gtab.bvals)[:, np.newaxis] * gtab.bvecs
1444-
1445-
for dwi_index in dwi_indices:
1446-
qvec = qvecs[dwi_index]
1447-
1448-
# Calculate distance in q-space, accounting for symmetry
1449-
pos_dist = cart_distance(qvec[np.newaxis, :], qvecs)
1450-
neg_dist = cart_distance(qvec[np.newaxis, :], -qvecs)
1451-
distances = np.min(np.column_stack([pos_dist, neg_dist]), axis=1)
1452-
1453-
# Be sure we don't select the image as its own neighbor
1454-
distances[dwi_index] = np.inf
1455-
# Or a b=0
1456-
distances[gtab.b0s_mask] = np.inf
1457-
neighbor_index = np.argmin(distances)
1458-
dwi_neighbors.append((dwi_index, neighbor_index))
1459-
1460-
return dwi_neighbors
1461-
1462-
14631393
def noise_piesno(data: np.ndarray, n_channels: int = 4) -> (np.ndarray, np.ndarray):
14641394
"""
14651395
Estimates noise in raw diffusion MRI (dMRI) data using the PIESNO algorithm.

mriqc/utils/bids.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def write_derivative_description(bids_dir, deriv_dir):
6868
if 'MRIQC_DOCKER_TAG' in os.environ:
6969
desc['GeneratedBy'][0]['Container'] = {
7070
'Type': 'docker',
71-
'Tag': f"nipreps/mriqc:{os.environ['MRIQC_DOCKER_TAG']}",
71+
'Tag': f'nipreps/mriqc:{os.environ["MRIQC_DOCKER_TAG"]}',
7272
}
7373
if 'MRIQC_SINGULARITY_URL' in os.environ:
7474
desc['GeneratedBy'][0]['Container'] = {
@@ -83,7 +83,7 @@ def write_derivative_description(bids_dir, deriv_dir):
8383
orig_desc = json.loads(fname.read_text())
8484

8585
if 'Name' in orig_desc:
86-
desc['Name'] = f"MRIQC - {orig_desc['Name']}"
86+
desc['Name'] = f'MRIQC - {orig_desc["Name"]}'
8787
else:
8888
desc['Name'] = 'MRIQC - MRI Quality Control'
8989

@@ -191,6 +191,6 @@ def derive_bids_fname(
191191
else:
192192
bidts.insert(position, entity.strip('_'))
193193

194-
retval = newpath / f"{'_'.join(bidts)}_{newsuffix}.{newext.strip('.')}"
194+
retval = newpath / f'{"_".join(bidts)}_{newsuffix}.{newext.strip(".")}'
195195

196196
return retval.absolute() if absolute else retval

mriqc/utils/misc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ def initialize_meta_and_data(
501501

502502
config.loggers.cli.log(
503503
25,
504-
f"File size ('{mod}'): {_max_size:.2f}|{np.mean(size):.2f} " 'GB [maximum|average].',
504+
f"File size ('{mod}'): {_max_size:.2f}|{np.mean(size):.2f} GB [maximum|average].",
505505
)
506506

507507

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ classifiers = [
1818
]
1919
dependencies = [
2020
"acres",
21-
"dipy",
21+
"dipy >= 1.10.0",
2222
'importlib_resources; python_version < "3.9"', # jinja2 imports deprecated function removed in 2.1
2323
"markupsafe ~= 2.0.1",
2424
"matplotlib",
@@ -48,7 +48,7 @@ dynamic = ["version"]
4848
license = "Apache-2.0"
4949
name = "mriqc"
5050
readme = "README.rst"
51-
requires-python = ">=3.8"
51+
requires-python = ">=3.9"
5252

5353
[project.urls]
5454
"Docker Images" = "https://hub.docker.com/r/nipreps/mriqc/tags/"

0 commit comments

Comments
 (0)