import nilearn as nl # nilearn for loading nifti
import os
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np
import nibabel as nib # nibable: loading nifti
from nilearn import plotting # nilearn plotting
from matplotlib.colors import ListedColormap # custom colormaps
import graphviz # graph
from PIL import Image # image resizing
import nilearn
In [1]:
In [2]:
='/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Quarto_Chisep_CSVO2_Manuscript/images/' figpath
In [3]:
def apply_slice_cut_to_nifti(nii_gz_path, slice_cut):
"""
Load a NIfTI image, apply a slice cut to extract a subregion, and return a new NIfTI image.
Parameters:
- nii_gz_path (str): Path to the input NIfTI (.nii.gz) file.
- slice_cut (list): Slice cut specification in the form [slice_x, slice_y, slice_z].
Returns:
- nibabel.Nifti1Image: New NIfTI image object containing the extracted subregion.
"""
# Load the NIfTI image
= nib.load(nii_gz_path)
nii_img = nii_img.get_fdata()
nii_data
# Extract the subregion using the slice cut
= slice_cut
slice_x, slice_y, slice_z = nii_data[slice_x, slice_y, slice_z]
subregion_data
# Create a new NIfTI image with the extracted subregion and original affine matrix
= nib.Nifti1Image(subregion_data, nii_img.affine)
subregion_img
return subregion_img
In [4]:
='/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Data/' basepath
In [5]:
= [slice(60, 190), slice(50, 200), slice(None)] # Define the slice cut [x, y, z] slice_cut
In [6]:
= 'QSM_SSS/qsm/sub-AMWCER18/mag_echo1.nii.gz'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
= apply_slice_cut_to_nifti(nii_gz_path, slice_cut)
mag
#plotting.plot_anat(anat_img=mag) #testing
In [7]:
= 'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/S001_QSM_star.nii.gz'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
= apply_slice_cut_to_nifti(nii_gz_path, slice_cut) qsm
In [8]:
= 'Chi_sep/sub-AMWCER18/x_pos_SA_finalmask.nii'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
= apply_slice_cut_to_nifti(nii_gz_path, slice_cut) parachi
In [24]:
= (64,42,51)
cut_coords_qsm
# Set the number of rows and columns for the subplot grid
= 3
num_rows = 1
num_cols
=(10, 12)
figsize= plt.figure(figsize=figsize)
fig = fig.add_gridspec(nrows=num_rows, ncols=num_cols, height_ratios=[1, 1, 1])
gs # Add subplots based on gridspec
= fig.add_subplot(gs[0,0]) # First subplot (top row)
ax1 = fig.add_subplot(gs[1,0]) # Second subplot (bottom row)
ax2 = fig.add_subplot(gs[2,0]) # Third subplot (bottom row, first column)
ax3
= np.percentile(mag.get_fdata(), (2, 99.9))
vmin, vmax =mag,
plotting.plot_anat(anat_img= False,
black_bg =False,
draw_cross=vmin, vmax=vmax,
vmin=True, axes=ax1,
annotate= False,
colorbar
)
# Second plot (with colorbar for QSM)
plotting.plot_anat(=qsm,
anat_img=False,
black_bg=False,
draw_cross=-0.2, vmax=0.2,
vmin=True, axes=ax2,
annotate=True,
colorbar=cut_coords_qsm,
cut_coords
)
=parachi,
plotting.plot_anat(anat_img= False,
black_bg =False,
draw_cross=0, vmax=0.2,
vmin=True, axes=ax3,
annotate= True,
colorbar=cut_coords_qsm
cut_coords
)=16
fontsize=-0.05
xoffset=1.05
yoffset# Add label "A" to the first subplot
'A', transform=ax1.transAxes,
ax1.text(xoffset, yoffset, =fontsize, fontweight='bold', va='top', ha='right')
fontsize
'B', transform=ax2.transAxes,
ax2.text(xoffset, yoffset, =fontsize, fontweight='bold', va='top', ha='right')
fontsize
'C', transform=ax3.transAxes,
ax3.text(xoffset, yoffset, =fontsize, fontweight='bold', va='top', ha='right')
fontsize
.9, 0.37, r'$\chi$ (ppm)', ha='right', fontsize=11)
plt.figtext(.9, 0.098, r'$\chi$ (ppm)', ha='right', fontsize=11)
plt.figtext(
+ "SampleImages.png", dpi=300, bbox_inches="tight")
plt.savefig(figpath
plt.show()
In [10]:
def plot_and_save_nifti_slice(nii_gz_path, slice_cut, single_slice_cut, figsize, out_path, cmap):
"""
Load a NIfTI image, apply slice cuts, extract a single slice, plot the slice, and save as a PNG file.
Parameters:
- nii_gz_path (str): Path to the input NIfTI (.nii.gz) file.
- slice_cut (list): Slice cut specification in the form [slice_x, slice_y, slice_z].
- single_slice_cut (tuple): Single slice specification for extraction (e.g., [54, :, :]).
- figsize (tuple): Figure size in inches (width, height).
- mask_path (str): Path to save the PNG file.
- cmap (str or matplotlib.colors.Colormap): Colormap for the plot.
Returns:
- str: Path to the saved PNG file.
"""
# Load the NIfTI image
= nib.load(nii_gz_path)
nii_img = nii_img.get_fdata()
nii_data
# Apply slice cuts to extract a subregion
if len(slice_cut) == 3: # For 3D data [slice_x, slice_y, slice_z]
= nii_data[slice_cut[0], slice_cut[1], slice_cut[2]]
subregion_data elif len(slice_cut) == 4: # For 4D data [slice_x, slice_y, slice_z, slice_t]
= nii_data[slice_cut[0], slice_cut[1], slice_cut[2], slice_cut[3]]
subregion_data
# Extract a single slice
= subregion_data[single_slice_cut]
single_slice_data
# Create a new figure with the specified figsize
=figsize)
plt.figure(figsize
# Display the single slice with the specified colormap
=cmap, origin='lower')
plt.imshow(single_slice_data.T, cmap
# Remove x-axis and y-axis ticks
plt.xticks([])
plt.yticks([])
# Save the plot as a PNG file
=300, bbox_inches="tight", pad_inches=0)
plt.savefig(out_path, dpi
# Show the plot (optional)
plt.show()
# Return the path to the saved PNG file
return out_path
In [11]:
# nii_gz_relpath = 'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/mag_echo5.nii.gz'
# nii_gz_path = basepath + nii_gz_relpath
# magechofive_path="magecho5.png"
# out_path=figpath + initialmask_path
# plot_and_save_nifti_slice(nii_gz_path, slice_cut, single_slice_cut, figsize, out_path, cmap)
In [12]:
basepath
'/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Data/'
In [13]:
= 'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/mag_echo5.nii.gz'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
= (62, slice(None), slice(None))
single_slice_cut =(8, 8)
figsize= 'gray'
cmap
="magecho5.png"
magechofive_path=figpath + magechofive_path
out_path
plot_and_save_nifti_slice(nii_gz_path, slice_cut, single_slice_cut, figsize, out_path, cmap)
'/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Quarto_Chisep_CSVO2_Manuscript/images/magecho5.png'
In [14]:
= 'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/mag_echo5_sqr_brain_mask.nii.gz'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
="InitialMask.png"
initialmask_path=figpath + initialmask_path
out_path
plot_and_save_nifti_slice(nii_gz_path, slice_cut, single_slice_cut, figsize, out_path, cmap)
'/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Quarto_Chisep_CSVO2_Manuscript/images/InitialMask.png'
In [15]:
= 'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/dil7_echo5mask.nii.gz'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
="DilatedMask.png"
dilatedmask_path=figpath + dilatedmask_path
out_path
plot_and_save_nifti_slice(nii_gz_path, slice_cut, single_slice_cut, figsize, out_path, cmap)
'/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Quarto_Chisep_CSVO2_Manuscript/images/DilatedMask.png'
In [16]:
= [slice(60, 190), slice(50, 200), slice(None), 1]
fourD_slice_cut = 'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/chi_dil7_echo5.nii.gz'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
="ChiDilated.png"
chidil_path=figpath + chidil_path
out_path
plot_and_save_nifti_slice(nii_gz_path, fourD_slice_cut, single_slice_cut, figsize, out_path, cmap)
'/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Quarto_Chisep_CSVO2_Manuscript/images/ChiDilated.png'
In [17]:
= ['black', 'red']
colors = ListedColormap(colors)
custom_cmap
= 'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/sss_dil7_echo5_mask.nii.gz'
nii_gz_relpath = basepath + nii_gz_relpath
nii_gz_path
="SSSMask.png"
sssmask_path=figpath + sssmask_path
out_path
plot_and_save_nifti_slice(nii_gz_path, slice_cut, single_slice_cut, figsize, out_path, custom_cmap)
'/home/weberam2/Dropbox/AssistantProf_BCCHRI/Projects/Gavin_CSVO2/Quarto_Chisep_CSVO2_Manuscript/images/SSSMask.png'
In [18]:
=basepath+'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/sss_dil7_echo5_mask.nii.gz'
nii_gz_path
# Load the NIfTI image
= nib.load(nii_gz_path)
nii_img = nii_img.get_fdata()
nii_data
# Extract a single slice
= nii_data[slice_cut[0], slice_cut[1], slice_cut[2]]
subregion_data = subregion_data[single_slice_cut]
single_slice_data
# Create a new figure with the specified figsize
=figsize)
plt.figure(figsize
= ['black', 'red']
colors = ListedColormap(colors)
custom_cmap
# Display the single slice with the specified colormap
=custom_cmap, origin='lower')
plt.imshow(single_slice_data.T, cmap
=basepath+'QSM_SSS/calc_chi/sub-AMWCER18/STISuite_Last3Echos/mag_echo5_sqr_brain_mask.nii.gz'
nii_gz_path
# Load the NIfTI image
= nib.load(nii_gz_path)
nii_img = nii_img.get_fdata()
nii_data
= nii_data[slice_cut[0], slice_cut[1], slice_cut[2]]
subregion_data
# Extract a single slice
= subregion_data[single_slice_cut]
single_slice_data2 = plt.cm.gray
mycmap =0)
mycmap.set_bad(alpha='gray', alpha=single_slice_data2.T, origin='lower', interpolation='none')
plt.imshow(single_slice_data2.T, cmap
# Remove x-axis and y-axis ticks
plt.xticks([])
plt.yticks([])
="finalmask.png"
finalmask_name=figpath+finalmask_name
finalmask_path# Save the plot as a PNG file
=300, bbox_inches="tight", pad_inches=0)
plt.savefig(finalmask_path, dpi
# Show the plot (optional)
plt.show()
In [19]:
def resize_image_to_png(original_path, resize_percent, output_png_name):
"""
Resize an image file and save it as a PNG file.
Parameters:
- sssmask_path (str): Path to the input image file.
- resize_percent (float): Percentage by which to resize the image (e.g., 30 for 30%).
- output_png_name (str): Desired name for the output PNG file (without the file extension).
Returns:
- str: Path to the saved PNG file.
"""
# Load the image using Pillow
= Image.open(original_path)
img
# Get the original width and height
= img.size
original_width, original_height
# Calculate the new dimensions based on the percentage
= int(original_width * (resize_percent / 100))
new_width = int(original_height * (resize_percent / 100))
new_height
# Resize the image
= img.resize((new_width, new_height))
resized_img
# Set the output file path for the resized image
= f"{output_png_name}.png"
output_png_path
# Save the resized image as a PNG file
resized_img.save(output_png_path)
# Return the path to the saved PNG file
return output_png_path
In [20]:
# Create a new graph
= graphviz.Graph(engine='neato')
graph
# Add nodes with text and images
#graph.node('A', 'NifTI image file', shape='box', pos='0,0!')
= resize_image_to_png(figpath + magechofive_path, 30, figpath + "initialmag5_resized")
resized_mag5_path = f'<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="1" CELLSPACING="0"><TR><TD><IMG SRC="{resized_mag5_path}" /></TD></TR><TR><TD ALIGN="CENTER">SWI magnitude, 5th echo</TD></TR></TABLE>>'
node_a_label 'A', label=node_a_label, shape='none', pos='0,0!')
graph.node(
'B', 'Create initial \nbrain mask', shape='ellipse', pos='2.5,0!')
graph.node('1', f'<<b>1</b>>', shape='none', pos='1.5,.3!')
graph.node(
= resize_image_to_png(figpath + initialmask_path, 30, figpath + "initialmask_resized")
resized_mask_path = f'<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="1" CELLSPACING="0"><TR><TD><IMG SRC="{resized_mask_path}" /></TD></TR><TR><TD ALIGN="CENTER">Brain mask</TD></TR></TABLE>>'
node_c_label 'C', label=node_c_label, shape='none', pos='5,0!')
graph.node(
'D', 'Dilate', shape='ellipse', pos='6.7,0!')
graph.node('2', f'<<b>2</b>>', shape='none', pos='6.3,.3!')
graph.node(
= resize_image_to_png(figpath + dilatedmask_path, 30, figpath + "dilmask_resized")
dilmaskresized_image_path = f'<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="1" CELLSPACING="0"><TR><TD><IMG SRC="{dilmaskresized_image_path}"/></TD></TR><TR><TD ALIGN="CENTER">Dilated brain mask</TD></TR></TABLE>>'
node_e_label 'E', label=node_e_label, shape='none', pos='8.5,0!')
graph.node(
'F', 'Calculate QSM with \ndilated mask', shape='ellipse', pos='8.5,-1.7!')
graph.node('3', f'<<b>3</b>>', shape='none', pos='7.3,-1.3!')
graph.node(
= resize_image_to_png(figpath + chidil_path, 30, figpath + 'dilchi_resized')
dilchiresized_image_path = f'<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="1" CELLSPACING="0"><TR><TD><IMG SRC="{dilchiresized_image_path}"/></TD></TR><TR><TD ALIGN="CENTER">Dilated QSM image</TD></TR></TABLE>>'
node_e_label 'G', label=node_e_label, shape='none', pos='8.5,-3.4!')
graph.node(
'H', 'SSS segmentation', shape='ellipse', pos='8.5,-5!')
graph.node('4', f'<<b>4</b>>', shape='none', pos='7.3,-4.75!')
graph.node(
= resize_image_to_png(figpath + sssmask_path, 30, figpath + 'sssmask_resized')
sssmaskresized_image_path = f'<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="1" CELLSPACING="0"><TR><TD><IMG SRC="{sssmaskresized_image_path}"/></TD></TR><TR><TD ALIGN="CENTER">SSS mask</TD></TR></TABLE>>'
node_i_label 'I', label=node_i_label, shape='none', pos='5,-5!')
graph.node(
'J', 'Combine masks', shape='ellipse', pos='5,-2.5!')
graph.node('5', f'<<b>5</b>>', shape='none', pos='4.2,-2.2!')
graph.node(
= resize_image_to_png(figpath + finalmask_name, 30, figpath + 'finalmask_resized')
finalmaskresized_image_path = f'<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="1" CELLSPACING="0"><TR><TD><IMG SRC="{finalmaskresized_image_path}"/></TD></TR><TR><TD ALIGN="CENTER">Final mask with SSS</TD></TR></TABLE>>'
node_k_label 'K', label=node_k_label, shape='none', pos='2,-2.5!')
graph.node(
# Add edges between nodes
'A', 'B', label='', constraint='false')
graph.edge('B', 'C', dir='forward', label='', constraint='false')
graph.edge('C', 'D', label='', constraint='false')
graph.edge('D', 'E', dir='forward', label='', constraint='false')
graph.edge('E', 'F', label='', constraint='false')
graph.edge('F', 'G', dir='forward', label='', constraint='false')
graph.edge('G', 'H', label='', constraint='false')
graph.edge('C', 'J', label='', constraint='false')
graph.edge('I', 'J', label='', constraint='false')
graph.edge('H', 'I', dir='forward', label='', constraint='false')
graph.edge('J', 'K', dir='forward', label='', constraint='false')
graph.edge(
# Attributes
='300', bgcolor='white', forcelabels='true')
graph.attr(dpi
# Render the graph
+ 'example_graph', format='png', engine='neato', cleanup=True)
graph.render(figpath
from IPython.display import Image as Ipmage
from IPython.display import display
from io import BytesIO
# Render the graph to a BytesIO object
= graph.pipe(format='png')
png_bytes
# Display the graph using IPython.display
display(Ipmage(png_bytes))
In [23]:
= (64,44,54)
cut_coords_masks
= 'QSM_SSS/calc_chi/star_fsl/18/star_fsl_SSSmask.nii.gz'
sss_relpath = basepath + sss_relpath
sss_path
= 'QSM_SSS/calc_chi/star_fsl/18/star_fsl_intveinmask.nii.gz'
ccv_relpath = basepath + ccv_relpath
ccv_path
= apply_slice_cut_to_nifti(sss_path, slice_cut)
sssmask = apply_slice_cut_to_nifti(ccv_path, slice_cut)
ccvmask
# Set the number of rows and columns for the subplot grid
#figsize=(10, 12)
#fig = plt.figure(figsize=figsize)
= np.percentile(mag.get_fdata(), (2, 99.9))
vmin, vmax
= plotting.plot_anat(
display =qsm,
anat_img=False,
black_bg=True,
draw_cross=-0.2, vmax=0.2,
vmin=True,
annotate=False,
colorbar=cut_coords_masks,
cut_coords=plt.figure(figsize=(10, 4))
figure#display_mode="mosaic"
)
= ['red']
redcolors = ListedColormap(redcolors)
custom_cmapred = ['blue']
bluecolors = ListedColormap(bluecolors)
custom_cmapblue
=custom_cmapred)
display.add_overlay(sssmask, cmap=custom_cmapblue)
display.add_overlay(ccvmask, cmap
+ "SampleMasks.png", dpi=300, bbox_inches="tight")
plt.savefig(figpath
plt.show()