When preparing to update my surface (gifti) tutorial knitr, I realized that some of the confusion I was trying to address wasn't due to the code so much as the general differences between volume and surface datasets. This post tries to fill in some of those gaps for people using my R scripts. Much of the information in this post is general, but there are many topics I am not going to cover at all - what I describe here is not the only way to work with fMRI brain data; there are many other file formats and software packages.
first, volumes.
library(RNifti); # package for NIfTI image reading https://github.com/jonclayden/RNifti
fname <- paste0(in.path, "S1200_AverageT1w_81x96x81.nii.gz"); # https://osf.io/6hdxv/
if (file.exists(fname)) { under.img <- readNifti(fname); } else { stop(paste("missing:", fname)); }
str(under.img)
# 'niftiImage' num [1:81, 1:96, 1:81] 0 0 0 0 0 0 0 0 0 0 ...
# - attr(*, "pixdim")= num [1:3] 2.4 2.4 2.4
# - attr(*, "pixunits")= chr [1:2] "mm" "Unknown"
# - attr(*, ".nifti_image_ptr")=<externalptr>
# - attr(*, ".nifti_image_ver")= int 2
under.img[25,56,37]
# [1] 605.887
why surfaces?
introduction to gifti files
library(gifti); # for readGIfTI https://github.com/muschellij2/gifti
# surface "underlay anatomy"
fname <- paste0(in.path, "fsaverage5_lh.inflated_avg.surf.gii"); # https://osf.io/nxpa7/
if (file.exists(fname)) { surf.L <- readGIfTI(fname); } else { stop("can't find fsaverage5_lh.inflated_avg.surf.gii"); }
fname <- paste0(in.path, "fsaverage5_rh.inflated_avg.surf.gii"); # https://osf.io/24y9q/
if (file.exists(fname)) { surf.R <- readGIfTI(fname); } else { stop("can't find fsaverage5_rh.inflated_avg.surf.gii"); }
# Schaefer parcellation "overlay" surfaces for each hemisphere
fname <- paste0(in.path, "Schaefer2018_400Parcels_7Networks_order_10K_L.label.gii"); # https://osf.io/7wk8v/
if (file.exists(fname)) { parcels.L <- readGIfTI(fname); } else { stop(paste("missing:", fname)); }
fname <- paste0(in.path, "Schaefer2018_400Parcels_7Networks_order_10K_R.label.gii"); # https://osf.io/7tms8/
if (file.exists(fname)) { parcels.R <- readGIfTI(fname); } else { stop(paste("missing:", fname)); }
str(surf.L$data);
# List of 2
# $ pointset: num [1:10242, 1:3] -0.685 22.359 41.099 9.658 -36.773 ...
# $ triangle: int [1:20480, 1:3] 0 0 0 0 0 3 3 3 4 4 ...
str(surf.R$data)
# List of 2
# $ pointset: num [1:10242, 1:3] -5.74 8.43 43.5 12.6 -40.33 ...
# $ triangle: int [1:20480, 1:3] 0 0 0 0 0 3 3 3 4 4 ..
str(parcels.L$data)
# List of 1
# $ labels: int [1:10242, 1] 57 81 49 180 40 132 14 22 0 143 ...
str(parcels.R$data)
# List of 1
# $ labels: int [1:10242, 1] 61 81 46 110 111 200 21 95 104 119 ...
using and plotting giftis
vals.L <- rep(0, 10242); # start with all vertices 0
map.L <- gifti.map(surf.L.infl$data$pointset, surf.L.infl$data$triangle, vals.L); # map vals.L onto left surface
vals.R <- rep(0, 10242); # start with all vertices 0
vals.R[1800] <- 1; # change vertex 1800 to 1
map.R <- gifti.map(surf.R.infl$data$pointset, surf.R.infl$data$triangle, vals.R); # map vals.R onto right surface
# plot lateral and medial of both hemispheres
plot.surface(map.L, ttl="left hemisphere, blank (all vertices 0)", pos.lims=c(0.5,5.5), which.surface='fsaverage5');
plot.surface(map.R, ttl="right hemisphere, vertex 1800 in red", pos.lims=c(0.5,5.5), which.surface='fsaverage5');
vals.L <- rep(0, 10242); # start with all vertices 0
inds <- which(parcels.L$data[[1]] == 60); # find indices; where 60s are in the 10,242-element vector parcels5.L$data
vals.L[inds] <- 4; # change indices in vals.L for parcel 60 to 4
map.L <- gifti.map(surf.L.infl$data$pointset, surf.L.infl$data$triangle, vals.L); # map vals.L onto left surface
map.R <- gifti.map(surf.R.infl$data$pointset, surf.R.infl$data$triangle, parcels.R$data[[1]]); # map all parcels.R vertices onto right surface
# plot lateral and medial of both hemispheres
plot.surface(map.L, ttl="left hemisphere, parcel 60 in orange", pos.lims=c(0.5,5.5), which.surface='fsaverage5'); # plot lateral and medial, left
plot.surface(map.R, ttl="right hemisphere, parcels 1 to 200", pos.lims=c(0.5,200.5), which.surface='fsaverage5'); # plot lateral and medial, right