.. _surfaces: .. title:: Visualization ********************* Surface visualization ********************* .. contents:: Table of Contents This section describes the whereabouts of the main surfaces generated by the pipeline, and how you can visualized them using ``python`` or ``R``. This example will use the subject ``HC001`` and session ``01`` from the MICs dataset, and all paths will be relative to the subject directory or ``out/micapipe/sub-HC001_ses01/`` In the following examples, we'll load and visualize single subject surfaces. Surfaces are distributed across different directories, namely: .. parsed-literal:: sub-HC001/ └── ses-01 ├── **surf** # fsnative, fsaverage5, fsLR-32k, fsLR-5k surfaces** └── **maps** # Thickness, curvature and quantitative maps** Each native surface parcellation is found inside the subject's freesurfer directory and contains the string ``mics.annot``: .. parsed-literal:: freesurfer/ └── sub-HC001_ses-01 └── label ├── lh.schaefer-400_**mics.annot** └── rh.schaefer-400_**mics.annot** Setting the environment -------------------------------------------------------- This example uses the packages the python packages ``os``, ``matplotlib``, ``numpy``, ``nibabel``, ``matplotlib`` and ``brainspace``. If you are interested in plotting surfaces with BrainSpace, check the corresponding `documentation `_!! **R** libraries are ``RColorBrewer``, ``viridis``, ``fsbrain``, ``freesurferformats`` and ``rgl``. For further information about managing and visualizing surfaces with **R**, check the `fsbrain vignettes `_, `fsbrain github repository `_, and `freesurferformats `_ The first step in both languages is to set the environment. .. tabs:: .. code-tab:: py # Set the environment import os import glob import numpy as np import nibabel as nib import seaborn as sns from brainspace.plotting import plot_hemispheres from brainspace.mesh.mesh_io import read_surface from brainspace.datasets import load_conte69 # Set the working directory to the 'out' directory out='/data_/mica3/BIDS_MICs/derivatives' # <<<<<<<<<<<< CHANGE THIS PATH os.chdir(out) # This variable will be different for each subject sub='sub-HC001' ses='ses-01' subjectID=f'{sub}_{ses}' # <<<<<<<<<<<< CHANGE THIS SUBJECT's ID subjectDir=f'micapipe_v0.2.0/{sub}/{ses}' # <<<<<<<<<<<< CHANGE THIS SUBJECT's DIRECTORY # Set paths and variables dir_FS = 'freesurfer/' + subjectID dir_surf = subjectDir + '/surf/' dir_maps = subjectDir + '/maps/' # Path to MICAPIPE micapipe=os.popen("echo $MICAPIPE").read()[:-1] .. code-tab:: r R # Set the environment 'R 4.3.1' require('RColorBrewer') # version 1.1.3 require('viridis') # version 0.6.5 require('fsbrain') # version 0.5.5 require('freesurferformats') # version 0.1.18 require('rgl') # version 1.2.8 require('gifti') # version 0.8.0 # Define working directory and subject-specific information. CHANGE THESE PATHS as appropriate. setwd('~/derivatives_RtD/') # working directory subjectID <- 'sub-HC001_ses-01' # subject ID subjectDir <- 'micapipe_v0.2.0/sub-HC001/ses-01' # subject directory path # Set paths for surface and morphometry data. dir_surf <- paste0(subjectDir, '/surf/') dir_maps <- paste0(subjectDir, '/maps/') Load the surfaces -------------------------------------------------------- .. tabs:: .. code-tab:: py # Load native pial surface pial_lh = read_surface(dir_FS+'/surf/lh.pial', itype='fs') pial_rh = read_surface(dir_FS+'/surf/rh.pial', itype='fs') # Load native white matter surface wm_lh = read_surface(dir_FS+'/surf/lh.white', itype='fs') wm_rh = read_surface(dir_FS+'/surf/rh.white', itype='fs') # Load native inflated surface inf_lh = read_surface(dir_FS+'/surf/lh.inflated', itype='fs') inf_rh = read_surface(dir_FS+'/surf/rh.inflated', itype='fs') # Load fsaverage5 fs5_lh = read_surface('freesurfer/fsaverage5/surf/lh.pial', itype='fs') fs5_rh = read_surface('freesurfer/fsaverage5/surf/rh.pial', itype='fs') # Load fsaverage5 inflated fs5_inf_lh = read_surface('freesurfer/fsaverage5/surf/lh.inflated', itype='fs') fs5_inf_rh = read_surface('freesurfer/fsaverage5/surf/rh.inflated', itype='fs') # Load fsLR 32k f32k_lh = read_surface(micapipe + '/surfaces/fsLR-32k.L.surf.gii', itype='gii') f32k_rh = read_surface(micapipe + '/surfaces/fsLR-32k.R.surf.gii', itype='gii') # Load fsLR 32k inflated f32k_inf_lh = read_surface(micapipe + '/surfaces/fsLR-32k.L.inflated.surf.gii', itype='gii') f32k_inf_rh = read_surface(micapipe + '/surfaces/fsLR-32k.R.inflated.surf.gii', itype='gii') # Load Load fsLR 5k f5k_lh = read_surface(micapipe + '/surfaces/fsLR-5k.L.surf.gii', itype='gii') f5k_rh = read_surface(micapipe + '/surfaces/fsLR-5k.R.surf.gii', itype='gii') # Load fsLR 5k inflated f5k_inf_lh = read_surface(micapipe + '/surfaces/fsLR-5k.L.inflated.surf.gii', itype='gii') f5k_inf_rh = read_surface(micapipe + '/surfaces/fsLR-5k.R.inflated.surf.gii', itype='gii') .. code-tab:: r R # Helper function to plot brain surfaces plot_surface <-function(brainMesh, legend='', view_angles=c('sd_lateral_lh', 'sd_medial_lh', 'sd_medial_rh', 'sd_lateral_rh'), img_only=FALSE) { try(img <- vis.export.from.coloredmeshes(brainMesh, colorbar_legend = legend, grid_like = FALSE, view_angles = view_angles, img_only = img_only, horizontal=TRUE)) while (rgl.cur() > 0) { rgl.close() }; file.remove(list.files(path = getwd(), pattern = 'fsbrain')) return(img) } # Define color maps for brain visualization. RdYlGn <- colorRampPalette(brewer.pal(11,'RdYlGn')) bw <- colorRampPalette(c('black','gray65', 'white')) grays <- colorRampPalette(c('gray65', 'gray65', 'gray65')) # Set color limits for data visualization lft = limit_fun(1.5, 4) # thickness color scale lfc = limit_fun(-0.2, 0.2) # curvature color scale Morphology -------------------------------------------------------- Two surface based morphological features are plotted here: cortical thickness and curvature. Both measurements are generates in three main surfaces, native, fsaverage5, fsLR-32k and fsLR-5k. Thickness: Inflated native surface ======================================================== .. tabs:: .. code-tab:: py # Load data th_lh = dir_maps + subjectID + '_hemi-L_surf-fsnative_label-thickness.func.gii' th_rh = dir_maps + subjectID + '_hemi-R_surf-fsnative_label-thickness.func.gii' th_nat = np.hstack(np.concatenate((nib.load(th_lh).darrays[0].data, nib.load(th_rh).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(inf_lh, inf_rh, array_name=th_nat, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(1.5, 4), cmap="inferno", transparent_bg=False) .. code-tab:: r R # Define paths for left and right hemisphere thickness data using FreeSurfer's native format (fsnative). th.lh <- paste0(dir_maps, subjectID, "_hemi-L_surf-fsnative_label-thickness.func.gii") th.rh <- paste0(dir_maps, subjectID, "_hemi-R_surf-fsnative_label-thickness.func.gii") # Use 'vis.data.on.subject' to visualize thickness data on the inflated cortical surface, specific to FreeSurfer format. th_nat <- vis.data.on.subject('freesurfer', subjectID, morph_data_lh=th.lh, morph_data_rh=th.rh, surface='inflated', draw_colorbar = TRUE, views=NULL, rglactions = list('trans_fun'=limit_fun(1.5, 4), 'no_vis'=T), makecmap_options = list('colFn'=inferno)) # Display the native surface with mapped thickness data. plot_surface(th_nat, 'Thickness [mm]') .. figure:: th_inf_nat.png :alt: alternate text :align: center Thickness: ``fsaverage5`` ======================================================== .. tabs:: .. code-tab:: py # Load data th_lh_fs5 = dir_maps + subjectID + '_hemi-L_surf-fsaverage5_label-thickness.func.gii' th_rh_fs5 = dir_maps + subjectID + '_hemi-R_surf-fsaverage5_label-thickness.func.gii' th_fs5 = np.hstack(np.concatenate((nib.load(th_lh_fs5).darrays[0].data, nib.load(th_rh_fs5).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(fs5_inf_lh, fs5_inf_rh, array_name=th_fs5, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(1.5, 4), cmap="inferno", transparent_bg=False) .. code-tab:: r R # This section provides a pathway for visualizing thickness without requiring FreeSurfer-formatted surfaces, utilizing the fsaverage5 template. # Load fsaverage5 surface paths for left and right hemispheres. fs5.lh <- read.fs.surface(filepath = 'micapipe/surfaces/fsaverage5/surf/lh.inflated') fs5.rh <- read.fs.surface(filepath = 'micapipe/surfaces/fsaverage5/surf/rh.inflated') # Define paths for thickness morphometric data on fsaverage5 for each hemisphere. fs5.lh.th <- paste0(dir_maps, subjectID, '_hemi-L_surf-fsaverage5_label-thickness.func.gii') fs5.rh.th <- paste0(dir_maps, subjectID, '_hemi-R_surf-fsaverage5_label-thickness.func.gii') # Create colored meshes for both hemispheres based on thickness data. cml.fs5.th <- coloredmesh.from.preloaded.data(fs5.lh, morph_data = lft(unlist(readgii(fs5.lh.th)$data)), hemi = 'lh', makecmap_options = list('colFn'=inferno)) cmr.fs5.th <- coloredmesh.from.preloaded.data(fs5.rh, morph_data = lft(unlist(readgii(fs5.rh.th)$data)), hemi = 'rh', makecmap_options = list('colFn'=inferno)) th_fs5 <- brainviews(views = 't4', coloredmeshes=list('lh'=cml.fs5.th, 'rh'=cmr.fs5.th), rglactions = list('no_vis'=T)) # Display the fsaverage5 surface with thickness data. plot_surface(th_fs5, 'Thickness [mm]') .. figure:: th_inf_fs5.png :alt: alternate text :align: center Thickness: ``fsLR-32k`` ======================================================== .. tabs:: .. code-tab:: py # Load the data th_lh_fsLR32k = dir_maps + subjectID + '_hemi-L_surf-fsLR-32k_label-thickness.func.gii' th_rh_fsLR32k = dir_maps + subjectID + '_hemi-R_surf-fsLR-32k_label-thickness.func.gii' th_fsLR32k = np.hstack(np.concatenate((nib.load(th_lh_fsLR32k).darrays[0].data, nib.load(th_rh_fsLR32k).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(f32k_inf_lh, f32k_inf_rh, array_name=th_fsLR32k, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(1.5, 4), cmap="inferno", transparent_bg=False) .. code-tab:: r R # Load fsLR-32k surface paths for left and right hemispheres. f32k.lh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-32k.L.surf.gii', format = "gii") f32k.rh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-32k.R.surf.gii', format = "gii") # Define paths for thickness morphometry data on fsLR-32k for each hemisphere. f32k.lh.th <- paste0(dir_maps, subjectID, '_hemi-L_surf-fsLR-32k_label-thickness.func.gii') f32k.rh.th <- paste0(dir_maps, subjectID, '_hemi-R_surf-fsLR-32k_label-thickness.func.gii') # Create colored meshes based on thickness data. cml.f32k.th <- coloredmesh.from.preloaded.data(f32k.lh, morph_data = lft(unlist(readgii(f32k.lh.th)$data)), hemi = 'lh', makecmap_options = list('colFn'=inferno)) cmr.f32k.th <- coloredmesh.from.preloaded.data(f32k.rh, morph_data = lft(unlist(readgii(f32k.rh.th)$data)), hemi = 'rh', makecmap_options = list('colFn'=inferno)) th_f32k <- brainviews(views = 't4', coloredmeshes=list('lh'=cml.f32k.th, 'rh'=cmr.f32k.th), rglactions = list('no_vis'=T)) # Display the fsLR-32k surface with thickness data. plot_surface(th_f32k, 'Thickness [mm]') .. figure:: th_inf_f32k.png :alt: alternate text :align: center Thickness: ``fsLR-5k`` ======================================================== .. tabs:: .. code-tab:: py # Load the data th_lh_fsLR5k = dir_maps + subjectID + '_hemi-L_surf-fsLR-5k_label-thickness.func.gii' th_rh_fsLR5k = dir_maps + subjectID + '_hemi-R_surf-fsLR-5k_label-thickness.func.gii' th_fsLR5k = np.hstack(np.concatenate((nib.load(th_lh_fsLR5k).darrays[0].data, nib.load(th_rh_fsLR5k).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(f5k_inf_lh, f5k_inf_rh, array_name=th_fsLR5k, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(1.5, 4), cmap="inferno", transparent_bg=False) .. code-tab:: r R # Load fsLR-5k surface paths for left and right hemispheres. f5k.lh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-5k.L.surf.gii', format = "gii") f5k.rh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-5k.R.surf.gii', format = "gii") # Define paths for thickness morphometry data on fsLR-5k for each hemisphere. f5k.lh.th <- paste0(dir_maps, subjectID, '_hemi-L_surf-fsLR-5k_label-thickness.func.gii') f5k.rh.th <- paste0(dir_maps, subjectID, '_hemi-R_surf-fsLR-5k_label-thickness.func.gii') # Create colored meshes based on thickness data. cml.f5k.th <- coloredmesh.from.preloaded.data(f5k.lh, morph_data = lft(unlist(readgii(f5k.lh.th)$data)), hemi = 'lh', makecmap_options = list('colFn'=inferno)) cmr.f5k.th <- coloredmesh.from.preloaded.data(f5k.rh, morph_data = lft(unlist(readgii(f5k.rh.th)$data)), hemi = 'rh', makecmap_options = list('colFn'=inferno)) th_f5k <- brainviews(views = 't4', coloredmeshes=list('lh'=cml.f5k.th, 'rh'=cmr.f5k.th), rglactions = list('no_vis'=T)) # Display the fsLR-5k surface with thickness data. plot_surface(th_f5k, 'Thickness [mm]') .. figure:: th_inf_f5k.png :alt: alternate text :align: center Curvature: Native inflated surface ======================================================== .. tabs:: .. code-tab:: py # Load the data cv_lh = dir_maps + subjectID + '_hemi-L_surf-fsnative_label-curv.func.gii' cv_rh = dir_maps + subjectID + '_hemi-R_surf-fsnative_label-curv.func.gii' cv = np.hstack(np.concatenate((nib.load(cv_lh).darrays[0].data, nib.load(cv_rh).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(inf_lh, inf_rh, array_name=cv, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(-0.2, 0.2), cmap='RdYlGn', transparent_bg=False) .. code-tab:: r R # Define paths for left and right hemisphere curvature data in FreeSurfer's native format (fsnative). cv.lh <- paste0(dir_maps, subjectID, '_hemi-L_surf-fsnative_label-curv.func.gii') cv.rh <- paste0(dir_maps, subjectID, '_hemi-R_surf-fsnative_label-curv.func.gii') # Use 'vis.data.on.subject' to visualize curvature on the subject's inflated surface. cv_nat <- vis.data.on.subject('freesurfer/', subjectID, morph_data_lh=cv.lh, morph_data_rh=cv.rh, surface='inflated', draw_colorbar = TRUE, views=NULL, rglactions = list('trans_fun'=limit_fun(-0.2, 0.2), 'no_vis'=T), makecmap_options = list('colFn'=RdYlGn)) # Display the native surface with mapped curvature data. plot_surface(cv_nat, 'Curvature [1/mm]') .. figure:: cv_inf_nat.png :alt: alternate text :align: center Curvature: ``fsaverage5`` ======================================================== .. tabs:: .. code-tab:: py # Load the data cv_lh_fs5 = dir_maps + subjectID + '_hemi-L_surf-fsaverage5_label-curv.func.gii' cv_rh_fs5 = dir_maps + subjectID + '_hemi-R_surf-fsaverage5_label-curv.func.gii' cv_fs5 = np.hstack(np.concatenate((nib.load(cv_lh_fs5).darrays[0].data, nib.load(cv_rh_fs5).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(fs5_inf_lh, fs5_inf_rh, array_name=cv_fs5, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(-0.2, 0.2), cmap='RdYlGn', transparent_bg=False) .. code-tab:: r R # Load fsaverage5 surface paths for left and right hemispheres. fs5.lh <- read.fs.surface(filepath = 'micapipe/surfaces/fsaverage5/surf/lh.inflated') fs5.rh <- read.fs.surface(filepath = 'micapipe/surfaces/fsaverage5/surf/rh.inflated') # Define paths to the morphometry data on fsaverage5. fs5.lh.cv <- paste0(dir_maps, subjectID, '_hemi-L_surf-fsaverage5_label-curv.func.gii') fs5.rh.cv <- paste0(dir_maps, subjectID, '_hemi-R_surf-fsaverage5_label-curv.func.gii') # Generate colored meshes using morphometry data. cml_fs5 <- coloredmesh.from.preloaded.data(fs5.lh, morph_data = lfc(unlist(readgii(fs5.lh.cv)$data)), hemi = 'lh', makecmap_options = list('colFn'=RdYlGn)) cmr_fs5 <- coloredmesh.from.preloaded.data(fs5.rh, morph_data = lfc(unlist(readgii(fs5.rh.cv)$data)), hemi = 'rh', makecmap_options = list('colFn'=RdYlGn)) cv_fs5 <- brainviews(views = 't4', coloredmeshes=list('lh'=cml_fs5, 'rh'=cmr_fs5), rglactions = list('no_vis'=T)) # Display the fsaverage5 surface with morphometry data. plot_surface(cv_fs5, 'Curvature [1/mm]') .. figure:: cv_inf_fs5.png :alt: alternate text :align: center Curvature: ``fsLR-32k`` ======================================================== .. tabs:: .. code-tab:: py # Load the data cv_lh_fsLR32k = dir_maps + subjectID + '_hemi-L_surf-fsLR-32k_label-curv.func.gii' cv_rh_fsLR32k = dir_maps + subjectID + '_hemi-R_surf-fsLR-32k_label-curv.func.gii' cv_fsLR32k = np.hstack(np.concatenate((nib.load(cv_lh_fsLR32k).darrays[0].data, nib.load(cv_rh_fsLR32k).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(f32k_inf_lh, f32k_inf_rh, array_name=cv_fsLR32k, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(-0.2, 0.2), cmap='RdYlGn', transparent_bg=False) .. code-tab:: r R # Load fsLF-32k surface paths for left and right hemispheres. f32k.lh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-32k.L.inflated.surf.gii') f32k.rh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-32k.R.inflated.surf.gii') # Define paths to the morphometry data on fsLF32k. f32k.lh.cv <- paste0(dir_maps, subjectID, '_hemi-L_surf-fsLR-32k_label-curv.func.gii') f32k.rh.cv <- paste0(dir_maps, subjectID, '_hemi-R_surf-fsLR-32k_label-curv.func.gii') # Generate colored meshes using morphometry data. cml_f32k <- coloredmesh.from.preloaded.data(f32k.lh, morph_data = lfc(unlist(readgii(f32k.lh.cv)$data)), hemi = 'lh', makecmap_options = list('colFn'=RdYlGn)) cmr_f32k <- coloredmesh.from.preloaded.data(f32k.rh, morph_data = lfc(unlist(readgii(f32k.rh.cv)$data)), hemi = 'rh', makecmap_options = list('colFn'=RdYlGn)) cv.f32k <- brainviews(views = 't4', coloredmeshes=list('lh'=cml_f32k, 'rh'=cmr_f32k), rglactions = list('no_vis'=T)) # Display the fsLR-32k surface with morphometry data. plot_surface(cv.f32k, 'Curvature [1/mm]') .. figure:: cv_f32k.png :alt: alternate text :align: center Curvature: ``fsLR-5k`` ======================================================== .. tabs:: .. code-tab:: py # Load the data cv_lh_fsLR5k = dir_maps + subjectID + '_hemi-L_surf-fsLR-5k_label-curv.func.gii' cv_rh_fsLR5k = dir_maps + subjectID + '_hemi-R_surf-fsLR-5k_label-curv.func.gii' cv_fsLR5k = np.hstack(np.concatenate((nib.load(cv_lh_fsLR5k).darrays[0].data, nib.load(cv_rh_fsLR5k).darrays[0].data), axis=0)) # Plot the surface plot_hemispheres(f5k_inf_lh, f5k_inf_rh, array_name=cv_fsLR5k, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(-0.2, 0.2), cmap='RdYlGn', transparent_bg=False) .. code-tab:: r R # Load fsLF-5k surface paths for left and right hemispheres. f5k.lh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-5k.L.inflated.surf.gii') f5k.rh <- read.fs.surface(filepath = 'micapipe/surfaces/fsLR-5k.R.inflated.surf.gii') # Define paths to the morphometry data on fsLR-5k. f5k.lh.cv <- paste0(dir_maps, subjectID, '_hemi-L_surf-fsLR-5k_label-curv.func.gii') f5k.rh.cv <- paste0(dir_maps, subjectID, '_hemi-R_surf-fsLR-5k_label-curv.func.gii') # Generate colored meshes using morphometry data. cml_f5k <- coloredmesh.from.preloaded.data(f5k.lh, morph_data = lfc(unlist(readgii(f5k.lh.cv)$data)), hemi = 'lh', makecmap_options = list('colFn'=RdYlGn)) cmr_f5k <- coloredmesh.from.preloaded.data(f5k.rh, morph_data = lfc(unlist(readgii(f5k.rh.cv)$data)), hemi = 'rh', makecmap_options = list('colFn'=RdYlGn)) cv.f5k <- brainviews(views = 't4', coloredmeshes=list('lh'=cml_f5k, 'rh'=cmr_f5k), rglactions = list('no_vis'=T)) # Display the fsLR-5k surface with morphometry data. plot_surface(cv.f5k, 'Curvature [1/mm]') .. figure:: cv_f5k.png :alt: alternate text :align: center ``fsLR-32k`` -------------------------------------------------------- ``fsLR-32k``: Pial surface ======================================================== .. tabs:: .. code-tab:: py # Native conte69 pial surface fsLR32k_pial_lh = read_surface(dir_surf+subjectID+'_hemi-L_space-nativepro_surf-fsLR-32k_label-pial.surf.gii', itype='gii') fsLR32k_pial_rh = read_surface(dir_surf+subjectID+'_hemi-R_space-nativepro_surf-fsLR-32k_label-pial.surf.gii', itype='gii') # Plot the surface plot_hemispheres(fsLR32k_pial_lh, fsLR32k_pial_rh, size=(900, 250), zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(1.5, 4), cmap='Greys', transparent_bg=False) .. code-tab:: r R # Load fsLR-32k pial surfaces for left and right hemispheres. f32k.pial.lh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-L_space-nativepro_surf-fsLR-32k_label-pial.surf.gii') ) f32k.pial.rh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-R_space-nativepro_surf-fsLR-32k_label-pial.surf.gii') ) # Prepare and plot the surfaces for visualization. cml = coloredmesh.from.preloaded.data(f32k.pial.lh, morph_data = rnorm(nrow(f32k.pial.lh$vertices),5,1), makecmap_options = list('colFn'=grays) ) cmr = coloredmesh.from.preloaded.data(f32k.pial.rh, morph_data = rnorm(nrow(f32k.pial.rh$vertices),5,1), makecmap_options = list('colFn'=grays) ) f32k.pial <- brainviews(views = 't4', coloredmeshes=list('lh'=cml, 'rh'=cmr), draw_colorbar = FALSE, rglactions = list('trans_fun'=limit_fun(-1, 1), 'no_vis'=T)) plot_surface(f32k.pial, 'fsLR-32k pial') .. figure:: f32k_pial.png :alt: alternate text :align: center ``fsLR-32k``: Middle surface ======================================================== .. tabs:: .. code-tab:: py # Native fsLR-32k midsurface fsLR32k_mid_lh = read_surface(dir_surf+subjectID+'_hemi-L_space-nativepro_surf-fsLR-32k_label-midthickness.surf.gii', itype='gii') fsLR32k_mid_rh = read_surface(dir_surf+subjectID+'_hemi-R_space-nativepro_surf-fsLR-32k_label-midthickness.surf.gii', itype='gii') # Plot the surface plot_hemispheres(fsLR32k_mid_lh, fsLR32k_mid_rh, size=(900, 250), zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(-1,1), cmap='Greys', transparent_bg=False) .. code-tab:: r R # Load fsLR-32k middle surfaces for left and right hemispheres. f32k.mid.lh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-L_space-nativepro_surf-fsLR-32k_label-midthickness.surf.gii') ) f32k.mid.rh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-R_space-nativepro_surf-fsLR-32k_label-midthickness.surf.gii') ) # Prepare and plot the surfaces for visualization. cml = coloredmesh.from.preloaded.data(f32k.mid.lh, morph_data = rnorm(nrow(f32k.mid.lh$vertices),5,1), makecmap_options = list('colFn'=grays) ) cmr = coloredmesh.from.preloaded.data(f32k.mid.rh, morph_data = rnorm(nrow(f32k.mid.rh$vertices),5,1), makecmap_options = list('colFn'=grays) ) f32k.mid <- brainviews(views = 't4', coloredmeshes=list('lh'=cml, 'rh'=cmr), draw_colorbar = FALSE, rglactions = list('trans_fun'=limit_fun(-1, 1), 'no_vis'=T)) plot_surface(f32k.mid, 'fsLR-32k mid') .. figure:: f32k_mid.png :alt: alternate text :align: center ``fsLR-32k``: White matter surface ======================================================== .. tabs:: .. code-tab:: py # Native fsLR-32k white matter fsLR32k_wm_lh = read_surface(dir_surf+subjectID+'_hemi-L_space-nativepro_surf-fsLR-32k_label-white.surf.gii', itype='gii') fsLR32k_wm_rh = read_surface(dir_surf+subjectID+'_hemi-R_space-nativepro_surf-fsLR-32k_label-white.surf.gii', itype='gii') # Plot the surface plot_hemispheres(fsLR32k_wm_lh, fsLR32k_wm_lh, size=(900, 250), zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(1.5, 4), cmap='Greys', transparent_bg=False) .. code-tab:: r R # Load fsLR-32k white surfaces for left and right hemispheres. f32k.wm.lh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-L_space-nativepro_surf-fsLR-32k_label-white.surf.gii') ) f32k.wm.rh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-R_space-nativepro_surf-fsLR-32k_label-white.surf.gii') ) # Prepare and plot the surfaces for visualization. cml <- coloredmesh.from.preloaded.data(f32k.wm.lh, morph_data = rnorm(nrow(f32k.wm.lh$vertices),5,1), makecmap_options = list('colFn'=grays) ) cmr <- coloredmesh.from.preloaded.data(f32k.wm.rh, morph_data = rnorm(nrow(f32k.wm.rh$vertices),5,1), makecmap_options = list('colFn'=grays) ) f32k.wm <- brainviews(views = 't4', coloredmeshes=list('lh'=cml, 'rh'=cmr), draw_colorbar = FALSE, rglactions = list('trans_fun'=limit_fun(-1, 1), 'no_vis'=T)) plot_surface(f32k.wm, 'fsLR-32k white') .. figure:: f32k_wm.png :alt: alternate text :align: center Native sphere -------------------------------------------------------- .. tabs:: .. code-tab:: py # Native sphere sph_lh = read_surface(dir_surf+subjectID+'_hemi-L_surf-fsnative_label-sphere.surf.gii', itype='gii') sph_rh = read_surface(dir_surf+subjectID+'_hemi-R_surf-fsnative_label-sphere.surf.gii', itype='gii') # Plot the surface plot_hemispheres(sph_lh, sph_rh, array_name=cv, size=(900, 250), zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(-0.2, 0.2), cmap="gray", transparent_bg=False) .. code-tab:: r R # Load native sphere surfaces for left and right hemispheres. sph.lh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-L_surf-fsnative_label-sphere.surf.gii')) sph.rh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-R_surf-fsnative_label-sphere.surf.gii')) # Prepare colored meshes with curvature data. cml <- coloredmesh.from.preloaded.data(sph.lh, morph_data = lfc(readgii(cv.lh)$data$unknown), hemi = 'lh', makecmap_options = list('colFn'=bw)) cmr <- coloredmesh.from.preloaded.data(sph.rh, morph_data = lfc(readgii(cv.rh)$data$unknown), hemi = 'rh', makecmap_options = list('colFn'=bw)) sph.nat <- brainviews(views = 't4', coloredmeshes=list('lh'=cml, 'rh'=cmr), rglactions = list('no_vis'=T)) # Display the native sphere surface with mapped curvature data. plot_surface(sph.nat, 'Native sphere curvature [1/mm]') .. figure:: nat_sph.png :alt: alternate text :align: center Superficial White Matter (SWM) in ``fsnative`` surface -------------------------------------------------------- The superficial white matter surfaces are generated across 3 different surface layer from the white mater to 1, 2 and 3mm deeps. Then each quantitative map from ``/maps`` is resample from ``fsnative`` to ``fsaverage5``, ``fsLR-32k`` and ``fsLR-5k``. In this example we will only plot the native surfaces. SWM Surfaces ======================================================== .. tabs:: .. code-tab:: py # Function to load and plot each SWM surfaces def plot_swm(mm='1'): # SWM fsnative 1mm swm_lh = read_surface(f'{dir_surf}{subjectID}_hemi-L_surf-fsnative_label-swm{mm}.0mm.surf.gii', itype='gii') swm_rh = read_surface(f'{dir_surf}{subjectID}_hemi-R_surf-fsnative_label-swm{mm}.0mm.surf.gii', itype='gii') # Plot the surface fig = plot_hemispheres(swm_lh, swm_rh, size=(900, 250), zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=(1.5, 4), cmap='Greys', transparent_bg=False) return(fig) .. code-tab:: r R # Function to visualize SWM at varying depths (1mm, 2mm, 3mm). mesh_swm <- function(mm = '1') { # Load SWM surface data for specified depth for both hemispheres. f32k.swm.lh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-L_surf-fsnative_label-swm',mm,'.0mm.surf.gii') ) f32k.swm.rh <- read.fs.surface(filepath = paste0(dir_surf, subjectID,'_hemi-R_surf-fsnative_label-swm',mm,'.0mm.surf.gii') ) # Generate colored meshes using random morphometric data for visualization. cml = coloredmesh.from.preloaded.data(f32k.swm.lh, morph_data = rnorm(nrow(f32k.swm.lh$vertices),5,1), makecmap_options = list('colFn'=grays) ) cmr = coloredmesh.from.preloaded.data(f32k.swm.rh, morph_data = rnorm(nrow(f32k.swm.rh$vertices),5,1), makecmap_options = list('colFn'=grays) ) bv <- brainviews(views = 't4', coloredmeshes=list('lh'=cml, 'rh'=cmr), draw_colorbar = FALSE, rglactions = list('trans_fun'=limit_fun(-1, 1), 'no_vis'=T)) return(bv) } SWM 1mm ======================================================== .. tabs:: .. code-tab:: py # SWM 1mm plot_swm(mm='1') .. code-tab:: r R # SWM 1mm plot_surface(mesh_swm('1'), 'Superficial white matter 1mm depth') .. figure:: swm1.png :alt: alternate text :align: center SWM 2mm ======================================================== .. tabs:: .. code-tab:: py # SWM 2mm plot_swm(mm='2') .. code-tab:: r R # SWM 2mm plot_surface(mesh_swm('2'), 'Superficial white matter 2mm depth') .. figure:: swm2.png :alt: alternate text :align: center SWM 3mm ======================================================== .. tabs:: .. code-tab:: py # SWM 3mm plot_swm(mm='3') .. code-tab:: r R # SWM 3mm plot_surface(mesh_swm('3'), 'Superficial white matter 3mm depth') .. figure:: swm3.png :alt: alternate text :align: center ``/maps``: ``fsnative``, ``fsaverage5``, ``fsLR-32k`` and ``fsLR-5k`` ----------------------------------------------------------------------- - Each file map with the extension ``func.gii`` corresponds to the data map from a NIFTI image at a certain deep. - The deep from where it was mapped is in the name after the string ``label-``. - The hemisphere is either ``L`` for left or ``R`` for right. - The surface will match the number of points of the surface that corresponds that file map. The options are: ``fsnative``, ``fsLR-32k``, ``fsLR-5k`` and ``fsaverage5``. .. admonition:: Note ❕ For example the file below corresponds to the left native surface mapped from midthicknes of the T1map nifti image: ``sub-001_hemi-L_surf-fsnative_label-midthickness_T1map.func.gii`` - The maps on the surfaces ``fsnative``, ``fsLR-32k``, ``fsLR-5k``, can be plot on their native surface or on the standard surface (regular or inflated). .. warning:: There is **NO inherent smoothing** applied to the map. If the user desires smoothing, they should customize it according to their preferences and requirements. .. tabs:: .. code-tab:: py def load_qmri(qmri='', surf='fsLR-32k'): ''' This function loads the qMRI intensity maps from midthickness surface ''' # List the files files_lh = sorted(glob.glob(f"{dir_maps}/*_hemi-L_surf-{surf}_label-midthickness_{qmri}.func.gii")) files_rh = sorted(glob.glob(f"{dir_maps}/*_hemi-R_surf-{surf}_label-midthickness_{qmri}.func.gii")) # Load map data surf_map=np.concatenate((nib.load(files_lh[0]).darrays[0].data, nib.load(files_rh[0]).darrays[0].data), axis=0) return(surf_map) def plot_qmri(qmri='', surf='fsLR-32k', label='pial', cmap='rocket', rq=(0.15, 0.95)): ''' This function plots the qMRI intensity maps on the pial surface ''' # Load the data map_surf = load_qmri(qmri, surf) print('Number of vertices: ' + str(map_surf.shape[0])) # Load the surfaces surf_lh=read_surface(f'{dir_surf}/{subjectID}_hemi-L_space-nativepro_surf-{surf}_label-{label}.surf.gii', itype='gii') surf_rh=read_surface(f'{dir_surf}/{subjectID}_hemi-R_space-nativepro_surf-{surf}_label-{label}.surf.gii', itype='gii') # Color range based in the quantiles crange=(np.quantile(map_surf, rq[0]), np.quantile(map_surf, rq[1])) # Plot the group T1map intensitites fig = plot_hemispheres(surf_lh, surf_rh, array_name=map_surf, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), cmap=cmap, color_range=crange, transparent_bg=False, screenshot = False) return(fig) .. code-tab:: r R # Function to aggregate qMRI surface data paths for a given type and surface. surf_qmri <- function(qmri = '', surf = 'fsLR-32k') { # Compile file paths for qMRI data across hemispheres. files_lh <- paste0(dir_maps, subjectID, '_hemi-L_surf-', surf, '_label-midthickness_', qmri, '.func.gii') files_rh <- paste0(dir_maps, subjectID, '_hemi-R_surf-', surf, '_label-midthickness_', qmri, '.func.gii') # Combine left and right hemisphere data into a single array. surf_map <- c(readgii(files_lh)$data, readgii(files_rh)$data) return(surf_map) } # Function to visualize qMRI data on a specified brain surface. mesh_qmri <- function(qmri = '', surf = 'fsLR-32k', label = 'pial', rq = c(0.15, 0.95), cmap = inferno) { # Retrieve qMRI data mapped to specified surface. map_surf <- surf_qmri(qmri, surf) # Load associated surface data for visualization. surf.lh <- read.fs.surface(filepath = paste0(dir_surf, '/', subjectID, '_hemi-L_space-nativepro_surf-', surf, '_label-', label, '.surf.gii' ) ) surf.rh <- read.fs.surface(filepath = paste0(dir_surf, '/', subjectID, '_hemi-R_space-nativepro_surf-', surf, '_label-', label, '.surf.gii' ) ) # Determine data range for color mapping based on specified quantiles. crange <- quantile(c(map_surf[[1]], map_surf[[2]]), probs = rq) # Set the color limits lf= limit_fun(crange[1], crange[2]) # Apply color mapping based on the data range. cml = coloredmesh.from.preloaded.data(surf.lh, morph_data = lf(map_surf[[1]]), makecmap_options = list('colFn'=cmap) ) cmr = coloredmesh.from.preloaded.data(surf.rh, morph_data = lf(map_surf[[2]]), makecmap_options = list('colFn'=cmap) ) # Generate and return the visual representation. return(brainviews(views = 't4', coloredmeshes=list('lh'=cml, 'rh'=cmr), draw_colorbar = FALSE, rglactions = list('trans_fun'=limit_fun(-1, 1), 'no_vis'=T))) } T1map on ``fsnative`` ======================================================== .. tabs:: .. code-tab:: py # Plot of T1map on fsnative plot_qmri('T1map', 'fsnative') .. code-tab:: r R # T1 map on fsnative surface plot_surface(mesh_qmri(qmri = 'T1map', surf = 'fsnative')) # Plot of T1map on fsnative plot_qmri('T1map', 'fsnative') .. figure:: qMRI_fsnat.png :alt: alternate text :align: center T1map on ``fsaverage5`` native ======================================================== .. tabs:: .. code-tab:: py # Plot of T1map on fsaverage5 plot_qmri('T1map', 'fsaverage5') .. code-tab:: r R # T1 map on fsaverage5 surface plot_surface(mesh_qmri(qmri = 'T1map', surf = 'fsaverage5')) .. figure:: qMRI_fs5.png :alt: alternate text :align: center T1map on ``fsLR-32k`` native ======================================================== .. tabs:: .. code-tab:: py # Plot of T1map on fsLR-32k plot_qmri('T1map', 'fsLR-32k') .. code-tab:: r R # T1 map on fsLR-32k surface plot_surface(mesh_qmri(qmri = 'T1map', surf = 'fsLR-32k')) .. figure:: qMRI_32k.png :alt: alternate text :align: center T1map on ``fsLR-5k`` native ======================================================== .. tabs:: .. code-tab:: py # Plot of T1map on fsLR-5k plot_qmri('T1map', 'fsLR-5k') .. code-tab:: r R # T1 map on fsLR-5k surface plot_surface(mesh_qmri(qmri = 'T1map', surf = 'fsLR-5k')) .. figure:: qMRI_5k.png :alt: alternate text :align: center ``/maps``: ``fsaverage5``, ``fsLR-32k`` and ``fsLR-5k`` on standard ------------------------------------------------------------------- T1map on ``fsaverage5`` standard ======================================================== .. tabs:: .. code-tab:: py # Load the T1map data on fsaverage5 map_data = load_qmri('T1map', 'fsaverage5') # Color range based in the quantiles crange=(np.quantile(map_data, 0.15), np.quantile(map_data, 0.95)) # Plot data on standard surface plot_hemispheres(fs5_lh, fs5_rh, array_name=map_data, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=crange, cmap="rocket", transparent_bg=False) .. figure:: qMRI_fs5_std.png :alt: alternate text :align: center T1map on ``fsLR-32k`` stardard ======================================================== .. tabs:: .. code-tab:: py # Load the T1map data on fsLR-32k map_data = load_qmri('T1map', 'fsLR-32k') # Plot data on standard surface plot_hemispheres(f32k_lh, f32k_rh, array_name=map_data, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=crange, cmap="rocket", transparent_bg=False) .. figure:: qMRI_32k_std.png :alt: alternate text :align: center T1map on ``fsLR-5k`` stardard ======================================================== .. tabs:: .. code-tab:: py # Load the T1map data on fsLR-5k map_data = load_qmri('T1map', 'fsLR-5k') # Plot data on standard surface plot_hemispheres(f5k_lh, f5k_rh, array_name=map_data, size=(900, 250), color_bar='bottom', zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), color_range=crange, cmap="rocket", transparent_bg=False) .. figure:: qMRI_5k_std.png :alt: alternate text :align: center Atlas labels on surface -------------------------------------------------------- All the native surface labels generated by *micapipe* are stored inside the subject's freesurfer directory. Schaefer-400 labels ======================================================== .. tabs:: .. code-tab:: py # Load annotation file annot = 'schaefer-400' annot_lh= dir_FS + '/label/lh.' + annot + '_mics.annot' annot_rh= dir_FS + '/label/rh.' + annot + '_mics.annot' label = np.concatenate((nib.freesurfer.read_annot(annot_lh)[0], nib.freesurfer.read_annot(annot_rh)[0]), axis=0) # plot labels on surface plot_hemispheres(pial_lh, pial_rh, array_name=label, size=(900, 250), zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), cmap='nipy_spectral', transparent_bg=False) .. code-tab:: r R # Generate and visualize Schaefer-400 labels on the pial surface. schaefer.400 <- vis.subject.annot('freesurfer/', subjectID, 'schaefer-400_mics', 'both', surface='pial', views=NULL, rglactions = list('no_vis'=T)) plot_surface(schaefer.400, 'Schaefer-400') .. figure:: atlas_schaefer-400.png :alt: alternate text :align: center Extra: Economo labels ======================================================== .. tabs:: .. code-tab:: py # Load annotation file annot = 'economo' annot_lh= dir_FS + '/label/lh.' + annot + '_mics.annot' annot_rh= dir_FS + '/label/rh.' + annot + '_mics.annot' label = np.concatenate((nib.freesurfer.read_annot(annot_lh)[0], nib.freesurfer.read_annot(annot_rh)[0]), axis=0) # plot labels on surface plot_hemispheres(pial_lh, pial_rh, array_name=label, size=(900, 250), zoom=1.25, embed_nb=True, interactive=False, share='both', nan_color=(0, 0, 0, 1), cmap='nipy_spectral', transparent_bg=False) .. code-tab:: r R # Generate and visualize Economo cortical labels on the pial surface. economo <- vis.subject.annot('freesurfer/', subjectID, 'economo_mics', 'both', surface='pial', views=NULL, rglactions = list('no_vis'=T)) plot_surface(economo, 'economo', img_only=TRUE) .. figure:: atlas-economo.png :alt: alternate text :align: center Download code examples: Surfaces -------------------------------------------------------- :download:`Python Jupyter notebook: 'tutorial_surface_visualization.ipynb' ` :download:`Python source code: 'tutorial_surface_visualization.py' ` :download:`R source code: 'tutorial_surface_visualization.R' `