Automated Visualization of mincLm and mincLmer Models - CoBrALab/documentation GitHub Wiki

Here you can find some example code which produces automatic figures from a model, in the below example, the code will produce a unified figure for each predictor, showing a triplanar view:

human_relative_tvalue-age

Here, we assume you have a dataframe data which contains all your information.

library(grid)
library(tidyverse)
library(MRIcrotome)
library(RMINC)
library(magrittr) #to be able to use "%>%"

## HERE GOES CODE TO SETUP DATAFRAME ETC ##

anatVol <- mincArray(mincGetVolume("template.mnc"))
averagemask <- mincArray(mincGetVolume("ask.mnc"))

model = mincLmer(relative ~ poly(age,2)*sex + (1|subject) + (1|dataset), data = data, mask = "mask.mnc", parallel = c("local",20))
model = mincLmerEstimateDF(model)
thresholds = attr(mincFDR(model), "thresholds")
print(thresholds)

#Here we figure out the extent of the mask, so we can use it to limit
# the FOV
# You may want to adjust these slighty buy adding/subtracting, so you don't
# quite go to the edge of the mask
dim1_begin <- min(which(averagemask == 1, arr.ind=TRUE)[,"dim1"])
dim1_end <-max(which(averagemask == 1, arr.ind=TRUE)[,"dim1"])
dim2_begin <- min(which(averagemask == 1, arr.ind=TRUE)[,"dim2"])
dim2_end <- max(which(averagemask == 1, arr.ind=TRUE)[,"dim2"])
dim3_begin <- min(which(averagemask == 1, arr.ind=TRUE)[,"dim3"])
dim3_end <- max(which(averagemask == 1, arr.ind=TRUE)[,"dim3"])

jacobian="relative"

# If your model is instead a mincLm, you need to use this loop command
# #for (predictor in dimnames(thresholds)[2](/CoBrALab/documentation/wiki/2)[c(-1,-2)]) {

for (predictor in dimnames(thresholds)[2](/CoBrALab/documentation/wiki/2)[c(-1)]) {
 
  #If you want to save this to a file, uncomment next line
  #svg(paste0("results/human_",jacobian,"_",predictor,".svg"), height = 3.1, width = 4)
  #We use a tryCatch here to keep going if there's some kind of error in a an individual plot
  tryCatch({
  #Here, we extract the thresholds from the code, and clip them to 2 digits, otherwise the plotting doesn't look good
  lowerthreshold = round(thresholds["0.05",predictor],digits=2)
  #Sometimes, there isn't an 0.01 threshold, when thats the case, we use the max instead, be careful to read the threshold array printed above
  upperthreshold = round(ifelse(is.na(thresholds["0.01",predictor]), max(c(max(mincArray(model, predictor)),abs(min(mincArray(model, predictor))))), thresholds["0.01",predictor]),digits=2)
  # Here is the plotting code, we do all three slice directions in one figure. This was optimized for a human brain, you may need to
  # adjust the nrow and ncol to get exactly the figure you want
  # You will also need to adjust the anatVol low and high values to correspond to good thresholds for your template
  sliceSeries(nrow = 5, ncol = 2, dimension = 2, begin = dim2_begin, end = dim2_end) %>%  
    anatomy(anatVol, low=1, high=5.9) %>%
    addtitle("Coronal") %>%
    overlay(mincArray(model, predictor),
      low=lowerthreshold, 
      high=upperthreshold, 
      symmetric = T, alpha=0.6) %>%
    sliceSeries(nrow = 6, ncol= 2, dimension = 1, begin = dim1_begin, end = dim1_end) %>%  
    anatomy(anatVol, low=1, high=5.9) %>%
    addtitle("Sagittal") %>%
    overlay(mincArray(model, predictor),   
      low=lowerthreshold,
      high=upperthreshold,
      symmetric = T, alpha=0.6) %>%
    sliceSeries(nrow = 5, ncol= 2, dimension = 3, begin = dim3_begin, end = dim3_end) %>% 
    anatomy(anatVol, low=1, high=5.9) %>%
    addtitle("Axial") %>%
    overlay(mincArray(model, predictor),
      low=lowerthreshold,
      high=upperthreshold,
      symmetric = T, alpha=0.6) %>%
    legend(predictor) %>%
    draw()}, error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
  #If you are saving to file, also uncomment this
  #dev.off()
}

Multiple figures

Here, we adjust the code to generate three figures, one for each view:

jacobian="relative"

for (predictor in dimnames(thresholds)[2](/CoBrALab/documentation/wiki/2)[-1]) {

  #We use a tryCatch here to keep going if there's some kind of error in a an individual plot
  tryCatch({
  #Here, we extract the thresholds from the code, and clip them to 2 digits, otherwise the plotting doesn't look good
  lowerthreshold = round(thresholds["0.05",predictor],digits=2)
  #Sometimes, there isn't an 0.01 threshold, when thats the case, we use the max instead, be careful to read the threshold array printed above
  upperthreshold = round(ifelse(is.na(thresholds["0.01",predictor]), max(c(max(mincArray(model, predictor)),abs(min(mincArray(model, predictor))))), thresholds["0.01",predictor]),digits=2)
  #svg(paste0("results/",jacobian,"_",predictor,"_coronal.svg"), height = 3.1, width = 4)
  sliceSeries(nrow = 5, ncol= 6, begin = dim2_begin, end = dim2_end, dimension = 2) %>%  #slice sequence to display stats
    anatomy(anatVol, low=1, high=5.9) %>%
    overlay(mincArray(model, predictor),     # specify which column of the mincLM model
            low=lowerthreshold, high=upperthreshold, symmetric = T, alpha=0.6) %>%       # t score range; symmetric = T means show positive and negative t values
    legend(predictor) %>%
    contourSliceIndicator(anatVol, c(1.8, 2), slice=125) %>%
    draw()
  #dev.off()

  #svg(paste0("results/",jacobian,"_",predictor,"_sagittal.svg"), height = 3.1, width = 4)
  sliceSeries(nrow = 5, ncol= 5, begin = dim1_begin, end = dim1_end, dimension = 1) %>%  #slice sequence to display stats
    anatomy(anatVol, low=1, high=5.9) %>%
    overlay(mincArray(model, predictor),     # specify which column of the mincLM model
            low=lowerthreshold, high=upperthreshold, symmetric = T, alpha=0.6) %>%       # t score range; symmetric = T means show positive and negative t values
    contourSliceIndicator(anatVol, c(1.8, 2), slice=125) %>%
    legend(predictor) %>%
    draw()
  #dev.off()

  #svg(paste0("results/",jacobian,"_",predictor,"_axial.svg"), height = 3.1, width = 4)
  sliceSeries(nrow = 4, ncol= 6, begin = dim3_begin, end = dim3_end, dimension = 3) %>%  #slice sequence to display stats
    anatomy(anatVol, low=1, high=5.9) %>%
    overlay(mincArray(model, predictor),     # specify which column of the mincLM model
            low=lowerthreshold, high=upperthreshold, symmetric = T, alpha=0.6) %>%       # t score range; symmetric = T means show positive and negative t values
    legend(predictor) %>%
    contourSliceIndicator(anatVol, c(1.8, 2), slice=125) %>%
    draw()
  #dev.off()
     }, error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
}

rel_jacobian_tvalue-sex_cherylF_sagittal rel_jacobian_tvalue-sex_cherylF_coronal rel_jacobian_tvalue-sex_cherylF_axial

Automatic Visualization with transparent thresholds

library(grid)
library(tidyverse)
library(MRIcrotome)
library(RMINC)
library(magrittr) #to be able to use "%>%"

## HERE GOES CODE TO SETUP DATAFRAME ETC ##

anatVol <- mincArray(mincGetVolume("template.mnc"))
averagemask <- mincArray(mincGetVolume("ask.mnc"))

model = mincLmer(relative ~ poly(age,2)*sex + (1|subject) + (1|dataset), data = data, mask = "mask.mnc", parallel = c("local",20))
model = mincLmerEstimateDF(model)
thresholds = attr(mincFDR(model), "thresholds")
print(thresholds)

#Here we figure out the extent of the mask, so we can use it to limit
# the FOV
# You may want to adjust these slighty buy adding/subtracting, so you don't
# quite go to the edge of the mask
dim1_begin <- min(which(averagemask == 1, arr.ind=TRUE)[,"dim1"])
dim1_end <-max(which(averagemask == 1, arr.ind=TRUE)[,"dim1"])
dim2_begin <- min(which(averagemask == 1, arr.ind=TRUE)[,"dim2"])
dim2_end <- max(which(averagemask == 1, arr.ind=TRUE)[,"dim2"])
dim3_begin <- min(which(averagemask == 1, arr.ind=TRUE)[,"dim3"])
dim3_end <- max(which(averagemask == 1, arr.ind=TRUE)[,"dim3"])

jacobian="relative"

# If your model is instead a mincLm, you need to use this loop command
# #for (predictor in dimnames(thresholds)[2](/CoBrALab/documentation/wiki/2)[c(-1,-2)]) {

for (predictor in dimnames(thresholds)[2](/CoBrALab/documentation/wiki/2)[c(-1)]) {
 
  #If you want to save this to a file, uncomment next line
  #svg(paste0("results/human_",jacobian,"_",predictor,".svg"), height = 3.1, width = 4)
  #We use a tryCatch here to keep going if there's some kind of error in a an individual plot
  tryCatch({
  #Here, we extract the thresholds from the code, and clip them to 2 digits, otherwise the plotting doesn't look good
  lowerthreshold = round(thresholds["0.05",predictor],digits=2)
  #Sometimes, there isn't an 0.01 threshold, when thats the case, we use the max instead, be careful to read the threshold array printed above
  upperthreshold = round(ifelse(is.na(thresholds["0.01",predictor]), max(c(max(mincArray(model, predictor)),abs(min(mincArray(model, predictor))))), thresholds["0.01",predictor]),digits=2)

# Generate the default colourmaps
pospal = colorRampPalette(c("red", "yellow"), alpha=TRUE)(255)
negpal = colorRampPalette(c("blue", "turquoise1"), alpha=TRUE)(255)

  # Find the crossover point in the map where the colourmap switches to "non transparent"
  # Need to include the alpha term here, but its always opaque
  breakpointpos = pospal[round(lowerthreshold/upperthreshold*255) - 1]
  breakpointneg = negpal[round(lowerthreshold/upperthreshold*255) - 1]

  # Generate a subset of the colourmap now which ramps from the same starting point and ends at breakpoint, with full opacity
  pospalalpha = colorRampPalette(c("#FF000000", breakpointpos), alpha=TRUE)(round(lowerthreshold/upperthreshold*255) - 1)
  negpalalpha = colorRampPalette(c("#0000FF00", breakpointneg), alpha=TRUE)(round(lowerthreshold/upperthreshold*255) - 1)

  # Concatenate the two maps together for a complete map
  combinedpospal = c(pospalalpha, pospal[round(lowerthreshold/upperthreshold*255):length(pospal)])
  combinednegpal = c(negpalalpha, negpal[round(lowerthreshold/upperthreshold*255):length(negpal)])


  # Here is the plotting code, we do all three slice directions in one figure. This was optimized for a human brain, you may need to
  # adjust the nrow and ncol to get exactly the figure you want
  # You will also need to adjust the anatVol low and high values to correspond to good thresholds for your template
  sliceSeries(nrow = 5, ncol = 2, dimension = 2, begin = dim2_begin, end = dim2_end) %>%  
    anatomy(anatVol, low=1, high=5.9) %>%
    addtitle("Coronal") %>%
    overlay(mincArray(model, predictor),
          low = 0,
          high = upperthreshold,
          col = combinedpospal,
          rCol = combinednegpal,
      symmetric = T) %>%
    contours(abs(mincArray(model, predictor)), levels=lowerthreshold, lwd=2, col="black") %>%
    sliceSeries(nrow = 6, ncol= 2, dimension = 1, begin = dim1_begin, end = dim1_end) %>%  
    anatomy(anatVol, low=1, high=5.9) %>%
    addtitle("Sagittal") %>%
    overlay(mincArray(model, predictor),   
          low = 0,
          high = upperthreshold,
          col = combinedpospal,
          rCol = combinednegpal,
      symmetric = T) %>%
  contours(abs(mincArray(model, predictor)), levels=lowerthreshold, lwd=2, col="black") %>%    
  sliceSeries(nrow = 5, ncol= 2, dimension = 3, begin = dim3_begin, end = dim3_end) %>% 
    anatomy(anatVol, low=1, high=5.9) %>%
    addtitle("Axial") %>%
    overlay(mincArray(model, predictor),
          low = 0,
          high = upperthreshold,
          col = combinedpospal,
          rCol = combinednegpal,
      symmetric = T) %>%
    legend(predictor) %>%
  contours(abs(mincArray(model, predictor)), levels=lowerthreshold, lwd=2, col="black") %>%
    draw()}, error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
  #If you are saving to file, also uncomment this
  #dev.off()

image