Skip to content

Commit

Permalink
Merge pull request #101 from jhlegarreta/RelocatePlotDWIFromEddy
Browse files Browse the repository at this point in the history
ENH: Add DWI volume plot method
  • Loading branch information
jhlegarreta authored May 9, 2024
2 parents 441bf34 + ba1f12a commit a8b3927
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 1 deletion.
17 changes: 17 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ jobs:
name: Install package
command: pip install .[test]

- restore_cache:
keys:
- apt-v0
paths:
- /var/lib/apt

- run:
name: Install texlive
command: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends dvipng texlive texlive-latex-extra cm-super
- save_cache:
key: apt-v0
paths:
- /var/lib/apt

- restore_cache:
keys:
- tf-v0
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/build_test_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ jobs:
- name: Display Python version
run: python -c "import sys; print(sys.version)"

- uses: actions/cache@v4
with:
path: /var/lib/apt
key: apt-cache-v0
restore-keys: |
apt-cache-v0
- name: Install tex
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends dvipng texlive texlive-latex-extra cm-super
- name: Install package
run: pip install $PACKAGE
- name: Verify installation
Expand Down
56 changes: 56 additions & 0 deletions nireports/reportlets/modality/dwi.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,66 @@
# https://www.nipreps.org/community/licensing/
#
"""Visualizations for diffusion MRI data."""
import nibabel as nb
import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import art3d
from nilearn.plotting import plot_anat


def plot_dwi(dataobj, affine, gradient=None, **kwargs):
"""
Plot orthogonal (axial, coronal, sagittal) slices of a given DWI volume. The
slices displayed are determined by a tuple contained in the ``cut_coords``
keyword argument.
Parameters
----------
dataobj : :obj:`numpy.ndarray`
DWI volume data: a single 3D volume from a given gradient direction.
affine : :obj:`numpy.ndarray`
Affine transformation matrix.
gradient : :obj:`numpy.ndarray`
Gradient values in RAS+b format at the chosen gradient direction.
kwargs : :obj:`dict`
Extra args given to :obj:`nilearn.plotting.plot_anat()`.
Returns
-------
:class:`nilearn.plotting.displays.OrthoSlicer` or None
An instance of the OrthoSlicer class. If ``output_file`` is defined,
None is returned.
"""

plt.rcParams.update(
{
"text.usetex": True,
"font.family": "sans-serif",
"font.sans-serif": ["Helvetica"],
}
)

affine = np.diag(nb.affines.voxel_sizes(affine).tolist() + [1])
affine[:3, 3] = -1.0 * (affine[:3, :3] @ ((np.array(dataobj.shape) - 1) * 0.5))

vmax = kwargs.pop("vmax", None) or np.percentile(dataobj, 98)
cut_coords = kwargs.pop("cut_coords", None) or (0, 0, 0)

return plot_anat(
nb.Nifti1Image(dataobj, affine, None),
vmax=vmax,
cut_coords=cut_coords,
title=(
r"Reference $b$=0"
if gradient is None
else f"""\
$b$={gradient[3].astype(int)}, \
$\\vec{{b}}$ = ({', '.join(str(v) for v in gradient[:3])})"""
),
**kwargs,
)


def plot_heatmap(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0 0 0 0 0 0 0 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
0 0 0 0 0 0 0 -1 -0.002 0.026 -0.591 0.236 0.893 -0.796 -0.234 -0.936 -0.506 -0.346 -0.457 0.487
0 0 0 0 0 0 0 0 1 0.649 -0.766 -0.524 -0.259 0.129 0.93 0.14 -0.845 -0.847 -0.631 -0.389
0 0 0 0 0 0 0 0 0 0.76 0.252 0.818 0.368 0.591 0.284 0.324 -0.175 -0.402 -0.627 0.782
Binary file not shown.
26 changes: 25 additions & 1 deletion nireports/tests/test_dwi.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,35 @@
"""Test DWI reportlets."""

import pytest
from pathlib import Path

import nibabel as nb
import numpy as np
from matplotlib import pyplot as plt

from nireports.reportlets.modality.dwi import plot_gradients
from nireports.reportlets.modality.dwi import plot_dwi, plot_gradients


def test_plot_dwi(tmp_path, testdata_path, outdir):
"""Check the plot of DWI data."""

stem = 'ds000114_sub-01_ses-test_desc-trunc_dwi'
dwi_img = nb.load(testdata_path / f'{stem}.nii.gz')
affine = dwi_img.affine

bvecs = np.loadtxt(testdata_path / f'{stem}.bvec').T
bvals = np.loadtxt(testdata_path / f'{stem}.bval')

gradients = np.hstack([bvecs, bvals[:, None]])

# Pick a random volume to show
rng = np.random.default_rng(1234)
idx = rng.integers(low=0, high=dwi_img.shape[-1], size=1).item()

_ = plot_dwi(dwi_img.get_fdata()[..., idx], affine, gradient=gradients[idx])

if outdir is not None:
plt.savefig(outdir / f'{stem}.svg', bbox_inches='tight')


@pytest.mark.parametrize(
Expand Down

0 comments on commit a8b3927

Please sign in to comment.