Package that provides tools for brain MRI Deep Learning pre-processing.
Source code for brainprep.plotting
# -*- coding: utf-8 -*-
##########################################################################
# NSAp - Copyright (C) CEA, 2021 - 2022
# Distributed under the terms of the CeCILL-B license, as published by
# the CEA-CNRS-INRIA. Refer to the LICENSE file or to
# http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
# for details.
##########################################################################
"""
Usefull plotting functions.
"""
# Imports
import os
import nibabel
import itertools
import numpy as np
import progressbar
from nilearn import plotting
import matplotlib.pyplot as plt
import seaborn as sns
from .utils import get_bids_keys
[docs]
def plot_images(nii_files, cut_coords, outdir):
""" Plot images on a subject basis.
Parameters
----------
img_files: list of n-uplet (n_subjects, n_path)
path to images.
cut_coords: list of int (n_path, 3)
the MNI coordinates of the point where the orthogonal cut is performed.
outdir: str
the destination folder.
Returns
-------
snaps: list of str
the generated snaps.
snapdir: str
the folder that contains all results.
"""
snapdir = os.path.join(outdir, "snap")
if not os.path.isdir(snapdir):
os.mkdir(snapdir)
snaps = []
with progressbar.ProgressBar(max_value=len(nii_files)) as bar:
for cnt, data in enumerate(nii_files):
fig, axs = plt.subplots(len(data))
for idx, (path, cut) in enumerate(zip(data, cut_coords)):
img = nibabel.load(path)
if not isinstance(axs, list):
axs = [axs]
plotting.plot_anat(img, figure=fig, axes=axs[idx],
cut_coords=cut, display_mode="ortho")
plt.subplots_adjust(wspace=0, hspace=0, top=0.9, bottom=0.1)
keys = get_bids_keys(path)
participant_id = keys["participant_id"]
session = keys["session"]
run = keys["run"]
snap_path = os.path.join(
snapdir, "sub-{}_ses-{}_run-{}_snaps.png".format(
participant_id, session, run))
plt.savefig(snap_path)
snaps.append(snap_path)
bar.update(cnt)
return snaps, snapdir
[docs]
def plot_hists(data, outdir, title=None):
""" Plot hisograms with optional vertical bars.
Parameters
----------
data: dict
containes the data to display in 'data' and optionnaly the coordianate
of the vertical line in 'bar_low' and 'bar_up'.
outdir: str
the destination folder.
title: str, default None
title of the histogram.
Returns
-------
snap: str
the generated snap.
"""
fig, axs = plt.subplots(len(data))
if not isinstance(axs, np.ndarray):
axs = [axs]
for cnt, (name, item) in enumerate(data.items()):
arr = item["data"].astype(np.single)
arr = arr[~np.isnan(arr)]
arr = arr[~np.isinf(arr)]
sns.histplot(arr, color="gray", alpha=0.6, ax=axs[cnt],
kde=True, stat="density", label=name)
coord_low = item.get("bar_low")
coord_up = item.get("bar_up")
if coord_low is not None:
axs[cnt].axvline(x=coord_low, color="red")
if coord_up is not None:
axs[cnt].axvline(x=coord_up, color="red")
axs[cnt].spines["right"].set_visible(False)
axs[cnt].spines["top"].set_visible(False)
axs[cnt].legend()
plt.subplots_adjust(wspace=0, hspace=0, top=0.9, bottom=0.1)
if title is not None:
plt.title(title)
snap_path = os.path.join(outdir, f"hists_{title}.png")
else:
snap_path = os.path.join(outdir, "hists.png")
plt.savefig(snap_path)
return snap_path
[docs]
def plot_fsreconall(fs_dirs, outdir, include_cerebellum=False):
""" Plot images on a subject basis.
Parameters
----------
fs_dirs: list of str
list of FreeSurfer recon-all generated directories.
outdir: str
the destination folder.
include_cerebellum: bool, default False
include the cerebellum as a structure of interest.
Returns
-------
snaps: list of str
the generated snaps.
snapdir: str
the folder that contains all results.
"""
snapdir = os.path.join(outdir, "snap")
if not os.path.isdir(snapdir):
os.mkdir(snapdir)
snaps = []
with progressbar.ProgressBar(max_value=len(fs_dirs)) as bar:
for cnt1, path in enumerate(fs_dirs):
fig, axs = plt.subplots(2)
ribbon_file = os.path.join(path, "mri", "ribbon.mgz")
wmparc_file = os.path.join(path, "mri", "wmparc.mgz")
anat_file = os.path.join(path, "mri", "norm.mgz")
ribbon_im = nibabel.load(ribbon_file)
wmparc_im = nibabel.load(wmparc_file)
wm_mask, gm_mask, csf_mask, brain_mask = get_fsreconall_masks(
ribbon_im.get_fdata(), wmparc_im.get_fdata(),
include_cerebellum=include_cerebellum)
anat_im = nibabel.load(anat_file)
anat_arr = anat_im.get_fdata()
gm_im = nibabel.Nifti1Image(
gm_mask.astype(int), affine=ribbon_im.affine)
plotting.plot_roi(roi_img=gm_im, bg_img=anat_im, alpha=0.3,
figure=fig, axes=axs[0])
palette = itertools.cycle(sns.color_palette("Set1"))
bins = np.histogram_bin_edges(anat_arr[brain_mask], bins="auto")
for name, mask in [("WM", wm_mask), ("GM", gm_mask),
("CSF", csf_mask)]:
sns.histplot(anat_arr[mask], bins=bins, color=next(palette),
alpha=0.6, ax=axs[1], kde=True,
stat="density", label=name)
axs[1].spines["right"].set_visible(False)
axs[1].spines["top"].set_visible(False)
axs[1].legend()
plt.subplots_adjust(wspace=0, hspace=0, top=0.9, bottom=0.1)
keys = get_bids_keys(path)
participant_id = keys["participant_id"]
session = keys["session"]
run = keys["run"]
snap_path = os.path.join(
snapdir, "sub-{}_ses-{}_run-{}_snaps.png".format(
participant_id, session, run))
plt.savefig(snap_path)
snaps.append(snap_path)
bar.update(cnt1)
return snaps, snapdir
[docs]
def get_fsreconall_masks(ribbon_arr, wmparc_arr, include_cerebellum=False):
""" Return the WM, GM, CSF, and brain binary masks.
"""
# - Left-Cerebral-White-Matter, Right-Cerebral-White-Matter
ribbon_wm_structures = [2, 41]
# - Left-Cerebral-Cortex, Right-Cerebral-Cortex
ribbon_gm_structures = [3, 42]
# - Fornix, CC-Posterior, CC-Mid-Posterior, CC-Central, CC-Mid-Anterior,
# CC-Anterior
wmparc_cc_structures = [250, 251, 252, 253, 254, 255]
# - Left-Lateral-Ventricle, Left-Inf-Lat-Vent, 3rd-Ventricle,
# 4th-Ventricle, CSF Left-Choroid-Plexus, Right-Lateral-Ventricle,
# Right-Inf-Lat-Vent, Right-Choroid-Plexus
wmparc_csf_structures = [4, 5, 14, 15, 24, 31, 43, 44, 63]
if include_cerebellum:
# - Cerebellar-White-Matter-Left, Brain-Stem,
# Cerebellar-White-Matter-Right
wmparc_wm_structures = [7, 16, 46]
# - Left-Cerebellar-Cortex, Right-Cerebellar-Cortex, Thalamus-Left,
# Caudate-Left, Putamen-Left, Pallidum-Left, Hippocampus-Left,
# Amygdala-Left, Accumbens-Left, Diencephalon-Ventral-Left,
# Thalamus-Right, Caudate-Right, Putamen-Right, Pallidum-Right,
# Hippocampus-Right, Amygdala-Right, Accumbens-Right,
# Diencephalon-Ventral-Right
wmparc_gm_structures = [8, 47, 10, 11, 12, 13, 17, 18, 26, 28, 49, 50,
51, 52, 53, 54, 58, 60]
else:
# Omit cerebellum and brain stem
wmparc_wm_structures = []
wmparc_gm_structures = [10, 11, 12, 13, 17, 18, 26, 28, 49, 50, 51,
52, 53, 54, 58, 60]
wm_mask = np.logical_and(
np.logical_and(
np.logical_or(
np.logical_or(
np.in1d(ribbon_arr, ribbon_wm_structures),
np.in1d(wmparc_arr, wmparc_wm_structures)),
np.in1d(wmparc_arr, wmparc_cc_structures)),
np.logical_not(np.in1d(wmparc_arr, wmparc_csf_structures))),
np.logical_not(np.in1d(wmparc_arr, wmparc_gm_structures)))
csf_mask = np.in1d(wmparc_arr, wmparc_csf_structures)
gm_mask = np.logical_or(
np.in1d(ribbon_arr, ribbon_gm_structures),
np.in1d(wmparc_arr, wmparc_gm_structures))
wm_mask = np.reshape(wm_mask, ribbon_arr.shape)
csf_mask = np.reshape(csf_mask, ribbon_arr.shape)
gm_mask = np.reshape(gm_mask, ribbon_arr.shape)
brain_mask = np.logical_or(
np.logical_or(wm_mask, gm_mask),
csf_mask)
return wm_mask, gm_mask, csf_mask, brain_mask
Follow us