Skip to content

Commit

Permalink
Merge branch 'master' into FixElapsedRuntimeFormat
Browse files Browse the repository at this point in the history
  • Loading branch information
oesteban authored Jan 13, 2025
2 parents 804b055 + f05769e commit 02159a5
Show file tree
Hide file tree
Showing 12 changed files with 25 additions and 96 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ['3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion docs/source/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ If, for some reason, you really need a custom installation,
First, please make sure you have the execution system dependencies
installed (see below).
Second, the latest development version of MRIQC can be installed from
github using ``pip`` on a Python 3 environment:
github using ``pip`` on a Python 3 environment::

python -m pip install -U mriqc

Expand Down
2 changes: 1 addition & 1 deletion mriqc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@

from mriqc._version import __version__

__copyright__ = 'Copyright 2022, The NiPreps Developers'
__copyright__ = 'Copyright 2016-2024, The NiPreps Developers'
__download__ = f'https://github.com/nipreps/mriqc/archive/{__version__}.tar.gz'
__all__ = ['__version__', '__copyright__', '__download__']
2 changes: 1 addition & 1 deletion mriqc/bin/labeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def main():
finished[j - 1] = finished[j - 1] + 1
hold[j - 1, i - 1] = int(file[i][j])
finished = np.divide(np.round(np.divide(finished, total) * 1000), 10)
print(f"Completed: {' '.join(['%g%%' % f for f in finished])}")
print(f'Completed: {" ".join(["%g%%" % f for f in finished])}')
print(f'Total: {np.round(np.divide(np.sum(finished), 3))}%')
input('Waiting: [enter]')

Expand Down
4 changes: 2 additions & 2 deletions mriqc/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,8 @@ def parse_args(args=None, namespace=None):
selected_label = set(config.execution.participant_label)
if missing_subjects := selected_label - set(participant_label):
parser.error(
"One or more participant labels were not found in the BIDS directory: "
f"{', '.join(missing_subjects)}."
'One or more participant labels were not found in the BIDS directory: '
f'{", ".join(missing_subjects)}.'
)
participant_label = selected_label

Expand Down
12 changes: 6 additions & 6 deletions mriqc/instrumentation/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ def run(self, *args, **kwargs):

# Write headers (comment trace + header row)
_header = [
f"# MRIQC Resource recorder started tracking PID {self._pid} "
f"{datetime.now(tz=UTC).strftime('(%Y/%m/%d; %H:%M:%S)')}",
f'# MRIQC Resource recorder started tracking PID {self._pid} '
f'{datetime.now(tz=UTC).strftime("(%Y/%m/%d; %H:%M:%S)")}',
'\t'.join(('timestamp', *SAMPLE_ATTRS)).replace(
'memory_info', 'mem_rss_mb\tmem_vsm_mb'
),
Expand All @@ -198,8 +198,8 @@ def run(self, *args, **kwargs):
sample2file(self._pid, fd=_logfile, timestamp=wait_til)
except psutil.NoSuchProcess:
print(
f"# MRIQC Resource recorder killed "
f"{datetime.now(tz=UTC).strftime('(%Y/%m/%d; %H:%M:%S)')}",
f'# MRIQC Resource recorder finished '
f'{datetime.now(tz=UTC).strftime("(%Y/%m/%d; %H:%M:%S)")}',
file=_logfile,
)
_logfile.flush()
Expand All @@ -216,6 +216,6 @@ def stop(self, *args):
self._done.set()
with Path(self._logfile).open('a') as f:
f.write(
f"# MRIQC Resource recorder finished "
f"{datetime.now(tz=UTC).strftime('(%Y/%m/%d; %H:%M:%S)')}",
f'# MRIQC Resource recorder finished '
f'{datetime.now(tz=UTC).strftime("(%Y/%m/%d; %H:%M:%S)")}',
)
2 changes: 1 addition & 1 deletion mriqc/instrumentation/viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def plot(filename, param='mem_vsm_mb', mask_processes=(), out_file=None):
for pid in pids:
pid_info = data[data['pid'] == pid]
try:
label = f"{pid_info['name'].values[0]}"
label = f'{pid_info["name"].values[0]}'
except KeyError:
label = f'{pid}'

Expand Down
3 changes: 1 addition & 2 deletions mriqc/interfaces/anatomical.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ def _run_interface(self, runtime): # pylint: disable=R0914,E1101

if np.sum(segdata > 0) < 1e3:
raise RuntimeError(
'Input segmentation data is likely corrupt. '
'MRIQC failed to process this dataset.'
'Input segmentation data is likely corrupt. MRIQC failed to process this dataset.'
)

# Load air, artifacts and head masks
Expand Down
80 changes: 5 additions & 75 deletions mriqc/interfaces/diffusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import nibabel as nb
import numpy as np
import scipy.ndimage as nd
from dipy.core.gradients import gradient_table
from dipy.stats.qc import find_qspace_neighbors
from nipype.interfaces.base import (
BaseInterfaceInputSpec as _BaseInterfaceInputSpec,
)
Expand Down Expand Up @@ -339,7 +341,9 @@ def _run_interface(self, runtime):
bvecs = np.loadtxt(self._results['out_bvec_file']).T
bvals = np.loadtxt(self._results['out_bval_file'])

self._results['qspace_neighbors'] = _find_qspace_neighbors(bvals, bvecs)
gtab = gradient_table(bvals, bvecs=bvecs)

self._results['qspace_neighbors'] = find_qspace_neighbors(gtab)
self._results['out_bmatrix'] = np.hstack((bvecs, bvals[:, np.newaxis])).tolist()

return runtime
Expand Down Expand Up @@ -1386,80 +1390,6 @@ def get_spike_mask(
return spike_mask


def _find_qspace_neighbors(bvals: np.ndarray, bvecs: np.ndarray) -> list[tuple[int, int]]:
"""
Create a mapping of dwi volume index to its nearest neighbor in q-space.
This function implements an approximate nearest neighbor search in q-space
(excluding delta encoding). It calculates the Cartesian distance between
q-space representations of each diffusion-weighted imaging (DWI) volume
(represented by b-values and b-vectors) and identifies the closest one
(excluding the volume itself and b=0 volumes).
Parameters
----------
bvals : :obj:`~numpy.ndarray`
List of b-values.
bvecs : :obj:`~numpy.ndarray`
Table of b-vectors.
Returns
-------
:obj:`list` of :obj:`tuple`
A list of 2-tuples indicating the nearest q-space neighbor
of each dwi volume.
Examples
--------
>>> _find_qspace_neighbors(
... np.array([0, 1000, 1000, 2000]),
... np.array([
... [1, 0, 0],
... [1, 0, 0],
... [0.99, 0.0001, 0.0001],
... [1, 0, 0]
... ]),
... )
[(1, 2), (2, 1), (3, 1)]
Notes
-----
This is a copy of DIPY's code to be removed (and just imported) as soon as
a new release of DIPY is cut including
`dipy/dipy#3156 <https://github.com/dipy/dipy/pull/3156>`__.
"""
from dipy.core.geometry import cart_distance
from dipy.core.gradients import gradient_table

gtab = gradient_table(bvals, bvecs)

dwi_neighbors: list[tuple[int, int]] = []

# Only correlate the b>0 images
dwi_indices = np.flatnonzero(~gtab.b0s_mask)

# Get a pseudo-qspace value for b>0s
qvecs = np.sqrt(gtab.bvals)[:, np.newaxis] * gtab.bvecs

for dwi_index in dwi_indices:
qvec = qvecs[dwi_index]

# Calculate distance in q-space, accounting for symmetry
pos_dist = cart_distance(qvec[np.newaxis, :], qvecs)
neg_dist = cart_distance(qvec[np.newaxis, :], -qvecs)
distances = np.min(np.column_stack([pos_dist, neg_dist]), axis=1)

# Be sure we don't select the image as its own neighbor
distances[dwi_index] = np.inf
# Or a b=0
distances[gtab.b0s_mask] = np.inf
neighbor_index = np.argmin(distances)
dwi_neighbors.append((dwi_index, neighbor_index))

return dwi_neighbors


def noise_piesno(data: np.ndarray, n_channels: int = 4) -> (np.ndarray, np.ndarray):
"""
Estimates noise in raw diffusion MRI (dMRI) data using the PIESNO algorithm.
Expand Down
6 changes: 3 additions & 3 deletions mriqc/utils/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def write_derivative_description(bids_dir, deriv_dir):
if 'MRIQC_DOCKER_TAG' in os.environ:
desc['GeneratedBy'][0]['Container'] = {
'Type': 'docker',
'Tag': f"nipreps/mriqc:{os.environ['MRIQC_DOCKER_TAG']}",
'Tag': f'nipreps/mriqc:{os.environ["MRIQC_DOCKER_TAG"]}',
}
if 'MRIQC_SINGULARITY_URL' in os.environ:
desc['GeneratedBy'][0]['Container'] = {
Expand All @@ -83,7 +83,7 @@ def write_derivative_description(bids_dir, deriv_dir):
orig_desc = json.loads(fname.read_text())

if 'Name' in orig_desc:
desc['Name'] = f"MRIQC - {orig_desc['Name']}"
desc['Name'] = f'MRIQC - {orig_desc["Name"]}'
else:
desc['Name'] = 'MRIQC - MRI Quality Control'

Expand Down Expand Up @@ -191,6 +191,6 @@ def derive_bids_fname(
else:
bidts.insert(position, entity.strip('_'))

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

return retval.absolute() if absolute else retval
2 changes: 1 addition & 1 deletion mriqc/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ def initialize_meta_and_data(

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


Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ classifiers = [
]
dependencies = [
"acres",
"dipy",
"dipy >= 1.10.0",
'importlib_resources; python_version < "3.9"', # jinja2 imports deprecated function removed in 2.1
"markupsafe ~= 2.0.1",
"matplotlib",
Expand Down Expand Up @@ -48,7 +48,7 @@ dynamic = ["version"]
license = "Apache-2.0"
name = "mriqc"
readme = "README.rst"
requires-python = ">=3.8"
requires-python = ">=3.9"

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

0 comments on commit 02159a5

Please sign in to comment.