Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions rabies/analysis_pkg/diagnosis_pkg/analysis_QC.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import SimpleITK as sitk
import numpy as np
import matplotlib.pyplot as plt
import nilearn
from rabies.visualization import otsu_scaling, plot_3d
from rabies.visualization import otsu_scaling, plot_3d, cold_hot
from rabies.analysis_pkg.analysis_math import elementwise_spearman, elementwise_corrcoef, dice_coefficient
from rabies.utils import recover_3D
from rabies.confound_correction_pkg.utils import smooth_image
Expand Down Expand Up @@ -180,7 +179,7 @@ def masked_plot(fig,axes, img, scaled, mask_img, vmax=None):
plot_3d(axes,scaled,fig,vmin=0,vmax=1,cmap='gray', alpha=1, cbar=False, num_slices=6, planes=planes)
# resample to match template
sitk_img = sitk.Resample(masked, scaled)
cbar_list = plot_3d(axes,sitk_img,fig,vmin=-vmax,vmax=vmax,cmap='cold_hot', alpha=1, cbar=True, threshold=vmax*0.001, num_slices=6, planes=planes)
cbar_list = plot_3d(axes,sitk_img,fig,vmin=-vmax,vmax=vmax,cmap=cold_hot, alpha=1, cbar=True, threshold=vmax*0.001, num_slices=6, planes=planes)
return cbar_list


Expand Down
5 changes: 2 additions & 3 deletions rabies/analysis_pkg/diagnosis_pkg/diagnosis_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from rabies.utils import copyInfo_3DImage, recover_3D
from rabies.analysis_pkg import analysis_functions
import SimpleITK as sitk
import nilearn.plotting
from .analysis_QC import masked_plot, threshold_top_percent

def compute_spatiotemporal_features(CR_data_dict, sub_maps_data_dict, common_maps_data_dict, analysis_dict,
Expand Down Expand Up @@ -465,7 +464,7 @@ def scan_diagnosis(CR_data_dict, maps_data_dict, temporal_info, spatial_info, pl
fig2, axes2 = plt.subplots(nrows=nrows, ncols=3, figsize=(12*3, 2*nrows))
plt.tight_layout()

from rabies.visualization import otsu_scaling, plot_3d
from rabies.visualization import otsu_scaling, plot_3d, cold_hot

axes = axes2[0, :]
scaled = otsu_scaling(template_file)
Expand Down Expand Up @@ -534,7 +533,7 @@ def scan_diagnosis(CR_data_dict, maps_data_dict, temporal_info, spatial_info, pl
vector = spatial_info['GS_cov'].flatten()
vector.sort()
vmax = vector[int(len(vector)*0.95)]
cbar_list = plot_3d(axes, sitk_img, fig2, vmin=-vmax, vmax=vmax, cmap='cold_hot',
cbar_list = plot_3d(axes, sitk_img, fig2, vmin=-vmax, vmax=vmax, cmap=cold_hot,
alpha=1, cbar=True, num_slices=6)
for cbar in cbar_list:
cbar.ax.get_yaxis().labelpad = 20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ def classification_plot(myinput, outDir):
df3 = pd.DataFrame.from_records([["True", 1., 1., 0., 0.],
["True", 1., 1., 0., 0.],
["True", 1., 1., 0., 0.]])
df = df.append(df3, ignore_index=True)
df = pd.concat([df, df3], ignore_index=True)
tmp = df.loc[df[0] == "False"]
if len(tmp) < 3:
df3 = pd.DataFrame.from_records([["False", 0., 0., 0., 0.],
["False", 0., 0., 0., 0.],
["False", 0., 0., 0., 0.]])
df = df.append(df3, ignore_index=True)
df = pd.concat([df, df3], ignore_index=True)

# rename columns
df = df.rename(index=str, columns={0: 'Motion',
Expand Down
94 changes: 91 additions & 3 deletions rabies/confound_correction_pkg/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,6 @@ def phase_randomized_regressors(regressors_array, frame_mask, TR):


def smooth_image(img, fwhm, mask_img):
# apply nilearn's Gaussian smoothing on a SITK image
from nilearn.image.image import _smooth_array
from rabies.utils import copyInfo_4DImage, copyInfo_3DImage

dim = img.GetDimension()
Expand Down Expand Up @@ -706,4 +704,94 @@ def sitk_affine_lps(img):
affine = np.eye(dim + 1)
affine[:dim, :dim] = direction @ spacing
affine[:dim, dim] = origin
return affine
return affine


"""
Reproduction of Nilearn's nilearn.image.smooth_img smoothing function (version 0.7.1)

Original reference:
Nilearn developers. Nilearn: Statistical learning for neuroimaging in Python.
URL: https://nilearn.github.io/
"""
def _smooth_array(arr, affine, fwhm=None, ensure_finite=True, copy=True):
"""Smooth images by applying a Gaussian filter.

Apply a Gaussian filter along the three first dimensions of `arr`.

Parameters
----------
arr : :class:`numpy.ndarray`
4D array, with image number as last dimension. 3D arrays are also
accepted.

affine : :class:`numpy.ndarray`
(4, 4) matrix, giving affine transformation for image. (3, 3) matrices
are also accepted (only these coefficients are used).
If `fwhm='fast'`, the affine is not used and can be None.

fwhm : scalar, :class:`numpy.ndarray`/:obj:`tuple`/:obj:`list`, 'fast' or None, optional
Smoothing strength, as a full-width at half maximum, in millimeters.
If a nonzero scalar is given, width is identical in all 3 directions.
A :class:`numpy.ndarray`, :obj:`tuple`, or :obj:`list` must have 3 elements,
giving the FWHM along each axis.
If any of the elements is zero or None, smoothing is not performed
along that axis.
If `fwhm='fast'`, a fast smoothing will be performed with a filter
[0.2, 1, 0.2] in each direction and a normalisation
to preserve the local average value.
If fwhm is None, no filtering is performed (useful when just removal
of non-finite values is needed).

ensure_finite : :obj:`bool`, optional
If True, replace every non-finite values (like NaNs) by zero before
filtering. Default=True.

copy : :obj:`bool`, optional
If True, input array is not modified. True by default: the filtering
is not performed in-place. Default=True.

Returns
-------
:class:`numpy.ndarray`
Filtered `arr`.

Notes
-----
This function is most efficient with arr in C order.

"""
# Here, we have to investigate use cases of fwhm. Particularly, if fwhm=0.
# See issue #1537
if isinstance(fwhm, (int, float)) and (fwhm == 0.0):
import warnings
warnings.warn("The parameter 'fwhm' for smoothing is specified "
"as {0}. Setting it to None "
"(no smoothing will be performed)"
.format(fwhm))
fwhm = None
if arr.dtype.kind == 'i':
if arr.dtype == np.int64:
arr = arr.astype(np.float64)
else:
arr = arr.astype(np.float32) # We don't need crazy precision.
if copy:
arr = arr.copy()
if ensure_finite:
# SPM tends to put NaNs in the data outside the brain
arr[np.logical_not(np.isfinite(arr))] = 0
if isinstance(fwhm, str) and (fwhm == 'fast'):
raise NotImplementedError("The 'fast' option for fwhm is not implemented in rabies confound correction. Please specify a numeric value for fwhm or set to None for no smoothing.")
arr = _fast_smooth_array(arr)
elif fwhm is not None:
from scipy.ndimage import gaussian_filter1d
fwhm = np.asarray([fwhm]).ravel()
fwhm = np.asarray([0. if elem is None else elem for elem in fwhm])
affine = affine[:3, :3] # Keep only the scale part.
fwhm_over_sigma_ratio = np.sqrt(8 * np.log(2)) # FWHM to sigma.
vox_size = np.sqrt(np.sum(affine ** 2, axis=0))
sigma = fwhm / (fwhm_over_sigma_ratio * vox_size)
for n, s in enumerate(sigma):
if s > 0.0:
gaussian_filter1d(arr, s, output=arr, axis=n)
return arr
2 changes: 0 additions & 2 deletions rabies/preprocess_pkg/preprocess_visual_QC.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ def template_info(anat_template, opts, out_dir,figure_format):
import SimpleITK as sitk
# set default threader to platform to avoid freezing with MultiProc https://github.com/SimpleITK/SimpleITK/issues/1239
sitk.ProcessObject_SetGlobalDefaultThreader('Platform')
from nilearn import plotting
import matplotlib.pyplot as plt
from rabies.visualization import plot_3d, otsu_scaling
os.makedirs(out_dir, exist_ok=True)
Expand Down Expand Up @@ -99,7 +98,6 @@ def template_masking(template, mask, out_dir, figure_format):
import SimpleITK as sitk
# set default threader to platform to avoid freezing with MultiProc https://github.com/SimpleITK/SimpleITK/issues/1239
sitk.ProcessObject_SetGlobalDefaultThreader('Platform')
from nilearn import plotting
import matplotlib.pyplot as plt
from rabies.visualization import plot_3d, otsu_scaling

Expand Down
40 changes: 40 additions & 0 deletions rabies/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,46 @@
"savefig.facecolor": "black",
"savefig.edgecolor": "black"})

"""
Standalone reproduction of Nilearn's 'cold_hot' colormap.

Original reference:
Nilearn developers. Nilearn: Statistical learning for neuroimaging in Python.
URL: https://nilearn.github.io/
"""
from matplotlib.colors import LinearSegmentedColormap
# Segment data extracted from the actual Nilearn 'cold_hot'
_cold_hot_segments = {
'red': [
(0.0, 1.0, 1.0),
(0.126984, 0.0, 0.0),
(0.5, 0.0, 0.0),
(0.5, 0.0416, 0.0416),
(0.682540, 1.0, 1.0),
(1.0, 1.0, 1.0),
],
'green': [
(0.0, 1.0, 1.0),
(0.126984, 1.0, 1.0),
(0.317461, 0.0, 0.0),
(0.5, 0.0, 0.0),
(0.5, 0.0, 0.0),
(0.682540, 0.0, 0.0),
(0.873016, 1.0, 1.0),
(1.0, 1.0, 1.0),
],
'blue': [
(0.0, 1.0, 1.0),
(0.317461, 1.0, 1.0),
(0.5, 0.0416, 0.0416),
(0.5, 0.0, 0.0),
(0.873016, 0.0, 0.0),
(1.0, 1.0, 1.0),
]
}
# Create the LinearSegmentedColormap
cold_hot = LinearSegmentedColormap('cold_hot', _cold_hot_segments, N=256)


def otsu_scaling(input_image):
from skimage.filters import threshold_multiotsu
Expand Down
1 change: 0 additions & 1 deletion rabies_environment.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ dependencies:
- future
- matplotlib
- nibabel
- nilearn
- nipype
- numpy
- pandas
Expand Down
1 change: 0 additions & 1 deletion rabies_environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ dependencies:
- future
- matplotlib=3.3.4
- nibabel=3.2.1
- nilearn=0.7.1
- nipype=1.10.0
- numpy=1.26.4
- pandas=1.2.4
Expand Down
28 changes: 13 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,24 @@
URL = 'https://github.com/CoBrALab/RABIES'
EMAIL = '[email protected]'
AUTHOR = 'CoBrALab'
REQUIRES_PYTHON = '>=3.9.0'
REQUIRES_PYTHON = '>=3.9.0, <3.13' # the package was tested up to 3.12

# What packages are required for this module to be executed?
REQUIRED = [
# 'requests', 'maya', 'records',
'pip>=23.0',
'matplotlib>=3.3.4',
'nibabel>=3.2.1',
'nilearn>=0.7.1',
'nipype>=1.6.1',
'numpy>=1.20.1',
'pandas>=1.2.4',
'pathos>=0.2.7',
'pybids==0.16.3',
'scikit-learn>=0.24.1',
'scikit-image>=0.18.2',
'scipy>=1.8.1',
'seaborn>=0.11.1',
'matplotlib>=3.3.4', # tested up to 3.10.8
'nibabel>=3.2.1', # tested up to 5.4.0
'nipype>=1.6.1', # tested up to 1.11.0
'numpy>=1.20.1', # tested up to 2.4.3
'pandas>=1.2.4', # tested up to 3.0.1
'pathos>=0.2.7', # tested up to 0.3.5
'pybids==0.16.3', # only tested with 0.16.3, newer versions have some issues with the BIDS layout of our data
'scikit-learn>=0.24.1', # tested up to 1.8.0
'scikit-image>=0.18.2', # tested up to 0.24.0
'scipy>=1.8.1', # tested up to 1.17.1
'seaborn>=0.11.1', # tested up to 0.13.2
'simpleitk>=2.5.0',
'qbatch==2.3',
'qbatch==2.3', # tested only with 2.3
'networkx<3',
'traits<7.0',
'tqdm',
Expand Down
Loading