R/powersACTrsfMRIprocessing.R

Defines functions fMRINormalization

Documented in fMRINormalization

#' 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:
#' \itemize{
#'   \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 ( class( extraRuns )[[1]] != "list"  )
      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)


}
neuroconductor-devel/ANTsR documentation built on April 1, 2021, 1:02 p.m.