#' Plotting an image slice or multi-slice with optional color overlay.
#'
#' This is a plotting utility for antsImage types with a background and color
#' overlay option. Useful for displaying statistical results overlaid on a
#' background image.
#'
#' @param x the reference image on which to overlay.
#' @param y image or list of images to use as overlays.
#' @param color.img color for main image.
#' @param color.overlay the color for the overlay , e.g c('blue','red') length
#' of this list should match the image list.
#' @param axis the axis to slice (1 , 2 or 3)
#' @param slices vector of slices to plot (e.g., c(10, 15, 20))
#' @param colorbar make colorbar?
#' @param title.colorbar title for colorbar
#' @param title.img title for main image (not displayed when file is saved with outname)
#' @param title.line title vertical displacement (irrelevant when a file is saved with outname)
#' @param color.colorbar color scale to use for colorbar
#' @param window.img lower and upper thresholds for display of main image
#' @param window.overlay lower and upper thresholds for display of overlay.
#' if you set \code{window.overlay = c( 0, 100 )} and \code{useAbsoluteScale=T}
#' then the image overlay will map into that range. otherswise, the min and
#' max of the image will be used.
#' @param quality integer quality magnification factor 1 => large (e.g.
#' 10)
#' @param outname name of output file if you want to write result to file, e.g.
#' \code{plot.jpg}.
#' @param alpha opacity
#' @param newwindow boolean controlling if we open a new device for this plot
#' @param nslices number of slices to view
#' @param domainImageMap this input antsImage or list contains a reference image
#' (\code{domainImage}) and optional reference mapping named \code{domainMap}.
#' these will be used to map the input image(s) to this antsImage space before
#' plotting. this is useful for non-standard image orientations.
#' @param ncolumns number of columns in plot
#' @param useAbsoluteScale boolean determines whether dynamic range is maximized
#' when visualizing overlays
#' @param doCropping apply cropping, defaults to \code{TRUE}
#' @param text vector containing x, y, label, cex and color values passed to
#' text command, e.g. \code{txt=list(x=0,y=0,label='my text',cex=2,col='red')}
#' @param begin The (corrected) hue in [0,1] at which the viridis colormap
#' begins.
#' @param end The (corrected) hue in [0,1] at which the viridis colormap
#' ends
#' @param direction Sets the order of colors in the scale.
#' If 1, the default, colors are ordered from darkest to lightest.
#' If -1, the order of colors is reversed.
#' @param ... other parameters
#' @return output is plot to standard R window
#' @author Avants BB
#' @examples
#'
#' img <- makeImage(c(4,4), rnorm(4*4))
#' mask <- makeImage(c(4,4),
#' as.matrix(c(0,0,0,0,
#' 0,1,1,0,
#' 0,1,1,0,
#' 0,0,0,0), nrow=4))
#' plot(img, list(mask))
#' txt=list(x=2.5,y=1.5,label='my text',cex=4,col='red')
#' plot(img, list(mask), text=txt)
#' testthat::expect_error(plot(multi_component_image))
#'
#' \dontrun{
#'
#' img = antsImageRead( getANTsRData( 'r16' ) )
#' betaVals = rnorm( prod( dim( img ) ), 0, 20 )
#' betaImg = makeImage( dim( img ), betaVals ) %>% smoothImage( 3.5 )
#' betaImg[ abs( betaImg ) < 1.5 ] = 0
#' plot( img, betaImg, window.img=range(img) ,window.overlay=range(betaImg) )
#'
#' mnit<-getANTsRData('mni')
#' mnit<-antsImageRead(mnit)
#' mniafn<-getANTsRData('mnia')
#' mnia<-antsImageRead(mniafn)
#' mnia<-thresholdImage(mnia,22,25)
#' mnia<-smoothImage(mnia,1.5)
#' mnia2<-antsImageRead(mniafn)
#' mnia2<-thresholdImage(mnia2,1,4)
#' mnia2<-smoothImage(mnia2,1.5)
#' ofn<-paste(tempfile(),'.png',sep='')
#' # write directly to a file
#' plot( mnit, list(mnia,mnia2), slices=seq(50, 140, by=5),
#' window.overlay = c(0.25,1), axis=2,
#' color.overlay=c('red','blue'), outname = ofn )
#' }
#'
#' @method plot antsImage
#' @export
#' @importFrom grDevices colorRampPalette dev.new dev.off heat.colors hsv
#' @importFrom grDevices jpeg png rainbow rgb
#' @importFrom graphics box hist image layout lcm par plot plot.new
#' @importFrom graphics plot.window points rect title
#' @importFrom stats ar as.formula coefficients convolve cor cor.test cov dist
#' @importFrom stats formula glm lm lm.fit loess median model.frame model.matrix
#' @importFrom stats model.response na.omit optimize p.adjust pchisq pf pnorm
#' @importFrom stats ppois predict pt qchisq qf qnorm qt quantile residuals rnorm
#' @importFrom stats spec.pgram spline stl t.test toeplitz ts
#' @importFrom utils capture.output data download.file glob2rx install.packages
#' @importFrom utils read.csv setTxtProgressBar tail txtProgressBar unzip
#' @importFrom utils write.csv
plot.antsImage <- function(x, y,
color.img = "white",
color.overlay = c("jet", "red", "blue", "green", "yellow", "viridis", "magma", "plasma", "inferno"),
axis = 2,
slices,
colorbar = missing(y),
title.colorbar,
title.img,
title.line=NA,
color.colorbar,
window.img,
window.overlay,
quality = 2,
outname = NA,
alpha = 1.0,
direction = 1,
begin = 0,
end = 1,
newwindow = FALSE,
nslices = 10,
domainImageMap = NA,
ncolumns = 4,
useAbsoluteScale = FALSE,
doCropping = TRUE,
text,
... ) {
if ( x@components > 1 )
{
stop("Cannot plot multichannel image: splitChannels, then plot as overlays.")
}
if ( ! is.antsImage( x ) ) stop("input x should be an antsImage.")
interpNN = 'NearestNeighbor'
interpStyle = 'Linear'
if ( ! missing( "y" ) )
{
if ( is.antsImage( y ) ) y <- list(y)
for ( i in 1:length( y ) ) {
if ( antsImagePhysicalSpaceConsistency( x, y[[i]] ) == FALSE ) {
y[[ i ]] = resampleImageToTarget( y[[i]], x, interpType = interpStyle )
}
}
}
if ( ! any( is.na( domainImageMap ) ) )
{
if ( is.antsImage( domainImageMap ) )
{
tx = new("antsrTransform", precision="float",
type="AffineTransform", dimension = x@dimension )
x = applyAntsrTransformToImage(tx, x, domainImageMap )
if ( ! missing( "y" ) )
{
if ( is.antsImage( y ) ) y <- list(y)
for ( i in 1:length( y ) )
y[[ i ]] =
applyAntsrTransformToImage(tx, y[[ i ]], domainImageMap,
interpolation = interpStyle )
}
}
if ( is.list( domainImageMap ) ) # expect an image and transformation
{
if ( length( domainImageMap ) != 2 ) stop("domainImageMap list Should be length 2.")
dimg = domainImageMap[[1]]
if ( ! is.antsImage( dimg ) )
stop("domainImageMap list first entry list should be antsImage.")
tx = domainImageMap[[2]]
x = antsApplyTransforms( dimg, x, transformlist = tx )
if ( ! missing( "y" ) )
{
if ( is.antsImage( y ) ) y <- list(y)
for ( i in 1:length( y ) )
y[[ i ]] = antsApplyTransforms( dimg, y[[ i ]], transformlist = tx,
interpolator = interpStyle )
}
}
}
if ( length( dim( x ) ) < axis ) axis = length( dim( x ) )
if(missing(slices)){
plotimask<-getMask(x, cleanup=0)
if ( max( plotimask ) == 0 ) plotimask = plotimask + 1
if ( doCropping ) x <- cropImage(x, plotimask )
slices <- round(seq(1, dim(x)[axis], length.out=nslices))
}
startpar <- par(c("mar", "las", "mfrow"))$mar
nonzeros <- x[x != 0]
if(missing(window.img)){
if (length(nonzeros) > 0 ){
window.img <- quantile(nonzeros, c(0.05, 0.95))
} else {
window.img <- c(0, 0)
}
}
color.colorbar <- ifelse(missing(y), "white", color.overlay[1])
myantsimage <- x
if (missing(y))
y <- NA
if (is.antsImage(y))
y <- list(y)
imagedim <- length(dim(myantsimage))
hvpx <- usePkg("pixmap")
hvmsc <- usePkg("misc3d")
if ( !hvmsc | ! hvpx )
{
print(paste("You need misc3d and pixmap libraries to use this."))
invisible(return())
}
read.img <- function(x, dim = 2) {
img <- antsImageRead(x, dim)
img <- as.array(img)
}
# define a bunch of functions for rotating matrices Flip matrix (upside-down)
flip.matrix <- function(x) {
mirror.matrix(rotate180.matrix(x))
}
# Mirror matrix (left-right)
mirror.matrix <- function(x) {
xx <- as.data.frame(x)
xx <- rev(xx)
xx <- as.matrix(xx)
xx
}
# Rotate matrix 90 clockworks
rotate90.matrix <- function(x) {
t(mirror.matrix(x))
}
# Rotate matrix 180 clockworks
rotate180.matrix <- function(x) {
xx <- rev(x)
dim(xx) <- dim(x)
xx
}
# Rotate matrix 270 clockworks
rotate270.matrix <- function(x) {
mirror.matrix(t(x))
}
############################################################################ Color methods The inverse function to col2rgb()
rgb2col <- function(rgb) {
hexDigit <- c(0:9, "A", "B", "C", "D", "E", "F")
rgb <- rgb%%256
hi <- rgb%/%16
# lo <- rgb %% 16
lo <- rgb - 16 * hi # Faster?
x <- t(matrix(c(hi, lo), ncol = 2)) + 1
s <- matrix(hexDigit[x], nrow = 6)
s <- apply(s, MARGIN = 2, FUN = paste, collapse = "")
paste("#", s, sep = "")
}
############################################################################ Draw methods
image180 <- function(z, ...) {
image(rotate180.matrix(z), ...)
}
image270 <- function(z, ...) {
image(rotate270.matrix(z), ...)
}
makePalette <- function( mpcolor, nlevels=15){
if ( mpcolor == "viridis") return( viridis::viridis( nlevels ) )
if ( mpcolor == "magma") return( viridis::magma( nlevels ) )
if ( mpcolor == "plasma") return( viridis::plasma( nlevels ) )
if ( mpcolor == "inferno") return( viridis::inferno( nlevels ) )
if (mpcolor == "white"){
colorfun <- colorRampPalette(c("black", "white"), interpolate = c("spline"),
space = "Lab")
} else if (mpcolor != "jet"){
colorfun <- colorRampPalette(c("white", mpcolor), interpolate = c("spline"),
space = "Lab")
} else {
colorfun <- colorRampPalette(c("#00007F", "blue", "#007FFF", "cyan",
"#7FFF7F", "yellow", "#FF7F00", "red", "#7F0000"), interpolate = c("spline"),
space = "Lab")
}
colorfun(nlevels)
}
if (all(is.na(y))) {
thresh <- "1.e9x1.e9"
}
# .................................................
img <- as.array(myantsimage) # the background/template image
if (imagedim == 2) {
img <- rotate270.matrix(img)
}
perms <- c(1, 2, 3)
axis <- as.numeric(axis)
if (axis == 1) {
perms <- c(2, 3, 1)
}
if (axis == 2) {
perms <- c(3, 1, 2)
}
if (axis == 3) {
perms <- c(1, 2, 3)
}
# now label the results
if (imagedim == 3)
img <- aperm(img, c(perms), resize = T)
if(class(slices) == "character"){
slices <- c(as.numeric(unlist(strsplit(slices, "x"))))
slices <- round(seq(slices[1], slices[2], by=slices[3]))
}
if (max(slices) > dim(myantsimage)[axis]) {
stop("Slices do not fit in image dimensions.")
}
if ( imagedim == 2 )
slices <- 1
nslices <- length(slices)
winrows <- ceiling(length(slices) / ncolumns ) # controls number of rows
if (winrows < 1)
winrows <- 1
wincols <- ncolumns # controls number of columns
if (length(slices) < wincols )
wincols <- length(slices)
reoSlice <- function( inimg )
{
if (axis != 2 & imagedim > 2)
slice <- rotate90.matrix(inimg[, , slices[1]])
if (axis == 2 & imagedim > 2)
slice <- flip.matrix(inimg[, , slices[1]])
if (imagedim > 2)
slice <- mirror.matrix(slice) else slice <- img
return( slice )
}
slice = reoSlice( img )
slicerow <- nrow(slice)
slicecol <- ncol(slice)
bigslice <- matrix(0, nrow = slicerow * winrows, ncol = (slicecol * wincols))
rowsl <- 0
# convert to 0 255
nlevels <- 2^8
reoSlice2 <- function( inimg, insl )
{
if (axis != 2 & imagedim > 2)
slice <- rotate90.matrix(inimg[, , slices[insl + 1]])
if (axis == 2 & imagedim > 2 )
slice <- flip.matrix(inimg[, , slices[insl + 1]])
if (imagedim > 2) {
slice <- mirror.matrix(slice)
} else {
slice <- inimg
}
return( slice )
}
for (sl in c(0:(length(slices) - 1))) {
if (sl < dim(img)[imagedim]) {
slice = reoSlice2( img, sl )
locsl <- (sl%%(wincols)) + 1
if (locsl == 1)
rowsl <- rowsl + 1
xl <- ((locsl - 1) * slicecol + 1)
xs <- c(xl:(xl + slicecol - 1))
yl <- (rowsl - 1) * slicerow + 1
ys <- c(yl:(yl + slicerow - 1))
bigslice[ys, xs] <- slice
}
}
# pdf(paste(output,'.pdf',sep='')) onm<-paste(output,'.jpg',sep='')
bbox <- c(1, 1, c(1+antsGetSpacing(myantsimage)[-axis]*dim(myantsimage)[-axis]) *
c(wincols, winrows))
mag <- quality
pixperinch <- 96
if (!is.na(outname)){
suppressMessages(jpeg(outname, width = ncol(bigslice) * mag,
height = nrow(bigslice) * mag, units = "px", quality = 75, bg = "white"))
} else {
if (newwindow) dev.new(height = nrow(bigslice)/pixperinch, width = ncol(bigslice)/pixperinch)
}
if ( window.img[ 1 ] == window.img[ 2 ] )
window.img[ 1 ]<-min( x )
bigslice[bigslice<window.img[1]] <- window.img[1]
bigslice[bigslice>window.img[2]] <- window.img[2]
if ( colorbar & missing( y ) ){
nlev = 50
levels <- seq(window.img[1], window.img[2], length.out=nlev)
# code taken from filled.contour
mar.orig <- (par.orig <- par(c("mar", "las", "mfrow")))$mar
on.exit(par(par.orig))
w <- (3 + mar.orig[2L]) * par("csi") * 2.54
layout(matrix(c(2, 1), ncol = 2L), widths = c(1, lcm(w)))
par(las = 1)
mar <- mar.orig
mar[4L] <- mar[2L]
mar[2L] <- 1
par(mar = mar)
plot.new()
plot.window(xlim = c(0, 1), ylim = range(levels), xaxs = "i",
yaxs = "i")
rect(0, levels[-length(levels)], 1, levels[-1L],
col = makePalette(color.colorbar, nlev))
axis(4)
box()
if (!missing(title.colorbar))
title(title.colorbar)
mar <- mar.orig
mar[4L] <- 1
par(mar = mar)
}
if ( ! missing( window.overlay ) ) {
eps = 1.e-8
window.overlay[1] = window.overlay[1] - eps
window.overlay[2] = window.overlay[2] + eps
}
if(colorbar & !missing(y)){
nlev = 50
levels <- seq(window.overlay[1], window.overlay[2], length.out=nlev )
# code taken from filled.contour
mar.orig <- (par.orig <- par(c("mar", "las", "mfrow")))$mar
on.exit(par(par.orig))
w <- (3 + mar.orig[2L]) * par("csi") * 2.54
layout(matrix(c(2, 1), ncol = 2L), widths = c(1, lcm(w)))
par(las = 1)
mar <- mar.orig
mar[4L] <- mar[2L]
mar[2L] <- 1
par(mar = mar)
plot.new()
plot.window(xlim = c(0, 1), ylim = range(levels), xaxs = "i",
yaxs = "i")
rect(0, levels[-length(levels)], 1, levels[-1L],
col = makePalette(color.colorbar, nlev))
axis(4)
box()
if (!missing(title.colorbar))
title(title.colorbar)
mar <- mar.orig
mar[4L] <- 1
par(mar = mar)
}
img.plot <- suppressWarnings(pixmap::pixmapGrey(
bigslice, bbox=bbox ) )
# dd<-pixmapRGB(c(bigslice,bigslice,bigslice),nrow=nrow(bigslice),ncol=ncol(bigslice),bbox=c(0,0,wincols,winrows))
# plot(dd)
par(mar = c(0, 0, 0, 0) + 0) # set margins to zero ! less wasted space
pixmap::plot(img.plot, bg = "white")
if (!missing(title.img))
title(title.img, line=title.line)
if (missing(window.overlay) & !all(is.na(y))) {
window.overlay <- quantile(y[[1]][y[[1]] != 0], c(0.05, 0.95))
if(window.overlay[1] == window.overlay[2]){
window.overlay[1] <- min(y[[1]])
window.overlay[2] <- max(y[[1]])
}
} else {
# window.overlay <- NA
}
if ( ! missing( window.overlay ) )
if ( typeof(window.overlay) == "character" ){
window.overlay <- c(as.numeric(unlist(strsplit(window.overlay, "x"))))
}
if ( ! missing( window.overlay ) )
if ( ( window.overlay[1] > window.overlay[2] ) |
all( is.na( y ) ) ) {
if (!is.na(outname))
dev.off()
invisible(return())
}
if ( ! all( is.na( y ) ) )
{
for (ind in 1:length( y )) {
biglab <- matrix(0, nrow = slicerow * winrows, ncol = (slicecol * wincols))
if ( exists("plotimask") ) { # the label image
if ( doCropping )
{
fimg = cropImage(y[[ind]], plotimask )
labimg <- as.array( fimg )
} else labimg <- as.array( y[[ind]] )
} else labimg <- as.array(y[[ind]]) # the label image
labimg[ labimg < window.overlay[1] ] = 0
labimg[ labimg > window.overlay[2] ] = 0
if (imagedim == 2) {
labimg <- rotate270.matrix(labimg)
}
if (imagedim == 3)
labimg <- aperm(labimg, c(perms), resize = T)
# check sizes
# if ( ! antsImagePhysicalSpaceConsistency( img, labimg ) )
# stop("Image and overlay image sizes do not match.")
mncl <- min(labimg)
mxcl <- max(labimg)
if ( useAbsoluteScale )
{
mncl = window.overlay[1]
mxcl = window.overlay[2]
}
temp <- labimg
temp <- (temp - mncl)/(mxcl - mncl) * (nlevels - 1)
temp[ temp < 0 ] = 0
temp[ temp > 255 ] = 0
labimg <- temp
locthresh <- round((window.overlay[1:2] - mncl) /
(mxcl - mncl) * (nlevels - 1))
zeroval = round(( 0 - mncl) /
(mxcl - mncl) * (nlevels - 1))
if ( ( min(locthresh) == max(locthresh) ) | any(is.na(locthresh) ) )
locthresh=c(0,1)
labslice = reoSlice( labimg )
slicerow <- nrow(slice)
slicecol <- ncol(slice)
bigslice <- matrix(0, nrow = slicerow * winrows, ncol = (slicecol * wincols))
rowsl <- 0
for (sl in c(0:(length(slices) - 1))) {
if (sl < dim(img)[imagedim]) {
labslice = reoSlice2( labimg, sl )
locsl <- (sl%%(wincols)) + 1
if (locsl == 1)
rowsl <- rowsl + 1
xl <- ((locsl - 1) * slicecol + 1)
xs <- c(xl:(xl + slicecol - 1))
yl <- (rowsl - 1) * slicerow + 1
ys <- c(yl:(yl + slicerow - 1))
biglab[ys, xs] <- labslice
}
}
overlaycolors <- c(0:nlevels)
minind <- 0
mindiff <- 1e+09
maxind <- 0
maxdiff <- 1e+09
for (i in c(1:length(overlaycolors))) {
diff <- abs(overlaycolors[i] - locthresh[1])
if (diff < mindiff) {
minind <- i
mindiff <- diff
}
diff <- abs(overlaycolors[i] - locthresh[2])
if (diff < maxdiff) {
maxind <- i
maxdiff <- diff
}
}
if (minind > 1)
minind <- minind - 1
colorfun = rainbow
heatvals <- heat.colors(nlevels, alpha = alpha)
heatvals <- rainbow(nlevels, alpha = alpha)
if ( color.overlay[ind] != "jet" & color.overlay[ind] != "viridis" & color.overlay[ind] != "magma" & color.overlay[ind] != "plasma" & color.overlay[ind] != "inferno" )
colorfun <- colorRampPalette(c("white", color.overlay[ind]), interpolate = c("spline"),
space = "Lab")
if (color.overlay[ind] == "jet") {
# print('use jet')
colorfun <- colorRampPalette(c("#00007F", "blue", "#007FFF", "cyan",
"#7FFF7F", "yellow", "#FF7F00", "red", "#7F0000"), interpolate = c("spline"),
space = "Lab")
}
if (color.overlay[ind] == "viridis") {
colorfun <- colorRampPalette( viridis::viridis( nlevels, alpha = alpha, direction = direction, begin = begin, end = end ) , interpolate = c("spline"),
space = "Lab")
}
heatvals <- colorfun(nlevels)
if ( color.overlay[ind] == "viridis" ) heatvals <- viridis::viridis( nlevels, alpha = alpha, direction = direction, begin = begin, end = end )
if ( color.overlay[ind] == "magma" ) heatvals <- viridis::magma( nlevels, alpha = alpha, direction = direction, begin = begin, end = end )
if ( color.overlay[ind] == "plasma" ) heatvals <- viridis::plasma( nlevels, alpha = alpha, direction = direction, begin = begin, end = end )
if ( color.overlay[ind] == "inferno" ) heatvals <- viridis::inferno( nlevels, alpha = alpha, direction = direction, begin = begin, end = end )
# fix to get alpha transparency correct
if (nchar(heatvals[1]) == 7 & alpha != 1) heatvals = paste0(heatvals,round(alpha*100,0))
if (locthresh[1] > 1)
heatvals[1:(locthresh[1] - 1)] <- NA
if (locthresh[2] < (nlevels - 1)) {
upper <- c((locthresh[2] + 1):nlevels)
heatvals[upper] <- NA
}
heatvals[ max( c(zeroval,(zeroval))):(zeroval+1) ]<-NA # dont overlay the background
if ( useAbsoluteScale )
{
biglab[1]=255
biglab[2]=0
}
mn = min(biglab,na.rm=T)
mx = max(biglab,na.rm=T)
if ( ( mn != mx ) & ( mn < mx ) )
{
invisible( suppressWarnings(
pixmap::plot(
pixmap::pixmapIndexed(biglab,
col = heatvals, bbox = bbox), add = TRUE) ) )
}
} # for loop
} # if not all na y
# g<-biglab ; g[]<-0 ; b<-biglab ; b[]<-0 print('try rgb')
# dd<-pixmapRGB(c(biglab,g,b),nrow=nrow(bigslice),ncol=ncol(bigslice),bbox=c(0,0,wincols,winrows))
par( mar = startpar ) # set margins to zero ! less wasted space
if ( ! missing( "text" ) )
text( x = text$x, y = text$y, label = text$label, cex = text$cex, col=text$col )
if (!is.na(outname))
dev.off()
invisible(return())
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.