#' Multi-run normalization, filtering and nuisance estimation for fMRI.
#'
#' This function leverages structural image processing based on ANTs
#' cortical thickness to implement standard functional image processing
#' recommendations. The function will crop out the first k time frames,
#' do motion correction and produce a variety of nuisance regressors. It will
#' also do spatial and temporal filtering as well as interpolation between
#' time frames that exceed a given framewise displacement. Finally, we return
#' maps to the common coordinate system. Output may be trimmed in the future
#' but currently provides access at different stages: merging versus filtering
#' and normalized, fused BOLD images in both subject and template space.
#'
#' @param img input time series antsImage.
#' @param steadyT number of seconds for steady state (used to remove initial volumes)
#' @param fdthresh threshold for framewise displacement. determines what time
#' frames should be interpolated. Set typically between 0.1 and 0.5 or Inf.
#' @param repeatMotionEst number of times to repeat motion estimation. We
#' recommend the value 2, in general. The first run improves the template
#' estimate such that the 2nd run gives a more accurate correction.
#' @param freqLimits pair defining bandwidth of interest from low to high.
#' @param nCompCor number of compcor components to use in CSF plus WM mask.
#' @param polydegree eg 4 for polynomial nuisance variables.
#' @param structuralImage the structural antsImage of the brain.
#' @param structuralSeg a 3 or greater class tissue segmentation of the structural image.
#' @param structuralNodes regions of interest for network analysis, in the structural image space.
#' @param templateMap antsRegistration output mapping template space (as moving) to struturalImage (fixed).
#' @param templateImage template reference space to which we map the BOLD image.
#' @param smoothingSigmas 4-vector defining amount of smoothing in FWHM units.
#' @param extraRuns a list containing additional BOLD images (runs) to be merged with the first image.
#' @param verbose enables visualization as well as commentary.
#' @return outputs a list containing:
#' \describe{
#' \item{fusedImg: }{runs fused into one image and corrected if polydegree set}
#' \item{fusedImgFilt: }{runs fused into one image and filtered}
#' \item{seg2bold: }{strutural segmentation in BOLD space.}
#' \item{nodes2bold: }{strutural nodes in BOLD space.}
#' \item{boldToTemplate: }{BOLD fusedImg mapped to template space.}
#' \item{mapsToTemplate: }{invertible maps from BOLD to template space.}
#' \item{runID: }{Identifies which run over time series.}
#' \item{boldMat: }{Matrix of filtered BOLD data.}
#' \item{boldMask: }{BOLD mask.}
#' \item{motionCorr: }{Motion corrected data.}
#' \item{polyNuis: }{Polynomial nuisance variables.}
#' \item{timevals: }{Temporal variables.}
#' \item{nuisance: }{Nuisance variables.}
#' \item{FD: }{mean framewise displacement.}
#' \item{badtimes: }{time frames that are above FD threshold.}
#' \item{dmnAtBOLDres: }{Default mode network at BOLD resolution in MNI space.}
#' \item{seg2template: }{Segmentation in BOLD resolution MNI space.}
#' \item{networkPriors2Bold: }{WIP: standard network priors in BOLD space.}
#' \item{powersLabels: }{Powers nodes in BOLD space i.e. fusedImg.}
#' \item{powersPoints: }{Powers points in BOLD space i.e. fusedImg.}
#' \item{connMatNodes: }{User provided nodal system connectivity matrix.}
#' \item{connMatNodesPartialCorr: }{TUser provided nodal system partial correlation matrix.}
#' }
#' @author Avants BB, Duda JT
#' @examples
#' # this example is long-running ( perhaps 10 minutes on an OSX laptop 2016 )
#' \dontrun{
#' exrun <- fMRINormalization(verbose = TRUE) # will download ex data
#' myid <- "BBAvants" # some MRI data
#' pre <- paste("~/rsfTest/", sep = "")
#' fn <- list.files(pre,
#' full.names = TRUE, recursive = TRUE,
#' pattern = glob2rx(paste(myid, "*rsfMRI0.nii.gz", sep = ""))
#' )
#' img <- antsImageRead(fn)
#' sfn <- list.files(pre,
#' full.names = TRUE, recursive = TRUE,
#' pattern = glob2rx(paste(myid, "*BrainSegmentation.nii.gz", sep = ""))
#' )
#' seg <- antsImageRead(sfn)
#' t1fn <- list.files(pre,
#' full.names = TRUE, recursive = TRUE,
#' pattern = glob2rx(paste(myid, "*BrainSegmentation0N4.nii.gz", sep = ""))
#' )
#' t1 <- antsImageRead(t1fn)
#' tt <- fMRINormalization(img,
#' repeatMotionEst = 1,
#' structuralImage = t1, structuralSeg = seg, verbose = TRUE
#' )
#' # bold to template
#' antsApplyTransforms(mni, getAverageOfTimeSeries(img),
#' transformlist = tt$mapsToTemplate$toTemplate,
#' whichtoinvert = tt$mapsToTemplate$toTemplateInversion
#' )
#' # template to bold
#' antsApplyTransforms(getAverageOfTimeSeries(img), mni,
#' transformlist = tt$mapsToTemplate$toBold,
#' whichtoinvert = tt$mapsToTemplate$toBoldInversion
#' )
#' }
#'
#' @export fMRINormalization
fMRINormalization <- function(
img,
steadyT = 20.0,
fdthresh = Inf,
repeatMotionEst = 2,
freqLimits = c(0.01, 0.1),
nCompCor = 0,
polydegree = NA,
structuralImage = NULL,
structuralSeg = NULL,
structuralNodes = NULL,
templateMap = NULL,
templateImage = NULL,
smoothingSigmas = NA,
extraRuns = list(),
verbose = FALSE) {
powers_areal_mni_itk <- NULL
if (!usePkg("ggplot2")) stop("need ggplot2")
if (!usePkg("igraph")) stop("need igraph")
if (!usePkg("pracma")) stop("need pracma")
if (!usePkg("mFilter")) stop("need mFilter")
if (missing(img)) # for stand-alone testing
{
img <- antsImageRead(getANTsRData("rsbold"))
mask <- antsImageRead(getANTsRData("rsboldmask"))
structuralSeg <- antsImageRead(getANTsRData("rsboldseg"))
structuralImage <- antsImageClone(structuralSeg)
structuralImage[structuralImage > 3] <- 2
}
# start with basic mean bold image
meanbold <- getAverageOfTimeSeries(img)
mask <- getMask(meanbold)
# Find first steady state timepoint
tr <- antsGetSpacing(img)[4]
steady <- floor(steadyT / tr) + 1
# Global signal before cropping (save for visualization)
origmean <- apply(img, c(1, 2, 3), mean)
fullmean <- rowMeans(timeseries2matrix(img, mask))
allTimes <- dim(img)[4]
# Eliminate non steady-state timepoints
img <- cropIndices(img, c(1, 1, 1, steady), dim(img))
runNuis <- rep(1, dim(img)[4])
if (length(extraRuns) > 0) {
if (!is.list(extraRuns)) {
stop("extraRuns must be a list of antsImages.")
}
for (i in 1:length(extraRuns))
{
timg <- extraRuns[[i]]
allTimes <- allTimes + dim(timg)[4]
timg <- cropIndices(timg, c(1, 1, 1, steady), dim(timg))
extraRuns[[i]] <- timg
runNuis <- c(runNuis, rep(i + 1, dim(timg)[4]))
}
}
runNuis <- factor(runNuis)
timevals <- 0
for (runlev in levels(runNuis))
{
if (length(timevals) == 1) {
timevals <- as.numeric(1:sum(runNuis == runlev)) * tr
} else {
timevals <- c(timevals, as.numeric(1:sum(runNuis == runlev)) * tr)
}
}
## ----moco,message=FALSE,warnings=FALSE, fig.width=7, fig.height=3--------
mocoTxType <- "BOLDRigid"
for (i in 1:repeatMotionEst)
{
moco <- antsrMotionCalculation(img, fixed = meanbold, typeofTransform = mocoTxType)
meanbold <- apply(moco$moco_img, c(1, 2, 3), mean)
}
if (repeatMotionEst < 1) {
mocoTxType <- "QuickRigid"
moco <- antsrMotionCalculation(img, fixed = meanbold, typeofTransform = mocoTxType)
}
meanbold <- apply(moco$moco_img, c(1, 2, 3), mean)
# at this point, we might map meanbold to the structural image
# and then motion correct all runs to that. this approach would be less
# biased. however, let us hold that thought for later. FIXME
# now add any additional runs and merge moco results
if (length(extraRuns) > 0) {
for (i in 1:length(extraRuns))
{
timg <- extraRuns[[i]]
# do a more accurate registration for this stage b/c it's a different run
if (verbose) print(paste("motion correction ", i))
mocoTemp <- antsrMotionCalculation(timg, fixed = meanbold, typeofTransform = mocoTxType)
meanbold2 <- apply(timg, c(1, 2, 3), mean)
mocoTempToSelf <- antsrMotionCalculation(timg, fixed = meanbold2, typeofTransform = mocoTxType)
if (verbose) print("merge corrected image ( and tsDisplacement? )")
if (usePkg("abind")) {
ttmo <- as.array(moco$moco_img)
ttmo <- abind::abind(ttmo, as.array(mocoTemp$moco_img))
moco$moco_img <- antsCopyImageInfo(moco$moco_img, as.antsImage(ttmo))
rm(ttmo)
} else {
stop("need abind package for the extraRuns feature")
}
if (verbose) print("merge parameters, fd and dvars")
moco$moco_params <- rbind(moco$moco_params, mocoTempToSelf$moco_params)
moco$fd <- rbind(moco$fd, mocoTempToSelf$fd)
moco$dvars <- c(moco$dvars, mocoTemp$dvars)
rm(mocoTemp)
}
if (verbose) print("fusion done")
}
#############################################################
# now use polynomial regressors to match images across runs #
#############################################################
polyNuis <- NA
boldMat <- timeseries2matrix(moco$moco_img, mask)
if (!is.na(polydegree)) # polynomial regressors
{
meanmat <- boldMat * 0
rboldMat <- boldMat * 0
mycolmean <- colMeans(boldMat)
mycolmean <- mycolmean * 1000 / mean(mycolmean) # map to 1000
for (i in 1:nrow(meanmat)) meanmat[i, ] <- mycolmean
for (runlev in levels(runNuis))
{
polyNuis <- stats::poly(timevals[runNuis == runlev], degree = polydegree)
rboldMat[runNuis == runlev, ] <- residuals(lm(boldMat[runNuis == runlev, ] ~ polyNuis))
}
# residualize but also keep the scale mean
boldMat <- rboldMat + meanmat
rm(meanmat)
rm(rboldMat)
if (verbose) print("residuals done")
polyNuis <- stats::poly(timevals, degree = polydegree)
}
if (verbose) print("polyNuis done")
fusedImg <- matrix2timeseries(moco$moco_img, mask, boldMat)
## ----mocoimg,message=FALSE,warnings=FALSE, fig.width=7, fig.height=3, echo=FALSE----
if (verbose) {
invisible(plot(moco$moco_avg_img, axis = 3, slices = 1:30, ncolumns = 10))
}
if (is.null(structuralImage)) # here do a quick hack so we can process bold alone
{
structuralImage <- antsImageClone(meanbold)
if (is.null(structuralSeg)) {
structuralSeg <- antsImageClone(mask)
}
mask1 <- iMath(mask, "ME", 1) # gm
mask2 <- iMath(mask, "ME", 2) # wm
structuralSeg <- structuralSeg + mask1 + mask2
t1brain <- meanbold * mask
} else {
structuralImage <- check_ants(structuralImage)
structuralSeg <- check_ants(structuralSeg)
t1brain <- structuralImage * thresholdImage(structuralSeg, 1, Inf)
}
if (!exists("boldmap")) {
if (verbose) print("boldmap to structure (no boldmap passed in)")
# boldmap = antsRegistration( meanbold * mask, t1brain,
# typeofTransform='QuickRigid', verbose=FALSE )
if (verbose) print(meanbold)
if (verbose) print(mask)
maskmean <- meanbold * mask
if (verbose) print("mask mean done")
boldmap <- antsRegistration(maskmean, t1brain,
typeofTransform = "SyNBoldAff", verbose = FALSE
)
if (verbose) print("boldmap to structure done")
}
havetemplateMap <- TRUE
if (is.null(templateMap)) {
havetemplateMap <- FALSE
templateMap <- list(fwdtransforms = NA, invtransforms = NA)
# mni = antsImageRead( getANTsRData( "mni" ) )
# if ( verbose ) print("boldmap to template")
# templateMap = antsRegistration( t1brain, mni, typeofTransform='SyN',
# verbose = FALSE )
}
mni2boldmaps <- c(boldmap$fwdtransforms, templateMap$fwdtransforms)
mni2boldmapsInv <- c(templateMap$invtransforms, boldmap$invtransforms)
seg2bold <- antsApplyTransforms(meanbold, structuralSeg, boldmap$fwdtransforms,
interpolator = "NearestNeighbor"
)
if (verbose) {
plot(meanbold, boldmap$warpedmovout %>% iMath("Canny", 10, 1, 1))
plot(meanbold, maskImage(seg2bold, seg2bold, 2))
}
## ----mocomatrix,message=FALSE,warnings=FALSE, fig.width=7, fig.height=3----
nVox <- length(which(as.array(mask) == 1))
vox <- sample(1:nVox, 1000)
if (verbose) {
invisible(plot(as.antsImage(t(timeseries2matrix(moco$moco_img, mask)[, vox]))))
}
#########################################
# extract just the transform parameters #
#########################################
reg_params <- as.matrix(moco$moco_params)
dvars <- computeDVARS(timeseries2matrix(fusedImg, mask))
## ----badtimes,message=FALSE,warnings=FALSE, fig.width=7, fig.height=3----
goodtimes <- (1:nrow(moco$moco_img))
badtimes <- which(moco$fd$MeanDisplacement > fdthresh)
haveBadTimes <- FALSE
if (length(badtimes) > 0) {
goodtimes <- goodtimes[-badtimes]
haveBadTimes <- TRUE
} else {
badtimes <- NA
}
boldMat <- timeseries2matrix(fusedImg, mask)
nTimes <- nrow(boldMat)
if (haveBadTimes) {
if (verbose) {
print("badtimes")
print(badtimes)
}
for (v in c(1:nVox))
{
boldMat[badtimes, v] <- spline(c(1:nTimes)[goodtimes], boldMat[goodtimes, v],
method = "natural", xout = badtimes
)$y
}
# FIXME - may not want to do this ie may want to avoid using badtimes
haveBadTimes <- FALSE
goodtimes <- (1:nTimes)
}
## ----nuisance,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5----
# white matter is labeled as 3
wmMask <- seg2bold * 1 * mask
wmMask[wmMask != 3] <- 0
wmMask[wmMask == 3] <- 1
wmMask <- iMath(wmMask, "ME", 1)
wmVox <- which(subset(wmMask, mask > 0) == 1)
wmMean <- rowMeans(boldMat[, wmVox])
# CSF is labeled as 1
csfMask <- seg2bold * 1
csfMask[csfMask != 1] <- 0
csfVox <- which(subset(csfMask, mask > 0) == 1)
csfMean <- rowMeans(boldMat[, csfVox])
globalMean <- rowMeans(boldMat)
tissueNuis <- cbind(globalMean, wmMean, csfMean)
if (haveBadTimes) {
for (v in c(1:dim(tissueNuis)[2])) {
tissueInterp <- spline(c(1:nTimes)[goodtimes], tissueNuis[goodtimes, v],
method = "natural", xout = badtimes
)$y
tissueNuis[badtimes, v] <- tissueInterp
}
}
tissueDeriv <- rbind(rep(0, dim(tissueNuis)[2]), diff(tissueNuis, 1))
# Save mean cortex signal for later plotting
ctxMask <- seg2bold * 1
ctxMask[ctxMask != 2] <- 0
ctxMask[ctxMask == 2] <- 1
ctxVox <- which(subset(ctxMask, mask > 0) == 1)
ctxMean <- rowMeans(boldMat[, ctxVox])
## ----regression,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5----
mocoNuis <- reg_params
mocoNuis2 <- reg_params * reg_params
colnames(mocoNuis2) <- paste("MocoSqr", 1:ncol(mocoNuis2), sep = "")
mocoNuis <- cbind(mocoNuis, mocoNuis2)
mocoDeriv <- rbind(rep(0, dim(mocoNuis)[2]), diff(mocoNuis, 1))
colnames(mocoDeriv) <- paste("MocoDeriv", 1:ncol(mocoDeriv), sep = "")
nuisance <- cbind(mocoNuis, mocoDeriv, tissueNuis, tissueDeriv, dvars = dvars)
nuisance <- cbind(mocoNuis, mocoDeriv, globalMean = globalMean, dvars = dvars)
nuisance <- cbind(nuisance, runs = runNuis)
if (nCompCor > 0) {
# use seg2bold and moco_img to get a better compcor set "anatomical compcor"
# http://www.ncbi.nlm.nih.gov/pubmed/25987368
tempMask <- thresholdImage(seg2bold, 1, 1)
tempMask <- tempMask + thresholdImage(seg2bold, 3, 3) %>% iMath("ME", 1)
tempMat <- timeseries2matrix(fusedImg, tempMask)
compcorNuis <- compcor(tempMat, nCompCor)
colnames(compcorNuis) <- paste("compcor", 1:ncol(compcorNuis), sep = "")
nuisance <- cbind(nuisance, compcorNuis)
rm(tempMat)
rm(tempMask)
}
## ----smooth,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5------
if (any(is.na(smoothingSigmas))) {
sptl <- sqrt(sum(antsGetSpacing(img)[1:3]^2)) * 1.5
smoothingSigmas <- c(sptl, sptl, sptl, 1.0)
}
img <- smoothImage(fusedImg, smoothingSigmas, FWHM = TRUE)
boldMat <- timeseries2matrix(img, mask)
if ((length(freqLimits) == 2) & (freqLimits[1] < freqLimits[2])) {
locruns <- levels(runNuis)
boldMatTemp <- frequencyFilterfMRI(boldMat[runNuis == locruns[1], ],
tr = tr, freqLo = freqLimits[1], freqHi = freqLimits[2], opt = "trig"
)
if (length(locruns) > 1) {
for (myrun in locruns[2:length(locruns)])
{
boldMatTemp2 <- frequencyFilterfMRI(boldMat[runNuis == myrun, ],
tr = tr, freqLo = freqLimits[1], freqHi = freqLimits[2], opt = "trig"
)
boldMatTemp <- rbind(boldMatTemp, boldMatTemp2)
}
}
boldMat <- boldMatTemp
}
fusedImgFilt <- matrix2timeseries(fusedImg, mask, boldMat)
#################
connMatNodes <- NA
dmnnodes <- NA
if (!is.null(structuralNodes)) {
dmnnodes <- antsApplyTransforms(
meanbold, structuralNodes, boldmap$fwdtransforms,
interpolator = "NearestNeighbor"
)
ulabs <- sort(unique(dmnnodes[mask == 1 & dmnnodes > 0]))
dmnlist <- list()
for (i in 1:length(ulabs)) {
dmnlist[[i]] <- thresholdImage(dmnnodes, ulabs[i], ulabs[i])
}
dmnpr <- imageListToMatrix(dmnlist, mask)
dmnref <- (boldMat %*% t(dmnpr))
connMatNodes <- cor(dmnref)
}
connMatNodesPartialCorr <- NA
if (usePkg("corpcor") & !any(is.na(connMatNodes))) {
connMatNodesPartialCorr <- corpcor::cor2pcor(connMatNodes)
} # partial correlation
# get priors for different networks
networkPriors2Bold <- NA
betasI <- NA
if (!exists("networkPriors") & FALSE & havetemplateMap) {
networkPriors <- getANTsRData("fmrinetworks")
networkPriors2Bold <- networkPriors$images
for (i in 1:length(networkPriors2Bold)) {
networkPriors2Bold[[i]] <- antsApplyTransforms(
meanbold,
networkPriors2Bold[[i]], mni2boldmaps
)
}
if (FALSE) {
pr <- imageListToMatrix(networkPriors2Bold, mask)
refSignal <- scale(boldMat %*% t(pr))
networkDf <- data.frame(ROI = refSignal[goodtimes, 1], nuisance[goodtimes, ])
mdl <- lm(scale(boldMat[goodtimes, ]) ~ ., data = networkDf)
bmdl <- bigLMStats(mdl, 0.01)
betas <- bmdl$beta.t["ROI", ]
betasI <- makeImage(mask, betas)
loth <- quantile(betas, probs = 0.8)
if (verbose) {
plot(meanbold, betasI,
axis = 3, nslices = 30, ncolumns = 10,
window.overlay = c(loth, max(betas))
)
}
}
}
concatenatedMaps <- NA
if (havetemplateMap) {
concatenatedMaps <-
list(
toBold = mni2boldmaps, toBoldInversion = rep(FALSE, 4),
toTemplate = mni2boldmapsInv,
toTemplateInversion = c(TRUE, FALSE, TRUE, FALSE)
)
}
boldToTemplate <- NA
dmnAtBOLDres <- NA
seg2template <- NA
# if ( exists("mni") & is.na( templateImage ) ) {
# mni = antsImageRead( getANTsRData( "mni" ) )
# templateImage = resampleImage( mni, rep( 2.0 , 3 ) )
# }
if (!is.null(templateImage) & havetemplateMap) {
## map the fusedImg to the common template space
boldToTemplate <- antsApplyTransforms(
fixed = templateImage, moving = fusedImg,
transformlist = concatenatedMaps$toTemplate,
whichtoinvert = concatenatedMaps$toTemplateInversion,
imagetype = 3
)
dmnnodes <- antsImageRead(getANTsRData("mnidfn"))
dmnAtBOLDres <- resampleImageToTarget(dmnnodes, templateImage, 1)
seg2template <- antsApplyTransforms(templateImage, structuralSeg,
templateMap$invtransforms,
interpolator = "NearestNeighbor"
)
}
######################################################
## FIXME - this only works if maps are to MNI space ##
######################################################
## ----networklabels,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5----
pts <- NA
powersLabels <- NA
if (havetemplateMap) {
data("powers_areal_mni_itk", package = "ANTsR", envir = environment())
pts <- antsApplyTransformsToPoints(3, powers_areal_mni_itk,
transformlist = concatenatedMaps$toTemplate,
whichtoinvert = concatenatedMaps$toTemplateInversion
)
powersLabels <- makePowersPointsImage(pts, mask, radius = 1)
if (verbose) {
plot(meanbold, powersLabels,
axis = 3, nslices = 30, ncolumns = 10,
window.overlay = c(1, max(powersLabels))
)
}
}
return(
list(
fusedImg = fusedImg,
fusedImgFilt = fusedImgFilt,
seg2bold = seg2bold,
nodes2bold = dmnnodes,
boldToTemplate = boldToTemplate,
mapsToTemplate = concatenatedMaps,
runID = runNuis,
boldMat = boldMat,
boldMask = mask,
motionCorr = moco,
polyNuis = polyNuis,
timevals = timevals,
nuisance = nuisance,
FD = moco$fd$MeanDisplacement,
badtimes = badtimes,
dmnAtBOLDres = dmnAtBOLDres,
seg2template = seg2template,
networkPriors2Bold = networkPriors2Bold,
powersLabels = powersLabels,
powersPoints = pts,
connMatNodes = connMatNodes,
connMatNodesPartialCorr = connMatNodesPartialCorr
)
)
## ----roimeans,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5----
labelMask <- powersLabels * 1
labelMask[labelMask > 0] <- 1
labelMask[mask == 0] <- 0
labelVox <- which(subset(labelMask, mask > 0) == 1)
labeledBoldMat <- boldMat[goodtimes, labelVox]
labels <- powersLabels[labelMask > 0]
nLabels <- max(labels)
roiMat <- matrix(0, nrow = dim(labeledBoldMat)[1], ncol = nLabels)
for (i in c(1:nLabels)) {
if (length(which(labels == i)) > 1) {
roiMat[, i] <- rowMeans(labeledBoldMat[, (labels == i)])
}
}
nActualTimes <- dim(roiMat)[1]
## ----sysmean,message=FALSE,warnings=FALSE, fig.width=7, fig.height=10, echo=TRUE----
systemNames <- levels(pts$SystemName)
nSystems <- length(systemNames)
sysMatMean <- matrix(0, nrow = dim(labeledBoldMat)[1], ncol = nSystems)
sysMatSD <- matrix(0, nrow = dim(labeledBoldMat)[1], ncol = nSystems)
systems <- pts$SystemName[labels]
for (i in 1:nSystems) {
sys <- systemNames[i]
sysIdx <- which(systems == sys)
if (length(sysIdx) > 0) {
sysMatMean[, i] <- rowMeans(labeledBoldMat[, sysIdx])
sysMatSD[, i] <- apply(labeledBoldMat[, sysIdx], 1, sd)
}
}
## ----corr,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5--------
missingROIs <- which(colMeans(roiMat) == 0)
goodROIs <- (1:nLabels)
if (length(missingROIs) > 0) {
goodROIs <- goodROIs[-missingROIs]
}
connMat <- suppressWarnings(cor(roiMat))
diag(connMat) <- rep(0, length(diag(connMat)))
if (length(missingROIs) > 0) {
connMat[missingROIs, ] <- 0
connMat[, missingROIs] <- 0
}
## ----adjacency,message=FALSE,warnings=FALSE, fig.width=5, fig.height=5----
density <- 0.1
nEdges <- length(upper.tri(connMat)) * density
thresh <- sort(connMat[upper.tri(connMat)], decreasing = T)[nEdges]
adj <- 1 * (connMat >= thresh)
bingraph <- igraph::graph.adjacency(adj, mode = "undirected", weighted = NULL)
components <- igraph::clusters(bingraph)
maxID <- which(components$csize == max(components$csize))[1]
adj[components$membership != maxID, ] <- 0
adj[, components$membership != maxID] <- 0
bingraph <- igraph::graph.adjacency(adj, mode = "undirected", weighted = NULL)
if (verbose) invisible(plot(as.antsImage(adj)))
## ----adjacencyplot,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5, echo=FALSE----
if (verbose) {
pts$SystemName <- factor(pts$SystemName, levels = c("Sensory/Somatomotor Hand", "Sensory/Somatomotor Mouth", "Cingulo-opercular Task Control", "Auditory", "Default Mode", "Memory Retrieval", "Visual", "Fronto-parietal Task Control", "Salience", "Subcortical", "Ventral Attention", "Dorsal Attention", "Cerebellar", "Uncertain"))
graph <- igraph::graph.adjacency(adj, mode = "directed", weighted = NULL)
igraph::V(graph)$name <- pts$ROI
igraph::V(graph)$comm <- pts$SystemName
igraph::V(graph)$degree <- igraph::degree(graph)
systems <- levels(pts$SystemName)
systemNames <- as.character(systems)
}
# Retain only the largest connected component
bingraph <- igraph::graph.adjacency(adj, mode = "undirected", weighted = NULL)
components <- igraph::clusters(bingraph)
maxID <- which(components$csize == max(components$csize))[1]
adj[components$membership != maxID, ] <- 0
adj[, components$membership != maxID] <- 0
graph <- igraph::graph.adjacency(adj, mode = "undirected", weighted = NULL)
# Set node colors
graph <- igraph::set.vertex.attribute(graph, "r", index = igraph::V(graph), value = as.double(pts$r))
graph <- igraph::set.vertex.attribute(graph, "g", index = igraph::V(graph), value = as.double(pts$g))
graph <- igraph::set.vertex.attribute(graph, "b", index = igraph::V(graph), value = as.double(pts$b))
# Set edge colors
edges <- igraph::get.edges(graph, igraph::E(graph))
nEdges <- dim(edges)[1]
er <- rep(200, nEdges)
eg <- rep(200, nEdges)
eb <- rep(200, nEdges)
# colors for intra-system connections
# gray for inter-system connections
for (e in c(1:nEdges))
{
if (pts$SystemName[edges[e, 1]] == pts$SystemName[edges[e, 2]]) {
er[e] <- pts$r[edges[e, 1]]
eg[e] <- pts$g[edges[e, 1]]
eb[e] <- pts$b[edges[e, 1]]
}
}
graph <- igraph::set.edge.attribute(graph, "r", index = igraph::E(graph), value = as.double(er))
graph <- igraph::set.edge.attribute(graph, "g", index = igraph::E(graph), value = as.double(eg))
graph <- igraph::set.edge.attribute(graph, "b", index = igraph::E(graph), value = as.double(eb))
# uncomment line below to write out graph
# write.graph(graph, "network.graphml", format="graphml", prefixAttr=FALSE)
graph <- igraph::graph.adjacency(adj, mode = "undirected", weighted = NULL)
deg <- igraph::degree(graph)
deg[deg == 0] <- NA
pathsmat <- igraph::shortest.paths(graph, weights = NA)
pathsmat[!is.finite(pathsmat)] <- NA
paths <- rowMeans(pathsmat, na.rm = TRUE)
paths[paths == 0] <- NA
clust <- igraph::transitivity(graph, type = "local")
clust[deg < 2] <- NA
pager <- igraph::page.rank(graph)$vector
pager[deg < 2] <- NA
# from http://pastebin.com/XqkEYtJS
leff <- numeric(length(deg))
goodnodes <- which(deg > 1)
leff[goodnodes] <- sapply(
goodnodes,
function(x) {
neighbs <- igraph::neighbors(graph, v = x)
g.sub <- igraph::induced.subgraph(graph, neighbs)
Nv <- igraph::vcount(g.sub)
lpaths <- igraph::shortest.paths(g.sub, weights = NA)
lpaths <- paths[upper.tri(lpaths)]
pathsup <- lpaths[upper.tri(lpaths)]
2 / Nv / (Nv - 1) * sum(1 / lpaths[which(is.na(lpaths) == FALSE)])
}
)
leff[deg < 2] <- NA
leff[which(is.na(deg) == TRUE)] <- NA
## ----cnodeplot,message=FALSE,warnings=FALSE, fig.width=7, fig.height=5, echo=FALSE----
nNodes <- length(deg)
cnode.dat <- data.frame(Node = rep(1:nNodes, 5))
cnode.dat$Value <- c(deg, paths, leff, clust, pager)
cnode.dat$Metric <- c(
rep("Degree", nNodes),
rep("Shortest Path", nNodes),
rep("Local Efficiency", nNodes),
rep("Clustering Coefficient", nNodes),
rep("Page-Rank", nNodes)
)
geff <- 1 / (igraph::shortest.paths(graph))
geff[!is.finite(geff)] <- NA
geff <- mean(geff, na.rm = TRUE)
cc <- igraph::transitivity(graph)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.