├── .Rbuildignore ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── NAMESPACE ├── R └── ggBrainCode.r ├── README.md ├── appveyor.yml ├── ggBrain.Rproj ├── inst ├── brain_mask.nii.gz ├── seed_corr_1.nii.gz ├── seed_corr_2.nii.gz ├── seed_mask.nii.gz ├── subj_trunc_1.nii.gz └── template.nii.gz ├── man ├── ggBrain.Rd ├── sign_no_zero.Rd └── theme_black_bg.Rd └── vignettes ├── figure ├── 2brain_compare.png ├── 4panel.png ├── fMRI.png ├── line-key-corr.png ├── line-key-str.png ├── single-plots-abs-val.png ├── single-plots-bf.png ├── single-plots-no-template.png ├── single-plots-seed-corr.png ├── single-plots-structural.png ├── tri-panel1.png └── tri-panel2.png ├── intro.html ├── intro.md └── intro.rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^\.travis\.yml$ 2 | ^.*\.Rproj$ 3 | ^\.Rproj\.user$ 4 | 5 | R/ggBrain\.R 6 | ^appveyor\.yml$ 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: false 5 | cache: packages 6 | warnings_are_errors: true 7 | 8 | notifications: 9 | email: 10 | on_success: change 11 | on_failure: change 12 | 13 | before_install: 14 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install libcgal-dev libglu1-mesa-dev mesa-common-dev; fi 15 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: ggBrain 2 | Title: ggplot Brain Images 3 | Description: Plotting brain images with ggplot2 using 'nifti' objects. Useful 4 | for integrating with a tidy image framework. 5 | Version: 0.1.2 6 | Authors@R: c(person(given = "Aaron", family = "Fisher", email = "afishe27@alumni.jh.edu", 7 | role = c("aut", "cre")), 8 | person(given = "John", family = "Muschelli", role = c("ctb"))) 9 | Maintainer: Aaron Fisher 10 | VignetteBuilder: knitr 11 | Depends: 12 | R (>= 3.0.2) 13 | Imports: 14 | ggplot2, 15 | RColorBrewer 16 | Suggests: 17 | knitr, 18 | gridExtra, 19 | brainR, 20 | oro.nifti 21 | License: GPL-2 22 | LazyData: true 23 | RoxygenNote: 6.0.1.9000 24 | Encoding: UTF-8 25 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(getBrainFrame) 4 | export(ggBrain) 5 | export(sign_no_zero) 6 | export(theme_all_blank) 7 | export(theme_black_bg) 8 | export(theme_no_ticks) 9 | import(RColorBrewer) 10 | import(ggplot2) 11 | -------------------------------------------------------------------------------- /R/ggBrainCode.r: -------------------------------------------------------------------------------- 1 | 2 | 3 | # _ _ _ 4 | # (_) | | | | 5 | # _ _ __ | |_ ___ _ __ _ __ __ _| |___ 6 | # | | '_ \| __/ _ \ '__| '_ \ / _` | / __| 7 | # | | | | | || __/ | | | | | (_| | \__ \ 8 | # |_|_| |_|\__\___|_| |_| |_|\__,_|_|___/ 9 | 10 | 11 | 12 | # internal helper functions 13 | sub3dMat<-function(x,MARGIN,ind){ 14 | if(MARGIN==1) out<-x[ind,,] 15 | if(MARGIN==2) out<-x[,ind,] 16 | if(MARGIN==3) out<-x[,,ind] 17 | out 18 | } 19 | 20 | 21 | # x is a 4D brain image 22 | # mar, ind and time are scalar 23 | array2long<-function(x,mask=!is.na(x[,,,1]),mar,ind,time=1,center_coords=TRUE){ 24 | x_s<-sub3dMat(x[,,,time],mar,ind) 25 | mask_s<-sub3dMat(mask==1,mar,ind) 26 | coords<-which(mask_s,arr.ind=TRUE) 27 | if(center_coords) coords<-t(apply(coords,1,function(row_x) { 28 | row_x-dim(mask)[c(1:3)[-mar]]/2 })) 29 | value<-x_s[mask_s] 30 | out<-cbind(value,coords) 31 | out 32 | } 33 | 34 | facet_just_unique<-function(row_ind,col_ind){ 35 | if( all(row_ind==row_ind[1]) & all(col_ind==col_ind[1])) 36 | out<-NULL 37 | if( all(row_ind==row_ind[1]) & !all(col_ind==col_ind[1])) 38 | out<-facet_grid(.~col_ind) 39 | if(!all(row_ind==row_ind[1]) & all(col_ind==col_ind[1])) 40 | out<-facet_grid(row_ind~.) 41 | if(!all(row_ind==row_ind[1]) & !all(col_ind==col_ind[1])) 42 | out<-facet_grid(row_ind~col_ind) 43 | 44 | return(out) 45 | } 46 | 47 | # ... is passed to getBrainFrame 48 | getggTemplate<-function(col_template,row_ind,col_ind, ...){ 49 | templateFrame<-getBrainFrame(row_ind=row_ind, col_ind=col_ind, ...) 50 | 51 | n<-length(col_template) 52 | if(n>1) col_cut<-as.numeric(cut(templateFrame$value,n)) 53 | if(n==1) col_cut=1 54 | 55 | 56 | p<-ggplot()+facet_just_unique(row_ind,col_ind) 57 | 58 | for(i in 1:n){ 59 | if(all(col_cut!=i)) next 60 | drop_ind<-which(names(templateFrame)=='value') 61 | #so it doesn't conflict with mappings to "value" later on 62 | templateFrame_col<-templateFrame[col_cut==i,-drop_ind] 63 | p<- p + geom_tile(data=templateFrame_col,aes(x=row,y=col),fill=col_template[i]) 64 | } 65 | 66 | p 67 | } 68 | 69 | # (Now only an internal function) 70 | # For creating ggplot line objects for use with \code{\link{ggBrain}} 71 | # 72 | # \code{getLinesFrame} creates long data frames which are transformed 73 | # into line objects by code{ggLines}. \code{\link{ggBrain}} automatically 74 | # calls \code{ggLines}. Alternatively, \code{getLinesFrame} can be used 75 | # with \code{\link{getBrainFrame}} 76 | # 77 | # @param row_ind should match the vector passed to \code{\link{ggBrain}} or 78 | # \code{\link{getBrainFrame}}. 79 | # @param col_ind should match the vector passed to \code{\link{ggBrain}} or 80 | # \code{\link{getBrainFrame}}. 81 | # @param mar should match the vector passed to \code{\link{ggBrain}} or 82 | # \code{\link{getBrainFrame}}. 83 | # @param lines_mat a matrix with 3 columns, and one row for each line to 84 | # be added to the brain images. 85 | # Each row of \code{lines_mat} contains a triplet of values, with the first 86 | # element telling the panel number where the line should be placed, the second 87 | # element containing 88 | # the margin to plot over, and the second element telling the slice index 89 | # where the line should be placed. 90 | # @param dim_image the dimension of the image template to plot lines on. 91 | # @param center_coords should match the value passed to \code{\link{ggBrain}} 92 | # or \code{\link{getBrainFrame}}. 93 | # @param ... passed to \code{getLinesFrame}. 94 | # @return 95 | # \code{getLinesFrame} Returns two data frames, \code{h} and \code{v}, 96 | # which can be use with \code{\link[ggplot2]{geom_hline}} and 97 | # \code{\link[ggplot2]{geom_vline}} respectively. 98 | # @alias ggLines 99 | getLinesFrame<-function(row_ind,col_ind,mar,lines_mat,dim_image=NULL,center_coords=FALSE){ 100 | 101 | colnames(lines_mat)<-c('panel','mar','slice') 102 | 103 | long_lines<-data.frame(matrix(NA,nrow=nrow(lines_mat),ncol=4)) 104 | colnames(long_lines)<-c('row_ind','col_ind','line_int','direction') 105 | long_lines[,'row_ind']<-row_ind[lines_mat[,'panel']] 106 | long_lines[,'col_ind']<-col_ind[lines_mat[,'panel']] 107 | long_lines[,'line_int']<-lines_mat[,'slice'] 108 | 109 | if(center_coords) { 110 | long_lines[,'line_int'] <- lines_mat[,'slice'] - 111 | dim_image[lines_mat[,'mar']]/2 112 | } 113 | 114 | if(any(mar[lines_mat[,'panel']]==lines_mat[,'mar'])) { 115 | stop(paste0( 116 | "Can't add lines the same margin that the", 117 | " panel is sliced from. Adjustment is needed for lines_mat argument")) 118 | } 119 | 120 | for(i in 1:nrow(lines_mat)){ 121 | if(mar[lines_mat[i,'panel']]==1) vertical <- lines_mat[i,'mar']==2 #as opposed to 3 122 | if(mar[lines_mat[i,'panel']]==2) vertical <- lines_mat[i,'mar']==1 #as opposed to 3 123 | if(mar[lines_mat[i,'panel']]==3) vertical <- lines_mat[i,'mar']==1 #as opposed to 2 124 | long_lines[i,'direction']<-c('h','v')[vertical+1] 125 | } 126 | 127 | long_lines 128 | } 129 | ggLines<-function(color='white',...){ 130 | line_int = NULL; rm(list = "line_int") 131 | 132 | lf<-getLinesFrame(...) 133 | 134 | out_h<-geom_hline(aes(yintercept=line_int),data=lf[lf$direction=='h',],col=color) 135 | out_v<-geom_vline(aes(xintercept=line_int),data=lf[lf$direction=='v',],col=color) 136 | 137 | if(all(lf$direction!='h')) out_h<-NULL 138 | if(all(lf$direction!='v')) out_v<-NULL 139 | 140 | return(list(v=out_v,h=out_h)) 141 | } 142 | 143 | 144 | 145 | 146 | # _ _ 147 | # | | | | 148 | # _____ _| |_ ___ _ __ _ __ __ _| |___ 149 | # / _ \ \/ / __/ _ \ '__| '_ \ / _` | / __| 150 | # | __/> <| || __/ | | | | | (_| | \__ \ 151 | # \___/_/\_\\__\___|_| |_| |_|\__,_|_|___/ 152 | # 153 | # User facing functions 154 | 155 | 156 | #' Plotting brain images with ggplot 157 | #' 158 | #' \code{ggBrain} creates ggplot brain images with minimal user input. 159 | #' This function calls \code{getBrainFrame}, which generates a data frame 160 | #' for use in ggplot objects. Aesthetic changes to the resulting figures 161 | #' can be made with standard ggplot functions, such as 162 | #' \code{\link[ggplot2]{scale_fill_gradient2}}. The \code{getBrainFrame} 163 | #' function can also be directly accessed by the user, for a deeper 164 | #' control of aesthetics. 165 | #' @param brains A list of 4-D arrays of brain images, with time on the 166 | #' fourth dimension. Alternatively, a list of 3-D arrays, a single 3-D, 167 | #' or a single 4-D array can be entered. 168 | #' @param mask A 3-D binary array of which voxels in the image to plot. 169 | #' If no mask is provided, the mask is set to be all voxels not equal 170 | #' to \code{NA}. 171 | #' @param template A 3-D structural brain image over which to plot 172 | #' voxelwise statistics, such as p-values or seed correlations. 173 | #' @param mar a numeric vector. The length of this vector should be 174 | #' equal to the number of panels in the figure. The \eqn{j^{th}} 175 | #' element of \code{mar} tells which margin of the image to slice 176 | #' over, for the \eqn{j^{th}} panel (see examples). 177 | #' @param mar_ind a numeric vector of the same length as \code{mar}. 178 | #' The \eqn{j^{th}} element of \code{mar_ind} tells the slice number 179 | #' to be shown in the \eqn{j^{th}} panel. 180 | #' @param row_ind a numeric vector of the same length as \code{mar}, 181 | #' which partially determines the layout of the image plots. 182 | #' The \eqn{j^{th}} element of \code{row_ind} tells the row number 183 | #' where the \eqn{j^{th}} panel should be positioned. 184 | #' @param col_ind a numeric vector of the same length as \code{mar}, 185 | #' which partially determines the layout of the image plots. 186 | #' The \eqn{j^{th}} element of \code{row_ind} tells the column 187 | #' number where the \eqn{j^{th}} panel should be positioned. 188 | #' @param brain_ind a vector of the same length as \code{mar}. 189 | #' The \eqn{j^{th}} element of \code{brain_ind} tells the index 190 | #' number of the appropriate brain image to be plotted in the 191 | #' \eqn{j^{th}} panel, from the list \code{brains}. 192 | #' @param time a vector of the same length as \code{mar}, used for 193 | #' plotting snapshots of 4-D fMRI data over time. The \eqn{j^{th}} 194 | #' element of \code{time} tells the time index to be used for the 195 | #' \eqn{j^{th}} panel. 196 | #' @param col_template a vector of colors to be used for displaying 197 | #' the template brain image. 198 | #' @param type the type of brain image to be shown, either 'signed', 199 | #' 'positive', 200 | #' 'binary' or 'structural'. These types should be used when the objects in 201 | #' \code{brains} are, respectively, images of voxelwise statistics that can be 202 | #' positive or negative (e.g. seed correlations); images of voxelwise 203 | #' statistics that are all positive (e.g. p-values); binary masks to 204 | #' be shown on top of tempaltes; or structural brain images that 205 | #' do not contain voxelwise statistics. When setting 206 | #' \code{type='structural'} there is no need to input a template brain image. 207 | #' @param binary_color the color to be used for plotting either binary masks or 208 | #' voxelwise, positive statistics (e.g. p-values). This argument will be used 209 | #' when \code{type} is set to either 'positive' or 'binary'. The color 210 | #' of 'signed' type figures can be changed using the standard ggplot 211 | #' functions for \code{fill} (see \code{\link[ggplot2]{scale_fill_gradient2}}). 212 | #' @param combine_legend when \code{type} is set to \code{'signed'}, the default 213 | #' approach \code{ggBrain} takes is to map absolute value of the voxelwise 214 | #' statistic to alpha blending, and sign of the voxelwise statistic to fill. 215 | #' This results in two separate legends. When the \code{combine_legend} 216 | #' is set to TRUE, \code{ggBrain} creates a new custom scale that combines 217 | #' both binary coloring for sign, and gradual alpha blending for absolute 218 | #' value. Each voxel is binned according to it's value. The legend 219 | #' created shows the upper bounds for each bin. This argument is only 220 | #' used when \code{type} is set to \code{'signed'}. 221 | #' @param breaks_legend the number of bins to use in creating a combined legend. 222 | #' This is only used when \code{combine_legend} is set to \code{TRUE}. 223 | #' @param digits_legend the number of digits to be used in the combined 224 | #' legend for 'signed' plots. This is only used when \code{combine_legend} 225 | #' is set to \code{TRUE}. 226 | #' @param signed_colors a vector of length two, with entries corresponding 227 | #' to the colors for negative and positive values of the overlaying 228 | #' voxelwise statistic. This argument is only used when \code{type} 229 | #' is set to \code{'signed'}. 230 | #' @param fix_ratio whether the aspect ratio should be fixed, to avoid 231 | #' warping of images. 232 | #' @param tri_planar a special mode for simultaneously plotting saggital, 233 | #' transverse, and coronal brain slices. If set to TRUE, a cross-hair will 234 | #' be plotted to show correspondance between these images (see examples). 235 | #' @param lines_color color of the lines defined by \code{lines_mat}, or 236 | #' the lines defined by using \code{tri_planar=TRUE}. 237 | #' @param center_coords whether the brains should be centered. If TRUE, 238 | #' axis tick marks will not be shown. If FALSE, axis tick marks will 239 | #' correspond to slice number 240 | #' @param all_brain_and_time_inds_one a parameter specific to 241 | #' \code{getBrainFrame}, which can generally be ignored by the user. This 242 | #' arguments helps \code{getBrainFrame} be called from different contexts 243 | #' within \code{ggBrain}, particularly when contructing ggplot objects for 244 | #' the template brain. If set to \code{TRUE}, all elements of \code{brain_ind} 245 | #' and \code{time} will be forced to equal 1. 246 | #' @param lines_mat a matrix with 3 columns, and one row for each line to be 247 | #' added to the figure. Each row of \code{lines_mat} contains a triplet of 248 | #' values, with the first element telling which panel the line should be 249 | #' placed in, the second element containing the margin to plot over, and 250 | #' the third element telling the slice index where the line should be 251 | #' placed. If \code{NULL}, no lines will be plotted. 252 | #' @param ... Parameters passed from \code{ggBrain} to \code{getBrainFrame}, 253 | #' such as \code{time} and \code{brain_ind}. 254 | #' 255 | #' 256 | #' @export 257 | #' @import ggplot2 RColorBrewer 258 | #' @return 259 | #' \code{ggBrain} returns a ggplot object showing the desired brain images. 260 | #' Further aesthetic changes to the plotting can be added to this ggplot 261 | #' object using the usual ggplot notation (see examples). \code{getBrainFrame} 262 | #' outputs a "long" dataframe which can be used in ggplot objects. 263 | #' Accessing this dataframe directly allows the users to have more 264 | #' control over the plotting procedure hard-coded by \code{ggBrain}. 265 | #' @aliases getBrainFrame 266 | #' @examples 267 | #' \dontrun{ 268 | #' 269 | #' 270 | #' ##################### 271 | #' # Load data 272 | #' ##################### 273 | #' 274 | #' library(oro.nifti) 275 | #' 276 | #' s_map1<-readNIfTI(system.file('seed_corr_1.nii.gz', package='ggBrain')) 277 | #' s_map2<-readNIfTI(system.file('seed_corr_2.nii.gz', package='ggBrain')) 278 | #' template <- readNIfTI(system.file('template.nii.gz', package='ggBrain')) 279 | #' mask <- readNIfTI(system.file('brain_mask.nii.gz', package='ggBrain')) 280 | #' seed_mask <- readNIfTI(system.file('seed_mask.nii.gz', package='ggBrain')) 281 | #' nii1_trunc <- readNIfTI(system.file('subj_trunc_1.nii.gz', package='ggBrain')) 282 | #' 283 | #' 284 | #' library(brainR) 285 | #' 286 | #' hd_template <- readNIfTI(system.file("MNI152_T1_1mm_brain.nii.gz", package="brainR")) 287 | #' 288 | #' 289 | #' 290 | #' 291 | #' 292 | #' ##################### 293 | #' # Generate plots 294 | #' ##################### 295 | #' 296 | #' library(ggplot2) 297 | #' 298 | #' ############### 299 | #' # Simple examples, just one plot 300 | #' 301 | #' # structural image (type = 'structural') 302 | #' dd<-ggBrain(brains=hd_template,mask=hd_template>0,mar=3, 303 | #' mar_ind=93,type='structural') 304 | #' dd 305 | #' #now add aethetic changes with conventional ggplot code. 306 | #' dd + scale_fill_continuous(low="black", high="white")+ theme_black_bg() 307 | #' 308 | #' # seed correlation (type = 'signed') 309 | #' dd<-ggBrain(template=template,brains=s_map1,mask=mask,mar=3, 310 | #' mar_ind=30,type='signed') 311 | #' dd 312 | #' 313 | #' # positive voxelwise statistics (type='positive'). 314 | #' # Here we use absolute value of seed correlation, 315 | #' # but a p-value map might also be applied. 316 | #' dd<-ggBrain(template=template,brains=abs(s_map1),mask=mask, 317 | #' mar=3,mar_ind=30,type='positive') 318 | #' dd + theme_black_bg() + scale_alpha(range=c(0,1)) 319 | #' #note, for type='signed', a scale is already included 320 | #' 321 | #' # Further customization can be done by using 322 | #' # getBrainFrame directly 323 | #' bf<-getBrainFrame(brains=hd_template,mar=3,mar_ind=93, 324 | #' mask=hd_template>0,center_coords=FALSE) 325 | #' ggplot() + 326 | #' geom_tile(data=bf, aes(x=row,y=col,fill=value)) + 327 | #' facet_grid(row_ind~col_ind)+ 328 | #' theme_black_bg()+labs(x='',y='')+coord_fixed(ratio = 1) 329 | #' 330 | #' 331 | #' # tri_planar basic example, cross-hairs show correspondence across plots 332 | #' dd<-ggBrain(brains=s_map1,template=template, 333 | #' mar = c(1,2,3), 334 | #' mar_ind = c(37,18,30), 335 | #' row_ind= c(1,1,2), 336 | #' col_ind= c(2,1,1), 337 | #' tri_planar=TRUE, lines_color='black',mask=mask) 338 | #' dd + theme_bw() +theme_no_ticks() 339 | #' 340 | #' 341 | #' ################### 342 | #' # use grid.arrange to show the seed mask and the 343 | #' # seed correlation. 344 | #' # Since these are on different scales, we use 345 | #' # grid.arrange to show them separately. 346 | #' mar = c(1,2,3) 347 | #' col_ind = factor(c(1,2,3),labels=c('Saggital','Coronal','Transverse')) 348 | #' row_ind = c(1,1,1) 349 | #' mar_ind= c(37,18,30) 350 | #' 351 | #' dd_mask<-ggBrain(brains=seed_mask,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind, 352 | #' col_ind=col_ind,type='binary',binary_color='black',tri_planar=TRUE,mask=mask)+ 353 | #' labs(alpha='Seed mask')+theme_black_bg() 354 | #' 355 | #' 356 | #' dd_1<-ggBrain(brains=s_map1,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind, 357 | #' col_ind=col_ind,tri_planar=TRUE,mask=mask) + theme_black_bg() 358 | #' 359 | #' library(gridExtra) 360 | #' grid.arrange(dd_mask,dd_1) 361 | #' 362 | #' 363 | #' # We can also show two seed correlation maps 364 | #' # from two different subjects. Note, these maps 365 | #' # are on the same scale, as correlations are 366 | #' # standardized 367 | #' dd<-ggBrain(brains=list(s_map1,s_map2), 368 | #' brain_ind=c(1,1,1,2,2,2), 369 | #' template=template, 370 | #' mar=c(1,2,3,1,2,3), 371 | #' mar_ind=c(37,18,30,37,18,30), 372 | #' row_ind=c('Subject 1','Subject 1','Subject 1','Subject 2','Subject 2','Subject 2'), 373 | #' col_ind=factor(c(1,2,3,1,2,3),labels=c('Saggital','Coronal','Transverse')), 374 | #' mask=mask) 375 | #' dd + ggtitle('Seed correlations for two subjects')+ theme_black_bg() 376 | #' 377 | #' 378 | #' 379 | #' ################### 380 | #' # row_ind and col_ind can be used to look at 381 | #' # several slices 382 | #' 383 | #' # instead of inputting the mask directly, we 384 | #' # can set the masked out voxels to NA 385 | #' hd_template_masked<-hd_template 386 | #' hd_template_masked[hd_template_masked==0]<-NA 387 | #' 388 | #' dd<-ggBrain(brains=hd_template_masked, 389 | #' mar=rep(3,8), 390 | #' mar_ind=floor(seq(140,50,length=8)), 391 | #' col_ind=c(1,1,1,1,2,2,2,2), 392 | #' row_ind=c(1,2,3,4,1,2,3,4), 393 | #' type='structural') 394 | #' dd+ theme_black_bg() 395 | #' 396 | #' 397 | #' 398 | #' # We can also add a key to the above type of plot, 399 | #' # using the lines_mat argument 400 | #' mar=c(3,3,3,3,3,3,3,1) 401 | #' mar_ind=c(floor(seq(140,50,length=7)),88) 402 | #' col_ind=c(1,1,1,1,2,2,2,2) 403 | #' row_ind=c(1,2,3,4,1,2,3,4) 404 | #' lines_mat<-cbind(8,mar,mar_ind)[1:7,] 405 | #' 406 | #' dd<-ggBrain(brains=hd_template,mar=mar,mar_ind=mar_ind,row_ind=row_ind,col_ind=col_ind, 407 | #' mask=hd_template>0,type='structural',lines_mat=lines_mat) 408 | #' 409 | #' 410 | #' dd+ theme_black_bg() 411 | #' 412 | #' 413 | #' 414 | #' # The same type of plots can be made for 415 | #' # seed correlations 416 | #' mar_ind=c(floor(seq(50,20,length=7)),30) #reduce dimensions 417 | #' # to match fMRI data 418 | #' 419 | #' lines_mat<-cbind(8,mar,mar_ind)[1:7,] 420 | #' 421 | #' dd<-ggBrain(brains=s_map1,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind, 422 | #' col_ind=col_ind,mask=mask,lines_mat=lines_mat) 423 | #' 424 | #' dd + theme_black_bg() 425 | #' 426 | #' 427 | #' 428 | #' # We can also plot fMRI activation over time 429 | #' dd<-ggBrain(brains=nii1_trunc,template=template, 430 | #' mask=mask, 431 | #' mar=rep(3,4), 432 | #' mar_ind=rep(30,4), 433 | #' row_ind=rep(1,4), 434 | #' col_ind=paste('time',1:4), 435 | #' time=1:4) 436 | #' dd + theme_black_bg() 437 | #' 438 | #' # Note, to change legend labels for figures of type='signed', 439 | #' # we must change both the label for fill and for alpha, 440 | #' # as ggBrain combines these two aesthetics into a custom, 441 | #' # hardcoded legend (when combine_legend=TRUE). If separate 442 | #' # labels are given for fill and alpha, the two aesthetic dimensions 443 | #' # will appear in separate legends. 444 | #' # For example: 445 | #' dd <- ggBrain(template=template,brains=s_map1, 446 | #' mask=mask,mar=3,mar_ind=30,type='signed') 447 | #' # ex1: 448 | #' dd + labs(fill='new_label',alpha='new_label') 449 | #' # ex2: 450 | #' dd + labs(fill='sign',alpha='abs_value') 451 | #' } 452 | ggBrain <- function( 453 | brains, 454 | template = NULL, 455 | mar = 1, 456 | mar_ind, 457 | row_ind = rep(1, length(mar_ind)), 458 | col_ind = rep(1, length(mar_ind)), 459 | col_template = rev(brewer.pal(8, 'Greys')), 460 | type = 'signed', 461 | binary_color = 'darkred', 462 | combine_legend = TRUE, 463 | breaks_legend = 8, 464 | digits_legend = 2, 465 | signed_colors = brewer.pal(9, 'RdYlBu')[c(1, 9)], 466 | fix_ratio = TRUE, 467 | tri_planar = FALSE, 468 | lines_color = 'white', 469 | center_coords = TRUE, 470 | lines_mat = NULL, 471 | ...) { 472 | Value = NULL; rm(list = "Value") 473 | value = NULL; rm(list = "value") 474 | 475 | if(class(brains)!='list') brains<-list(brains) 476 | #also in getBrainFrame, but we need it here too. 477 | 478 | keyLines<- 479 | strip_axis_labels<- 480 | fix_ratio_gg<- 481 | 482 | if(fix_ratio){ 483 | fix_ratio_gg <- coord_fixed(ratio = 1) 484 | } 485 | 486 | if(center_coords) strip_axis_labels<-theme_no_ticks() 487 | 488 | if(tri_planar){ 489 | if(length(mar)!=3) stop('tri_planar only works for 3 images at once') 490 | if(length(unique(mar))<3) stop('mar must contain three unique margins') 491 | 492 | #don't center points here, centering will be handled by ggLines 493 | cp<-mar_ind[mar] #central point 494 | 495 | lines_mat<-matrix(NA,6,3) 496 | colnames(lines_mat)<-c('panel','mar','slice') 497 | #need all 3x2 orderings of panel, and margin to plot a line on. 498 | lines_mat[1,]<-c(1,mar[3],cp[3]) 499 | lines_mat[2,]<-c(1,mar[2],cp[2]) 500 | lines_mat[3,]<-c(2,mar[3],cp[3]) 501 | lines_mat[4,]<-c(2,mar[1],cp[1]) 502 | lines_mat[5,]<-c(3,mar[2],cp[2]) 503 | lines_mat[6,]<-c(3,mar[1],cp[1]) 504 | } 505 | 506 | if(!is.null(lines_mat)){ 507 | keyLines<-ggLines(row_ind=row_ind,col_ind=col_ind,mar=mar, 508 | lines_mat=lines_mat,dim_image=dim(brains[[1]])[1:3], 509 | center_coords=TRUE,color=lines_color) 510 | } 511 | 512 | 513 | 514 | if(type=='structural'){ 515 | bf<-getBrainFrame(brains=brains, mar=mar,mar_ind=mar_ind,row_ind=row_ind, 516 | col_ind=col_ind,center_coords=center_coords,...) 517 | out<-ggplot()+geom_tile(data=bf, aes(x=row,y=col,fill=value))+facet_just_unique(row_ind,col_ind) 518 | return(out+labs(x='',y='')+fix_ratio_gg+strip_axis_labels+keyLines$v+keyLines$h) 519 | } 520 | #if no template, plot on a white background 521 | if(is.null(template)){ 522 | template<-is.na(brains[[1]]) 523 | col_template='white' 524 | } 525 | #get background colors 526 | ggTemplate<-getggTemplate(col_template=col_template,brains=template, 527 | all_brain_and_time_inds_one=TRUE, 528 | mar=mar,mar_ind=mar_ind,row_ind=row_ind, 529 | col_ind=col_ind,center_coords=center_coords,...) 530 | #get brain long data matrix 531 | brainFrame<-getBrainFrame( 532 | brains=brains,mar=mar,mar_ind=mar_ind, 533 | row_ind=row_ind,col_ind=col_ind,center_coords=center_coords,...) 534 | #plot values to colors or alpha 535 | if(type=='signed'){ 536 | if(combine_legend){ 537 | names(brainFrame)[names(brainFrame)=='value']<-'value_raw' 538 | seqVal<-seq(min(brainFrame$value_raw),max(brainFrame$value_raw),length=breaks_legend+1) 539 | brainFrame$Value<-cut(brainFrame$value_raw, breaks=seqVal,include.lowest=TRUE) 540 | levels(brainFrame$Value)<-signif(seqVal[-1],digits=digits_legend) 541 | #Display upper bounds for bins. If we round with signif before this step, 542 | # we can get NAs if the max is larger than the rounded down max. 543 | seqCol<-signed_colors[(seqVal>0)+1]#binary colors, varied alpha 544 | out <-ggTemplate + 545 | geom_tile(data=brainFrame, aes(x=row,y=col,fill=Value,alpha=Value)) + 546 | scale_alpha_manual(values=abs(seqVal[-1])/max(abs(seqVal))) + 547 | scale_fill_manual(values=seqCol[-1]) 548 | } 549 | if(!combine_legend) 550 | out<-ggTemplate + geom_tile(data=brainFrame, 551 | aes(x=row,y=col, 552 | fill=as.factor(sign_no_zero(value)), 553 | alpha=abs(value))) 554 | } 555 | if(type=='positive'){ 556 | out<-ggTemplate + geom_tile(data=brainFrame, 557 | aes(x=row,y=col,alpha=value),fill=binary_color) 558 | } 559 | if(type=='binary'){ 560 | out<-ggTemplate+geom_tile(data=brainFrame, 561 | aes(x=row,y=col,alpha=as.factor(value)), 562 | fill=binary_color) 563 | } 564 | 565 | return(out + labs(x = '', y = '') + fix_ratio_gg + strip_axis_labels + keyLines$v + 566 | keyLines$h) 567 | } 568 | 569 | #' Get binary sign of a variable, or array 570 | #' 571 | #' @param x a vector or array 572 | #' @export 573 | #' @seealso \code{\link{sign}} 574 | #' @return a vector or array telling if each element of x is 575 | #' greater than or equal to zero. This array will be of the same 576 | #' dimension as \code{x}, but with elements -1 for negative values of 577 | #' \code{x}, and elements +1 for positive values of \code{x} 578 | #' @examples 579 | #' sign_no_zero(-2:2) #returns -1 -1 1 1 1 580 | sign_no_zero<-function(x){ 581 | x[x>=0]<- 1 582 | x[x< 0]<- -1 583 | return(x) 584 | } 585 | 586 | #' @rdname ggBrain 587 | #' @export 588 | getBrainFrame <- function( 589 | brains, 590 | mask = NULL, 591 | mar = 1, 592 | mar_ind, 593 | row_ind = rep(1, length(mar_ind)), 594 | col_ind = rep(1, length(mar_ind)), 595 | brain_ind = rep(1, length(mar_ind)), 596 | all_brain_and_time_inds_one = FALSE, 597 | time = rep(1, length(mar_ind)), 598 | center_coords = FALSE) { 599 | 600 | if(length(unique( length(row_ind),length(col_ind),length(mar), 601 | length(mar_ind), length(brain_ind),length(time) ))>1) { 602 | stop(paste0('row_ind, col_ind, mar, mar_ind, brain_ind, and time', 603 | ' arguments must all be of the same length.')) 604 | } 605 | 606 | row_ind<-as.factor(row_ind) 607 | col_ind<-as.factor(col_ind) 608 | 609 | out<-c() 610 | if(class(brains)!='list') brains<-list(brains) 611 | if(all_brain_and_time_inds_one){ 612 | brain_ind<- 613 | time<-rep(1,length(mar_ind)) 614 | } 615 | for(i in 1:length(brains)) if(length(dim(brains[[i]]))==3) 616 | brains[[i]]<- array(brains[[i]],dim=c(dim(brains[[i]]),1)) 617 | 618 | if(is.null(mask)) mask<- !is.na(brains[[1]][,,,1]) 619 | 620 | 621 | # have to make it a data frame asap so you can add row_ind as 622 | # a factor or string, and have it not turn the whole array into 623 | # strings which eventually become all factors and unplottable. 624 | for(i in 1:length(mar)){ 625 | t_i<-data.frame(array2long(brains[[brain_ind[i] ]], 626 | mask,mar[i],mar_ind[i],time=time[i], 627 | center_coords=center_coords)) 628 | t_i_lab<-cbind(t_i,'row_ind'=row_ind[i],'col_ind'=col_ind[i]) 629 | out<-rbind(out,t_i_lab) 630 | } 631 | 632 | out 633 | } 634 | 635 | 636 | #' Possible theme settings for brain image plots 637 | #' 638 | #' \code{theme_black_bg} makes the background of the image black, 639 | #' \code{theme_no_ticks} removes tick marks from the axes, 640 | #' \code{theme_all_blank} removes additional aesthetic labels 641 | #' from the ggplot image, 642 | #' @export 643 | #' @return 644 | #' ggplot theme objects 645 | #' @aliases theme_all_blank theme_no_ticks 646 | #' @examples \dontrun{ 647 | #' library(oro.nifti) 648 | #' library(ggplot2) 649 | #' 650 | #' s_map1<-readNIfTI(system.file('seed_corr_1.nii.gz', package='ggBrain')) 651 | #' template <- readNIfTI(system.file('template.nii.gz', package='ggBrain')) 652 | #' 653 | #' dd<-ggBrain(brains=template,mask=template>0, 654 | #' mar=c(3,3),mar_ind=c(30,40),col_ind=c(1,2), 655 | #' type='structural',center_coords=FALSE)+ 656 | #' scale_fill_continuous(low="black", high="white") 657 | #' 658 | #' #without theme settings 659 | #' dd 660 | #' 661 | #' #with theme settings 662 | #' dd + theme_black_bg() 663 | #' dd + theme_black_bg() + theme_no_ticks() 664 | #' dd + theme_black_bg() + theme_all_blank() 665 | #'} 666 | theme_black_bg<-function() { 667 | theme(panel.background = element_rect(fill = "black"), 668 | panel.grid.major = element_blank(),panel.grid.minor = element_blank()) 669 | } 670 | 671 | #' @rdname theme_black_bg 672 | #' @export 673 | theme_all_blank<-function() { 674 | theme( 675 | strip.background = element_blank(), 676 | strip.text.x = element_blank(), 677 | strip.text.y = element_blank(),axis.ticks = element_blank(), 678 | axis.text=element_blank()) 679 | } 680 | 681 | #' @rdname theme_black_bg 682 | #' @export 683 | theme_no_ticks<-function() { 684 | theme(axis.ticks = element_blank(),axis.text=element_blank()) 685 | } 686 | 687 | 688 | 689 | 690 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ggBrain 2 | ======== 3 | [![Build Status](https://travis-ci.org/aaronjfisher/ggBrain.png?branch=master)](https://travis-ci.org/aaronjfisher/ggBrain) 4 | [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/aaronjfisher/ggBrain?branch=master&svg=true)](https://ci.appveyor.com/project/aaronjfisher/ggBrain) 5 | 6 | `muschellij2` badges: 7 | [![Build Status](https://travis-ci.org/muschellij2/ggBrain.png?branch=master)](https://travis-ci.org/muschellij2/ggBrain) 8 | [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/muschellij2/ggBrain?branch=master&svg=true)](https://ci.appveyor.com/project/muschellij2/ggBrain) 9 | 10 | An R package of simple helper functions for creating brain image figures with ggplot. The primary workhorse function is `ggBrain`, which is documented in the vignette. Some of the images generated in the vignette are shown below. 11 | 12 | 13 | ### To install 14 | ```r 15 | ## if needed 16 | install.packages("devtools") 17 | 18 | ## main package 19 | library(devtools) 20 | install_github('aaronjfisher/ggBrain',build_vignettes=TRUE) 21 | 22 | ## to access help pages 23 | library(ggBrain) 24 | help(package=ggBrain) 25 | ``` 26 | 27 | 28 | ### Sample images from vignette 29 | 30 | #### Structural images 31 | 32 | 33 | #### Comparing seed maps across two subjects 34 | 35 | 36 | #### Tri-planar cross-hairs 37 | 38 | 39 | #### Basic, single panel figures 40 | 41 | 42 | 43 | 44 | 45 |

46 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | # Adapt as necessary starting from here 17 | environment: 18 | global: 19 | WARNINGS_ARE_ERRORS: 1 20 | USE_RTOOLS: yes 21 | R_CHECK_INSTALL_ARGS: --install-args=--build --no-multiarch 22 | 23 | build_script: 24 | - travis-tool.sh install_deps 25 | 26 | test_script: 27 | - travis-tool.sh run_tests 28 | 29 | on_failure: 30 | - cat *.Rcheck/00install.out 31 | - 7z a failure.zip *.Rcheck\* 32 | - appveyor PushArtifact failure.zip 33 | 34 | artifacts: 35 | - path: '*.Rcheck\**\*.log' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.out' 39 | name: Logs 40 | 41 | - path: '*.Rcheck\**\*.fail' 42 | name: Logs 43 | 44 | - path: '*.Rcheck\**\*.Rout' 45 | name: Logs 46 | 47 | - path: '\*_*.zip' 48 | name: Bits 49 | -------------------------------------------------------------------------------- /ggBrain.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | 17 | BuildType: Package 18 | PackageUseDevtools: Yes 19 | PackageInstallArgs: --no-multiarch --with-keep.source 20 | PackageCheckArgs: --as-cran 21 | PackageRoxygenize: rd,collate,namespace,vignette 22 | -------------------------------------------------------------------------------- /inst/brain_mask.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/inst/brain_mask.nii.gz -------------------------------------------------------------------------------- /inst/seed_corr_1.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/inst/seed_corr_1.nii.gz -------------------------------------------------------------------------------- /inst/seed_corr_2.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/inst/seed_corr_2.nii.gz -------------------------------------------------------------------------------- /inst/seed_mask.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/inst/seed_mask.nii.gz -------------------------------------------------------------------------------- /inst/subj_trunc_1.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/inst/subj_trunc_1.nii.gz -------------------------------------------------------------------------------- /inst/template.nii.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/inst/template.nii.gz -------------------------------------------------------------------------------- /man/ggBrain.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ggBrainCode.r 3 | \name{ggBrain} 4 | \alias{ggBrain} 5 | \alias{getBrainFrame} 6 | \title{Plotting brain images with ggplot} 7 | \usage{ 8 | ggBrain(brains, template = NULL, mar = 1, mar_ind, row_ind = rep(1, 9 | length(mar_ind)), col_ind = rep(1, length(mar_ind)), 10 | col_template = rev(brewer.pal(8, "Greys")), type = "signed", 11 | binary_color = "darkred", combine_legend = TRUE, breaks_legend = 8, 12 | digits_legend = 2, signed_colors = brewer.pal(9, "RdYlBu")[c(1, 9)], 13 | fix_ratio = TRUE, tri_planar = FALSE, lines_color = "white", 14 | center_coords = TRUE, lines_mat = NULL, ...) 15 | 16 | getBrainFrame(brains, mask = NULL, mar = 1, mar_ind, row_ind = rep(1, 17 | length(mar_ind)), col_ind = rep(1, length(mar_ind)), brain_ind = rep(1, 18 | length(mar_ind)), all_brain_and_time_inds_one = FALSE, time = rep(1, 19 | length(mar_ind)), center_coords = FALSE) 20 | } 21 | \arguments{ 22 | \item{brains}{A list of 4-D arrays of brain images, with time on the 23 | fourth dimension. Alternatively, a list of 3-D arrays, a single 3-D, 24 | or a single 4-D array can be entered.} 25 | 26 | \item{template}{A 3-D structural brain image over which to plot 27 | voxelwise statistics, such as p-values or seed correlations.} 28 | 29 | \item{mar}{a numeric vector. The length of this vector should be 30 | equal to the number of panels in the figure. The \eqn{j^{th}} 31 | element of \code{mar} tells which margin of the image to slice 32 | over, for the \eqn{j^{th}} panel (see examples).} 33 | 34 | \item{mar_ind}{a numeric vector of the same length as \code{mar}. 35 | The \eqn{j^{th}} element of \code{mar_ind} tells the slice number 36 | to be shown in the \eqn{j^{th}} panel.} 37 | 38 | \item{row_ind}{a numeric vector of the same length as \code{mar}, 39 | which partially determines the layout of the image plots. 40 | The \eqn{j^{th}} element of \code{row_ind} tells the row number 41 | where the \eqn{j^{th}} panel should be positioned.} 42 | 43 | \item{col_ind}{a numeric vector of the same length as \code{mar}, 44 | which partially determines the layout of the image plots. 45 | The \eqn{j^{th}} element of \code{row_ind} tells the column 46 | number where the \eqn{j^{th}} panel should be positioned.} 47 | 48 | \item{col_template}{a vector of colors to be used for displaying 49 | the template brain image.} 50 | 51 | \item{type}{the type of brain image to be shown, either 'signed', 52 | 'positive', 53 | 'binary' or 'structural'. These types should be used when the objects in 54 | \code{brains} are, respectively, images of voxelwise statistics that can be 55 | positive or negative (e.g. seed correlations); images of voxelwise 56 | statistics that are all positive (e.g. p-values); binary masks to 57 | be shown on top of tempaltes; or structural brain images that 58 | do not contain voxelwise statistics. When setting 59 | \code{type='structural'} there is no need to input a template brain image.} 60 | 61 | \item{binary_color}{the color to be used for plotting either binary masks or 62 | voxelwise, positive statistics (e.g. p-values). This argument will be used 63 | when \code{type} is set to either 'positive' or 'binary'. The color 64 | of 'signed' type figures can be changed using the standard ggplot 65 | functions for \code{fill} (see \code{\link[ggplot2]{scale_fill_gradient2}}).} 66 | 67 | \item{combine_legend}{when \code{type} is set to \code{'signed'}, the default 68 | approach \code{ggBrain} takes is to map absolute value of the voxelwise 69 | statistic to alpha blending, and sign of the voxelwise statistic to fill. 70 | This results in two separate legends. When the \code{combine_legend} 71 | is set to TRUE, \code{ggBrain} creates a new custom scale that combines 72 | both binary coloring for sign, and gradual alpha blending for absolute 73 | value. Each voxel is binned according to it's value. The legend 74 | created shows the upper bounds for each bin. This argument is only 75 | used when \code{type} is set to \code{'signed'}.} 76 | 77 | \item{breaks_legend}{the number of bins to use in creating a combined legend. 78 | This is only used when \code{combine_legend} is set to \code{TRUE}.} 79 | 80 | \item{digits_legend}{the number of digits to be used in the combined 81 | legend for 'signed' plots. This is only used when \code{combine_legend} 82 | is set to \code{TRUE}.} 83 | 84 | \item{signed_colors}{a vector of length two, with entries corresponding 85 | to the colors for negative and positive values of the overlaying 86 | voxelwise statistic. This argument is only used when \code{type} 87 | is set to \code{'signed'}.} 88 | 89 | \item{fix_ratio}{whether the aspect ratio should be fixed, to avoid 90 | warping of images.} 91 | 92 | \item{tri_planar}{a special mode for simultaneously plotting saggital, 93 | transverse, and coronal brain slices. If set to TRUE, a cross-hair will 94 | be plotted to show correspondance between these images (see examples).} 95 | 96 | \item{lines_color}{color of the lines defined by \code{lines_mat}, or 97 | the lines defined by using \code{tri_planar=TRUE}.} 98 | 99 | \item{center_coords}{whether the brains should be centered. If TRUE, 100 | axis tick marks will not be shown. If FALSE, axis tick marks will 101 | correspond to slice number} 102 | 103 | \item{lines_mat}{a matrix with 3 columns, and one row for each line to be 104 | added to the figure. Each row of \code{lines_mat} contains a triplet of 105 | values, with the first element telling which panel the line should be 106 | placed in, the second element containing the margin to plot over, and 107 | the third element telling the slice index where the line should be 108 | placed. If \code{NULL}, no lines will be plotted.} 109 | 110 | \item{...}{Parameters passed from \code{ggBrain} to \code{getBrainFrame}, 111 | such as \code{time} and \code{brain_ind}.} 112 | 113 | \item{mask}{A 3-D binary array of which voxels in the image to plot. 114 | If no mask is provided, the mask is set to be all voxels not equal 115 | to \code{NA}.} 116 | 117 | \item{brain_ind}{a vector of the same length as \code{mar}. 118 | The \eqn{j^{th}} element of \code{brain_ind} tells the index 119 | number of the appropriate brain image to be plotted in the 120 | \eqn{j^{th}} panel, from the list \code{brains}.} 121 | 122 | \item{all_brain_and_time_inds_one}{a parameter specific to 123 | \code{getBrainFrame}, which can generally be ignored by the user. This 124 | arguments helps \code{getBrainFrame} be called from different contexts 125 | within \code{ggBrain}, particularly when contructing ggplot objects for 126 | the template brain. If set to \code{TRUE}, all elements of \code{brain_ind} 127 | and \code{time} will be forced to equal 1.} 128 | 129 | \item{time}{a vector of the same length as \code{mar}, used for 130 | plotting snapshots of 4-D fMRI data over time. The \eqn{j^{th}} 131 | element of \code{time} tells the time index to be used for the 132 | \eqn{j^{th}} panel.} 133 | } 134 | \value{ 135 | \code{ggBrain} returns a ggplot object showing the desired brain images. 136 | Further aesthetic changes to the plotting can be added to this ggplot 137 | object using the usual ggplot notation (see examples). \code{getBrainFrame} 138 | outputs a "long" dataframe which can be used in ggplot objects. 139 | Accessing this dataframe directly allows the users to have more 140 | control over the plotting procedure hard-coded by \code{ggBrain}. 141 | } 142 | \description{ 143 | \code{ggBrain} creates ggplot brain images with minimal user input. 144 | This function calls \code{getBrainFrame}, which generates a data frame 145 | for use in ggplot objects. Aesthetic changes to the resulting figures 146 | can be made with standard ggplot functions, such as 147 | \code{\link[ggplot2]{scale_fill_gradient2}}. The \code{getBrainFrame} 148 | function can also be directly accessed by the user, for a deeper 149 | control of aesthetics. 150 | } 151 | \examples{ 152 | \dontrun{ 153 | 154 | 155 | ##################### 156 | # Load data 157 | ##################### 158 | 159 | library(oro.nifti) 160 | 161 | s_map1<-readNIfTI(system.file('seed_corr_1.nii.gz', package='ggBrain')) 162 | s_map2<-readNIfTI(system.file('seed_corr_2.nii.gz', package='ggBrain')) 163 | template <- readNIfTI(system.file('template.nii.gz', package='ggBrain')) 164 | mask <- readNIfTI(system.file('brain_mask.nii.gz', package='ggBrain')) 165 | seed_mask <- readNIfTI(system.file('seed_mask.nii.gz', package='ggBrain')) 166 | nii1_trunc <- readNIfTI(system.file('subj_trunc_1.nii.gz', package='ggBrain')) 167 | 168 | 169 | library(brainR) 170 | 171 | hd_template <- readNIfTI(system.file("MNI152_T1_1mm_brain.nii.gz", package="brainR")) 172 | 173 | 174 | 175 | 176 | 177 | ##################### 178 | # Generate plots 179 | ##################### 180 | 181 | library(ggplot2) 182 | 183 | ############### 184 | # Simple examples, just one plot 185 | 186 | # structural image (type = 'structural') 187 | dd<-ggBrain(brains=hd_template,mask=hd_template>0,mar=3, 188 | mar_ind=93,type='structural') 189 | dd 190 | #now add aethetic changes with conventional ggplot code. 191 | dd + scale_fill_continuous(low="black", high="white")+ theme_black_bg() 192 | 193 | # seed correlation (type = 'signed') 194 | dd<-ggBrain(template=template,brains=s_map1,mask=mask,mar=3, 195 | mar_ind=30,type='signed') 196 | dd 197 | 198 | # positive voxelwise statistics (type='positive'). 199 | # Here we use absolute value of seed correlation, 200 | # but a p-value map might also be applied. 201 | dd<-ggBrain(template=template,brains=abs(s_map1),mask=mask, 202 | mar=3,mar_ind=30,type='positive') 203 | dd + theme_black_bg() + scale_alpha(range=c(0,1)) 204 | #note, for type='signed', a scale is already included 205 | 206 | # Further customization can be done by using 207 | # getBrainFrame directly 208 | bf<-getBrainFrame(brains=hd_template,mar=3,mar_ind=93, 209 | mask=hd_template>0,center_coords=FALSE) 210 | ggplot() + 211 | geom_tile(data=bf, aes(x=row,y=col,fill=value)) + 212 | facet_grid(row_ind~col_ind)+ 213 | theme_black_bg()+labs(x='',y='')+coord_fixed(ratio = 1) 214 | 215 | 216 | # tri_planar basic example, cross-hairs show correspondence across plots 217 | dd<-ggBrain(brains=s_map1,template=template, 218 | mar = c(1,2,3), 219 | mar_ind = c(37,18,30), 220 | row_ind= c(1,1,2), 221 | col_ind= c(2,1,1), 222 | tri_planar=TRUE, lines_color='black',mask=mask) 223 | dd + theme_bw() +theme_no_ticks() 224 | 225 | 226 | ################### 227 | # use grid.arrange to show the seed mask and the 228 | # seed correlation. 229 | # Since these are on different scales, we use 230 | # grid.arrange to show them separately. 231 | mar = c(1,2,3) 232 | col_ind = factor(c(1,2,3),labels=c('Saggital','Coronal','Transverse')) 233 | row_ind = c(1,1,1) 234 | mar_ind= c(37,18,30) 235 | 236 | dd_mask<-ggBrain(brains=seed_mask,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind, 237 | col_ind=col_ind,type='binary',binary_color='black',tri_planar=TRUE,mask=mask)+ 238 | labs(alpha='Seed mask')+theme_black_bg() 239 | 240 | 241 | dd_1<-ggBrain(brains=s_map1,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind, 242 | col_ind=col_ind,tri_planar=TRUE,mask=mask) + theme_black_bg() 243 | 244 | library(gridExtra) 245 | grid.arrange(dd_mask,dd_1) 246 | 247 | 248 | # We can also show two seed correlation maps 249 | # from two different subjects. Note, these maps 250 | # are on the same scale, as correlations are 251 | # standardized 252 | dd<-ggBrain(brains=list(s_map1,s_map2), 253 | brain_ind=c(1,1,1,2,2,2), 254 | template=template, 255 | mar=c(1,2,3,1,2,3), 256 | mar_ind=c(37,18,30,37,18,30), 257 | row_ind=c('Subject 1','Subject 1','Subject 1','Subject 2','Subject 2','Subject 2'), 258 | col_ind=factor(c(1,2,3,1,2,3),labels=c('Saggital','Coronal','Transverse')), 259 | mask=mask) 260 | dd + ggtitle('Seed correlations for two subjects')+ theme_black_bg() 261 | 262 | 263 | 264 | ################### 265 | # row_ind and col_ind can be used to look at 266 | # several slices 267 | 268 | # instead of inputting the mask directly, we 269 | # can set the masked out voxels to NA 270 | hd_template_masked<-hd_template 271 | hd_template_masked[hd_template_masked==0]<-NA 272 | 273 | dd<-ggBrain(brains=hd_template_masked, 274 | mar=rep(3,8), 275 | mar_ind=floor(seq(140,50,length=8)), 276 | col_ind=c(1,1,1,1,2,2,2,2), 277 | row_ind=c(1,2,3,4,1,2,3,4), 278 | type='structural') 279 | dd+ theme_black_bg() 280 | 281 | 282 | 283 | # We can also add a key to the above type of plot, 284 | # using the lines_mat argument 285 | mar=c(3,3,3,3,3,3,3,1) 286 | mar_ind=c(floor(seq(140,50,length=7)),88) 287 | col_ind=c(1,1,1,1,2,2,2,2) 288 | row_ind=c(1,2,3,4,1,2,3,4) 289 | lines_mat<-cbind(8,mar,mar_ind)[1:7,] 290 | 291 | dd<-ggBrain(brains=hd_template,mar=mar,mar_ind=mar_ind,row_ind=row_ind,col_ind=col_ind, 292 | mask=hd_template>0,type='structural',lines_mat=lines_mat) 293 | 294 | 295 | dd+ theme_black_bg() 296 | 297 | 298 | 299 | # The same type of plots can be made for 300 | # seed correlations 301 | mar_ind=c(floor(seq(50,20,length=7)),30) #reduce dimensions 302 | # to match fMRI data 303 | 304 | lines_mat<-cbind(8,mar,mar_ind)[1:7,] 305 | 306 | dd<-ggBrain(brains=s_map1,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind, 307 | col_ind=col_ind,mask=mask,lines_mat=lines_mat) 308 | 309 | dd + theme_black_bg() 310 | 311 | 312 | 313 | # We can also plot fMRI activation over time 314 | dd<-ggBrain(brains=nii1_trunc,template=template, 315 | mask=mask, 316 | mar=rep(3,4), 317 | mar_ind=rep(30,4), 318 | row_ind=rep(1,4), 319 | col_ind=paste('time',1:4), 320 | time=1:4) 321 | dd + theme_black_bg() 322 | 323 | # Note, to change legend labels for figures of type='signed', 324 | # we must change both the label for fill and for alpha, 325 | # as ggBrain combines these two aesthetics into a custom, 326 | # hardcoded legend (when combine_legend=TRUE). If separate 327 | # labels are given for fill and alpha, the two aesthetic dimensions 328 | # will appear in separate legends. 329 | # For example: 330 | dd <- ggBrain(template=template,brains=s_map1, 331 | mask=mask,mar=3,mar_ind=30,type='signed') 332 | # ex1: 333 | dd + labs(fill='new_label',alpha='new_label') 334 | # ex2: 335 | dd + labs(fill='sign',alpha='abs_value') 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /man/sign_no_zero.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ggBrainCode.r 3 | \name{sign_no_zero} 4 | \alias{sign_no_zero} 5 | \title{Get binary sign of a variable, or array} 6 | \usage{ 7 | sign_no_zero(x) 8 | } 9 | \arguments{ 10 | \item{x}{a vector or array} 11 | } 12 | \value{ 13 | a vector or array telling if each element of x is 14 | greater than or equal to zero. This array will be of the same 15 | dimension as \code{x}, but with elements -1 for negative values of 16 | \code{x}, and elements +1 for positive values of \code{x} 17 | } 18 | \description{ 19 | Get binary sign of a variable, or array 20 | } 21 | \examples{ 22 | sign_no_zero(-2:2) #returns -1 -1 1 1 1 23 | } 24 | \seealso{ 25 | \code{\link{sign}} 26 | } 27 | -------------------------------------------------------------------------------- /man/theme_black_bg.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ggBrainCode.r 3 | \name{theme_black_bg} 4 | \alias{theme_black_bg} 5 | \alias{theme_all_blank} 6 | \alias{theme_no_ticks} 7 | \title{Possible theme settings for brain image plots} 8 | \usage{ 9 | theme_black_bg() 10 | 11 | theme_all_blank() 12 | 13 | theme_no_ticks() 14 | } 15 | \value{ 16 | ggplot theme objects 17 | } 18 | \description{ 19 | \code{theme_black_bg} makes the background of the image black, 20 | \code{theme_no_ticks} removes tick marks from the axes, 21 | \code{theme_all_blank} removes additional aesthetic labels 22 | from the ggplot image, 23 | } 24 | \examples{ 25 | \dontrun{ 26 | library(oro.nifti) 27 | library(ggplot2) 28 | 29 | s_map1<-readNIfTI(system.file('seed_corr_1.nii.gz', package='ggBrain')) 30 | template <- readNIfTI(system.file('template.nii.gz', package='ggBrain')) 31 | 32 | dd<-ggBrain(brains=template,mask=template>0, 33 | mar=c(3,3),mar_ind=c(30,40),col_ind=c(1,2), 34 | type='structural',center_coords=FALSE)+ 35 | scale_fill_continuous(low="black", high="white") 36 | 37 | #without theme settings 38 | dd 39 | 40 | #with theme settings 41 | dd + theme_black_bg() 42 | dd + theme_black_bg() + theme_no_ticks() 43 | dd + theme_black_bg() + theme_all_blank() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vignettes/figure/2brain_compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/2brain_compare.png -------------------------------------------------------------------------------- /vignettes/figure/4panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/4panel.png -------------------------------------------------------------------------------- /vignettes/figure/fMRI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/fMRI.png -------------------------------------------------------------------------------- /vignettes/figure/line-key-corr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/line-key-corr.png -------------------------------------------------------------------------------- /vignettes/figure/line-key-str.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/line-key-str.png -------------------------------------------------------------------------------- /vignettes/figure/single-plots-abs-val.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/single-plots-abs-val.png -------------------------------------------------------------------------------- /vignettes/figure/single-plots-bf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/single-plots-bf.png -------------------------------------------------------------------------------- /vignettes/figure/single-plots-no-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/single-plots-no-template.png -------------------------------------------------------------------------------- /vignettes/figure/single-plots-seed-corr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/single-plots-seed-corr.png -------------------------------------------------------------------------------- /vignettes/figure/single-plots-structural.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/single-plots-structural.png -------------------------------------------------------------------------------- /vignettes/figure/tri-panel1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/tri-panel1.png -------------------------------------------------------------------------------- /vignettes/figure/tri-panel2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronjfisher/ggBrain/729d8a670248448ad1738765a2933d5036201671/vignettes/figure/tri-panel2.png -------------------------------------------------------------------------------- /vignettes/intro.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | # Introduction to the ggBrain Package 8 | 9 | 10 | ## Introduction 11 | 12 | The *ggBrain* package converts 3-D or 4-D brain image arrays to "long" data frames, which are then converted in *ggplot* objects. Users can create multi-panel figures showing several slices from several brains. Within each panel, either structural images can be displayed, or voxelwise statistics (i.e. seed correlations or p-values) can be displayed on top of a template. 13 | 14 | The `ggBrain` function is the flagship function of this package, and requires minimal input from the user. This function generates *ggplot* objects for displaying brain images. For further customization of brain image figures, the `getBrainFrame` function can be used to generate long data frames from 3-D or 4-D brain image arrays. These data frames include variables that can be used for faceting images in multi-panel displays. Within the *ggBrain* package, the `ggBrain` function makes several calls to `getFrameBrain`. 15 | 16 | The package also includes several aesthetic features, such as: 17 | * A special option for "tri-planar" figures: For a given voxel, a tri-planar figure shows the sagittal, coronal, and transverse slices that intersect that voxel. These three slices are shown in three panels, and cross-hairs are generated to show the spacial correspondence between the slices. 18 | * Separete fill scales for template images and for overlaying voxelwise statistics: The *ggplot2* package generally discourages the use of color to display different types of data, on different scales. This poses a challange for brain image figures where we want to use color to display tissue intensity of a template brain image, and also use color to show the value of a voxel-wise statistic (such as seed correlation) overlaid on top of the template. The template tissue intensities and the test statistic values are on different scales, which goes against *ggplot*'s method of mapping only one scale to color. `ggBrain` implements the quick fix of hardcoding the coloring of the template image. 19 | * Combined legends that incorportate both alpha blending and fill. 20 | * *ggplot* themes, for changing the background to be black, and for removing irrelevant plot labels. 21 | 22 | The remainder of this vignette provides example code for basic image figures with just one slice, for multi-panel figures, and for tri-planar figures. 23 | 24 | 25 | ## Single-panel figures 26 | 27 | Before beginning our basic examples, we'll load brain images for use in the remainder of this vignette. 28 | 29 | 30 | ```r 31 | # Loading data for use in all examples 32 | 33 | library(oro.nifti) #for opening nii.gz files 34 | 35 | s_map1<-readNIfTI(system.file('seed_corr_1.nii.gz', package='ggBrain')) 36 | s_map2<-readNIfTI(system.file('seed_corr_2.nii.gz', package='ggBrain')) 37 | template <- readNIfTI(system.file('template.nii.gz', package='ggBrain')) 38 | mask <- readNIfTI(system.file('brain_mask.nii.gz', package='ggBrain')) 39 | seed_mask <- readNIfTI(system.file('seed_mask.nii.gz', package='ggBrain')) 40 | nii1_trunc <- readNIfTI(system.file('subj_trunc_1.nii.gz', package='ggBrain')) 41 | 42 | 43 | # get high definition brain image from the brainR package 44 | if(require(brainR)){ 45 | hd_template <- readNIfTI(system.file("MNI152_T1_1mm_brain.nii.gz", package="brainR")) 46 | } 47 | 48 | library(ggBrain) 49 | library(ggplot2) 50 | ``` 51 | 52 | To create a single-slice plot of a structural brain image (i.e. MRI, as opposed to fMRI), set the `type` argument of `ggBrain` to `'structural'`. 53 | 54 | 55 | ```r 56 | dd<-ggBrain(brains=hd_template,mask=hd_template>0,mar=3,mar_ind=93,type='structural') 57 | #now add aethetic changes with conventional ggplot code. 58 | dd + scale_fill_continuous(low="black", high="white") + theme_black_bg() 59 | ``` 60 | 61 | ![plot of chunk single-plots-structural](figure/single-plots-structural.png) 62 | 63 | Above, the `mar=3` argument tells that the transverse plane should be used, as opposed to the sagittal or coronal planes. The `mar_ind` argument tells the slice number to plot. 64 | 65 | Voxelwise statistics can also be plotted on top of a template image. If the voxelwise statistic can be both positive and negative (i.e. seed correlation images), users should set `type=signed`. `ggBrain` uses color to denote the sign of the voxelwise statistic, and alpha blending to denote the absolute value of the statistic. By default, `ggBrain` combines these two aesthetic dimensions (color and alpha blending) into a single legend. This is achieved by binning the values of the voxelwise statistic. The legend shows the upper boundaries of these bins. 66 | 67 | 68 | ```r 69 | # s_map1 is a seed correlation image, based on correlation with the region denoted by seed_mask 70 | dd<-ggBrain(template=template,brains=s_map1,mask=mask,mar=3,mar_ind=30,type='signed') 71 | 72 | dd + theme_black_bg() 73 | ``` 74 | 75 | ![plot of chunk single-plots-seed-corr](figure/single-plots-seed-corr.png) 76 | 77 | For voxelwise statistics are all positive (i.e., p-values), the `type` argument should be set to `'positive'`. As an example here we simply take the absolute value of the seed correlation image, but a p-value map could also be displayed. 78 | 79 | 80 | 81 | 82 | ```r 83 | dd<-ggBrain(template=template,brains=abs(s_map1),mask=mask,mar=3,mar_ind=30,type='positive') 84 | 85 | dd + scale_alpha(range=c(0,1)) + theme_black_bg() 86 | ``` 87 | 88 | ![plot of chunk single-plots-abs-val](figure/single-plots-abs-val.png) 89 | 90 | If no template is specified, values are plotted against a pure white version of the mask. 91 | 92 | 93 | ```r 94 | dd<-ggBrain(brains=abs(s_map1),mask=mask,mar=3,mar_ind=30,type='positive') 95 | 96 | dd + scale_alpha(range=c(0,1)) + theme_black_bg() 97 | ``` 98 | 99 | ![plot of chunk single-plots-no-template](figure/single-plots-no-template.png) 100 | 101 | 102 | For users more familiar with *ggplot*, the `getBrainFrame` function can be used to generate a data frames for use in *ggplot* objects. This can allows more control over plotting choices, but also requires more input from the user. 103 | 104 | 105 | ```r 106 | bf<-getBrainFrame(brains=hd_template,mar=3,mar_ind=93,mask=hd_template>0,center_coords=FALSE) 107 | head(bf) 108 | ``` 109 | 110 | ``` 111 | ## value row col row_ind col_ind 112 | ## 1 3409 97 26 1 1 113 | ## 2 3877 98 26 1 1 114 | ## 3 4258 99 26 1 1 115 | ## 4 4530 100 26 1 1 116 | ## 5 4710 101 26 1 1 117 | ## 6 4782 102 26 1 1 118 | ``` 119 | 120 | ```r 121 | ggplot()+geom_tile(data=bf, aes(x=row,y=col,fill=value))+facet_grid(row_ind~col_ind)+coord_fixed(ratio = 1) 122 | ``` 123 | 124 | ![plot of chunk single-plots-bf](figure/single-plots-bf.png) 125 | 126 | 127 | ## Multi-panel brain figures 128 | 129 | For multi-panel images, either `ggBrain` or `getBrainFrame` require the input of several vectors: `mar`, `mar_ind`, `col_ind`, `row_ind`. All of these vectors should be of the same length. This length will be equal to the number of panels in the final figure. 130 | 131 | For each panel, `mar` denotes which margin of the brain image we should slice over, `mar_ind` denotes the slice number, and `row_ind` and `col_ind` denote the position of the panel within the overall figure. This layout convention allows for several types of images to be constructed, such as tri-planar figures and comparisons of images from different subjects. 132 | 133 | As a basic example, suppose we wish to show four transverse slices from a single subject's brain image. 134 | 135 | 136 | ```r 137 | mar_ind<-floor(seq(140,90,length=4)) 138 | 139 | dd<-ggBrain(hd_template, mask=hd_template>0, 140 | mar= c(3,3,3,3), 141 | mar_ind=mar_ind, 142 | col_ind=c(1,1,1,1), 143 | row_ind=factor(c(1,2,3,4),labels=paste('Slice',mar_ind)), 144 | type='structural') 145 | 146 | dd + theme_black_bg() 147 | ``` 148 | 149 | ![plot of chunk 4panel](figure/4panel.png) 150 | 151 | Above, setting the values of `row_ind` to the vector `c(1,2,3,4)` causes the images to be aligned vertically. 152 | 153 | Alternatively, we can use the `time` argument to plot different images taken during the course of an fMRI 154 | 155 | 156 | ```r 157 | dd<-ggBrain(brains=nii1_trunc,template=template, 158 | mask=mask, 159 | mar=rep(3,4), 160 | mar_ind=rep(30,4), 161 | row_ind=rep(1,4), 162 | col_ind=paste('Time',1:4), 163 | time=1:4) 164 | 165 | dd + theme_black_bg() + labs(title='Sample fMRI data') 166 | ``` 167 | 168 | ![plot of chunk fMRI](figure/fMRI.png) 169 | 170 | 171 | We can also use the `brain_ind` argument to show seed correlation images from two different subjects. Changing the `mar` vector lets us to show different slices for each subject. Note, these correlation images are on the same scale. 172 | 173 | 174 | 175 | ```r 176 | dd<-ggBrain(brains=list(s_map1,s_map2), 177 | brain_ind=c(1,1,1,2,2,2), 178 | template=template, 179 | mar=c(1,2,3,1,2,3), 180 | mar_ind=c(37,18,30,37,18,30), 181 | row_ind=c('Subject 1','Subject 1','Subject 1','Subject 2','Subject 2','Subject 2'), 182 | col_ind=factor(c(1,2,3,1,2,3),labels=c('Sagittal','Coronal','Transverse')), 183 | mask=mask) 184 | dd + ggtitle('Seed correlations for two subjects') + theme_black_bg() 185 | ``` 186 | 187 | ![plot of chunk 2brain_compare](figure/2brain_compare.png) 188 | 189 | The `lines_mat` argument can be used to add a key to multi-panel plots. This argument should contain a matrix with 3 columns, and one row for each line to be added to the figure. Each row of `lines_mat` should contain a triplet of values, with the first element telling which panel the line should be placed in, the second element containing the margin to plot over, and the third element telling the slice index where the line should be placed. 190 | 191 | 192 | 193 | ```r 194 | mar=c(3,3,3,3,3,3,3,1) 195 | mar_ind=c(floor(seq(140,50,length=7)),88) 196 | col_ind=c(1,1,1,1,2,2,2,2) 197 | row_ind=c(1,2,3,4,1,2,3,4) 198 | lines_mat<-cbind('panel'=8,mar,mar_ind)[1:7,] 199 | 200 | lines_mat 201 | ``` 202 | 203 | ``` 204 | ## panel mar mar_ind 205 | ## [1,] 8 3 140 206 | ## [2,] 8 3 125 207 | ## [3,] 8 3 110 208 | ## [4,] 8 3 95 209 | ## [5,] 8 3 80 210 | ## [6,] 8 3 65 211 | ## [7,] 8 3 50 212 | ``` 213 | 214 | ```r 215 | dd <- ggBrain(brains=hd_template, mar=mar, mar_ind=mar_ind, 216 | row_ind=row_ind, col_ind=col_ind, mask=hd_template>0, 217 | type='structural', lines_mat=lines_mat) 218 | 219 | dd + theme_black_bg() + theme_all_blank() 220 | ``` 221 | 222 | ![plot of chunk line-key-str](figure/line-key-str.png) 223 | 224 | These types of plots can also be created for voxelwise statistics 225 | 226 | 227 | ```r 228 | mar_ind=c(floor(seq(48,20,length=7)),30) #reduce dimensions 229 | # to match fMRI data 230 | lines_mat<-cbind('panel'=8,mar,mar_ind)[1:7,] 231 | 232 | dd <- ggBrain(brains=s_map1, template=template, mar=mar,mar_ind=mar_ind, 233 | row_ind=row_ind, col_ind=col_ind, mask=mask, lines_mat=lines_mat) 234 | 235 | dd + theme_black_bg() + theme_all_blank() 236 | ``` 237 | 238 | ![plot of chunk line-key-corr](figure/line-key-corr.png) 239 | 240 | 241 | 242 | ### Tri-planar figures 243 | 244 | For a given voxel, a tri-planar figure shows the sagittal, coronal, and transverse slices that intersect that voxel. These three slices are shown in three panels, and cross-hairs are generated to show the spacial correspondence between the panels. 245 | 246 | In the example arrangement below, horizontal and vertical cross-hair lines are set up to continue across the panels. Both horizontal cross-hair lines on the top two panels correspond to the same transverse slice, shown in the bottom panel. Both virtical cross-hairs on the leftmost panels correspond to the same sagittal slice, shown on the right. 247 | 248 | 249 | ```r 250 | dd<-ggBrain(brains=s_map1,template=template, 251 | mar = c(1,2,3), 252 | mar_ind = c(37,18,30), 253 | row_ind= c(1,1,2), 254 | col_ind= c(2,1,1), 255 | tri_planar=TRUE, lines_color='black',mask=mask) 256 | dd 257 | ``` 258 | 259 | ![plot of chunk tri-panel1](figure/tri-panel1.png) 260 | 261 | In the next example, we show the seed mask and the seed correlation map from an example subject. Since the mask and the map are on different scales, we use `grid.arrange` to display them separately. 262 | 263 | 264 | 265 | ```r 266 | mar = c(1,2,3) 267 | col_ind = factor(c(1,2,3),labels=c('Sagittal','Coronal','Transverse')) 268 | row_ind = c(1,1,1) 269 | mar_ind= c(37,18,30) 270 | 271 | dd_mask<-ggBrain(brains=seed_mask,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind,col_ind=col_ind,type='binary',binary_color='black',tri_planar=TRUE,mask=mask)+ 272 | labs(alpha='Binary mask',title='Seed Mask')+theme_black_bg() 273 | 274 | 275 | dd_1<-ggBrain(brains=s_map1,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind,col_ind=col_ind,tri_planar=TRUE,mask=mask)+ 276 | labs(title='Seed Correlation Map') + theme_black_bg() 277 | 278 | library(gridExtra) 279 | grid.arrange(dd_mask,dd_1) 280 | ``` 281 | 282 | ![plot of chunk tri-panel2](figure/tri-panel2.png) 283 | 284 | 285 | 286 | -------------------------------------------------------------------------------- /vignettes/intro.rmd: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | # Introduction to the ggBrain Package 8 | 9 | 10 | ## Introduction 11 | 12 | The *ggBrain* package converts 3-D or 4-D brain image arrays to "long" data frames, which are then converted in *ggplot* objects. Users can create multi-panel figures showing several slices from several brains. Within each panel, either structural images can be displayed, or voxelwise statistics (i.e. seed correlations or p-values) can be displayed on top of a template. 13 | 14 | The `ggBrain` function is the flagship function of this package, and requires minimal input from the user. This function generates *ggplot* objects for displaying brain images. For further customization of brain image figures, the `getBrainFrame` function can be used to generate long data frames from 3-D or 4-D brain image arrays. These data frames include variables that can be used for faceting images in multi-panel displays. Within the *ggBrain* package, the `ggBrain` function makes several calls to `getFrameBrain`. 15 | 16 | The package also includes several aesthetic features, such as: 17 | * A special option for "tri-planar" figures: For a given voxel, a tri-planar figure shows the sagittal, coronal, and transverse slices that intersect that voxel. These three slices are shown in three panels, and cross-hairs are generated to show the spacial correspondence between the slices. 18 | * Separete fill scales for template images and for overlaying voxelwise statistics: The *ggplot2* package generally discourages the use of color to display different types of data, on different scales. This poses a challange for brain image figures where we want to use color to display tissue intensity of a template brain image, and also use color to show the value of a voxel-wise statistic (such as seed correlation) overlaid on top of the template. The template tissue intensities and the test statistic values are on different scales, which goes against *ggplot*'s method of mapping only one scale to color. `ggBrain` implements the quick fix of hardcoding the coloring of the template image. 19 | * Combined legends that incorportate both alpha blending and fill. 20 | * *ggplot* themes, for changing the background to be black, and for removing irrelevant plot labels. 21 | 22 | The remainder of this vignette provides example code for basic image figures with just one slice, for multi-panel figures, and for tri-planar figures. 23 | 24 | 25 | ## Single-panel figures 26 | 27 | Before beginning our basic examples, we'll load brain images for use in the remainder of this vignette. 28 | 29 | ```{r load-data, results='hide',cache=TRUE} 30 | # Loading data for use in all examples 31 | 32 | library(oro.nifti) #for opening nii.gz files 33 | 34 | s_map1<-readNIfTI(system.file('seed_corr_1.nii.gz', package='ggBrain')) 35 | s_map2<-readNIfTI(system.file('seed_corr_2.nii.gz', package='ggBrain')) 36 | template <- readNIfTI(system.file('template.nii.gz', package='ggBrain')) 37 | mask <- readNIfTI(system.file('brain_mask.nii.gz', package='ggBrain')) 38 | seed_mask <- readNIfTI(system.file('seed_mask.nii.gz', package='ggBrain')) 39 | nii1_trunc <- readNIfTI(system.file('subj_trunc_1.nii.gz', package='ggBrain')) 40 | 41 | 42 | # get high definition brain image from the brainR package 43 | if(require(brainR)){ 44 | hd_template <- readNIfTI(system.file("MNI152_T1_1mm_brain.nii.gz", package="brainR")) 45 | } 46 | 47 | library(ggBrain) 48 | library(ggplot2) 49 | 50 | ``` 51 | 52 | To create a single-slice plot of a structural brain image (i.e. MRI, as opposed to fMRI), set the `type` argument of `ggBrain` to `'structural'`. 53 | 54 | ```{r single-plots-structural,cache=TRUE,fig.height=4,fig.width=4} 55 | 56 | dd<-ggBrain(brains=hd_template,mask=hd_template>0,mar=3,mar_ind=93,type='structural') 57 | #now add aethetic changes with conventional ggplot code. 58 | dd + scale_fill_continuous(low="black", high="white") + theme_black_bg() 59 | 60 | ``` 61 | 62 | Above, the `mar=3` argument tells that the transverse plane should be used, as opposed to the sagittal or coronal planes. The `mar_ind` argument tells the slice number to plot. 63 | 64 | Voxelwise statistics can also be plotted on top of a template image. If the voxelwise statistic can be both positive and negative (i.e. seed correlation images), users should set `type=signed`. `ggBrain` uses color to denote the sign of the voxelwise statistic, and alpha blending to denote the absolute value of the statistic. By default, `ggBrain` combines these two aesthetic dimensions (color and alpha blending) into a single legend. This is achieved by binning the values of the voxelwise statistic. The legend shows the upper boundaries of these bins. 65 | 66 | ```{r single-plots-seed-corr,cache=TRUE,fig.height=4,fig.width=4} 67 | # s_map1 is a seed correlation image, based on correlation with the region denoted by seed_mask 68 | dd<-ggBrain(template=template,brains=s_map1,mask=mask,mar=3,mar_ind=30,type='signed') 69 | 70 | dd + theme_black_bg() 71 | ``` 72 | 73 | For voxelwise statistics are all positive (i.e., p-values), the `type` argument should be set to `'positive'`. As an example here we simply take the absolute value of the seed correlation image, but a p-value map could also be displayed. 74 | 75 | 76 | 77 | ```{r single-plots-abs-val,cache=TRUE,fig.height=4,fig.width=4} 78 | dd<-ggBrain(template=template,brains=abs(s_map1),mask=mask,mar=3,mar_ind=30,type='positive') 79 | 80 | dd + scale_alpha(range=c(0,1)) + theme_black_bg() 81 | ``` 82 | 83 | If no template is specified, values are plotted against a pure white version of the mask. 84 | 85 | ```{r, single-plots-no-template,cache=TRUE,fig.height=4,fig.width=4} 86 | dd<-ggBrain(brains=abs(s_map1),mask=mask,mar=3,mar_ind=30,type='positive') 87 | 88 | dd + scale_alpha(range=c(0,1)) + theme_black_bg() 89 | ``` 90 | 91 | 92 | For users more familiar with *ggplot*, the `getBrainFrame` function can be used to generate a data frames for use in *ggplot* objects. This can allows more control over plotting choices, but also requires more input from the user. 93 | 94 | ```{r single-plots-bf,cache=TRUE,fig.height=4,fig.width=4} 95 | bf<-getBrainFrame(brains=hd_template,mar=3,mar_ind=93,mask=hd_template>0,center_coords=FALSE) 96 | head(bf) 97 | 98 | ggplot()+geom_tile(data=bf, aes(x=row,y=col,fill=value))+facet_grid(row_ind~col_ind)+coord_fixed(ratio = 1) 99 | ``` 100 | 101 | 102 | ## Multi-panel brain figures 103 | 104 | For multi-panel images, either `ggBrain` or `getBrainFrame` require the input of several vectors: `mar`, `mar_ind`, `col_ind`, `row_ind`. All of these vectors should be of the same length. This length will be equal to the number of panels in the final figure. 105 | 106 | For each panel, `mar` denotes which margin of the brain image we should slice over, `mar_ind` denotes the slice number, and `row_ind` and `col_ind` denote the position of the panel within the overall figure. This layout convention allows for several types of images to be constructed, such as tri-planar figures and comparisons of images from different subjects. 107 | 108 | As a basic example, suppose we wish to show four transverse slices from a single subject's brain image. 109 | 110 | ```{r 4panel,cache=TRUE,fig.height=10,fig.width=5} 111 | mar_ind<-floor(seq(140,90,length=4)) 112 | 113 | dd<-ggBrain(hd_template, mask=hd_template>0, 114 | mar= c(3,3,3,3), 115 | mar_ind=mar_ind, 116 | col_ind=c(1,1,1,1), 117 | row_ind=factor(c(1,2,3,4),labels=paste('Slice',mar_ind)), 118 | type='structural') 119 | 120 | dd + theme_black_bg() 121 | ``` 122 | 123 | Above, setting the values of `row_ind` to the vector `c(1,2,3,4)` causes the images to be aligned vertically. 124 | 125 | Alternatively, we can use the `time` argument to plot different images taken during the course of an fMRI 126 | 127 | ```{r fMRI,cache=TRUE,fig.height=4,fig.width=8} 128 | dd<-ggBrain(brains=nii1_trunc,template=template, 129 | mask=mask, 130 | mar=rep(3,4), 131 | mar_ind=rep(30,4), 132 | row_ind=rep(1,4), 133 | col_ind=paste('Time',1:4), 134 | time=1:4) 135 | 136 | dd + theme_black_bg() + labs(title='Sample fMRI data') 137 | ``` 138 | 139 | 140 | We can also use the `brain_ind` argument to show seed correlation images from two different subjects. Changing the `mar` vector lets us to show different slices for each subject. Note, these correlation images are on the same scale. 141 | 142 | 143 | ```{r 2brain_compare,cache=TRUE, fig.height=6,fig.width=8} 144 | dd<-ggBrain(brains=list(s_map1,s_map2), 145 | brain_ind=c(1,1,1,2,2,2), 146 | template=template, 147 | mar=c(1,2,3,1,2,3), 148 | mar_ind=c(37,18,30,37,18,30), 149 | row_ind=c('Subject 1','Subject 1','Subject 1','Subject 2','Subject 2','Subject 2'), 150 | col_ind=factor(c(1,2,3,1,2,3),labels=c('Sagittal','Coronal','Transverse')), 151 | mask=mask) 152 | dd + ggtitle('Seed correlations for two subjects') + theme_black_bg() 153 | ``` 154 | 155 | The `lines_mat` argument can be used to add a key to multi-panel plots. This argument should contain a matrix with 3 columns, and one row for each line to be added to the figure. Each row of `lines_mat` should contain a triplet of values, with the first element telling which panel the line should be placed in, the second element containing the margin to plot over, and the third element telling the slice index where the line should be placed. 156 | 157 | 158 | ```{r line-key-str,cache=TRUE,fig.height=9,fig.width=7} 159 | mar=c(3,3,3,3,3,3,3,1) 160 | mar_ind=c(floor(seq(140,50,length=7)),88) 161 | col_ind=c(1,1,1,1,2,2,2,2) 162 | row_ind=c(1,2,3,4,1,2,3,4) 163 | lines_mat<-cbind('panel'=8,mar,mar_ind)[1:7,] 164 | 165 | lines_mat 166 | 167 | dd <- ggBrain(brains=hd_template, mar=mar, mar_ind=mar_ind, 168 | row_ind=row_ind, col_ind=col_ind, mask=hd_template>0, 169 | type='structural', lines_mat=lines_mat) 170 | 171 | dd + theme_black_bg() + theme_all_blank() 172 | ``` 173 | 174 | These types of plots can also be created for voxelwise statistics 175 | 176 | ```{r line-key-corr,cache=TRUE,fig.height=9,fig.width=7} 177 | mar_ind=c(floor(seq(48,20,length=7)),30) #reduce dimensions 178 | # to match fMRI data 179 | lines_mat<-cbind('panel'=8,mar,mar_ind)[1:7,] 180 | 181 | dd <- ggBrain(brains=s_map1, template=template, mar=mar,mar_ind=mar_ind, 182 | row_ind=row_ind, col_ind=col_ind, mask=mask, lines_mat=lines_mat) 183 | 184 | dd + theme_black_bg() + theme_all_blank() 185 | ``` 186 | 187 | 188 | 189 | ### Tri-planar figures 190 | 191 | For a given voxel, a tri-planar figure shows the sagittal, coronal, and transverse slices that intersect that voxel. These three slices are shown in three panels, and cross-hairs are generated to show the spacial correspondence between the panels. 192 | 193 | In the example arrangement below, horizontal and vertical cross-hair lines are set up to continue across the panels. Both horizontal cross-hair lines on the top two panels correspond to the same transverse slice, shown in the bottom panel. Both virtical cross-hairs on the leftmost panels correspond to the same sagittal slice, shown on the right. 194 | 195 | ```{r tri-panel1,cache=TRUE,fig.height=5,fig.width=10} 196 | dd<-ggBrain(brains=s_map1,template=template, 197 | mar = c(1,2,3), 198 | mar_ind = c(37,18,30), 199 | row_ind= c(1,1,2), 200 | col_ind= c(2,1,1), 201 | tri_planar=TRUE, lines_color='black',mask=mask) 202 | dd 203 | ``` 204 | 205 | In the next example, we show the seed mask and the seed correlation map from an example subject. Since the mask and the map are on different scales, we use `grid.arrange` to display them separately. 206 | 207 | 208 | ```{r tri-panel2, results='hide',cache=TRUE,fig.height=6,fig.width=8} 209 | mar = c(1,2,3) 210 | col_ind = factor(c(1,2,3),labels=c('Sagittal','Coronal','Transverse')) 211 | row_ind = c(1,1,1) 212 | mar_ind= c(37,18,30) 213 | 214 | dd_mask<-ggBrain(brains=seed_mask,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind,col_ind=col_ind,type='binary',binary_color='black',tri_planar=TRUE,mask=mask)+ 215 | labs(alpha='Binary mask',title='Seed Mask')+theme_black_bg() 216 | 217 | 218 | dd_1<-ggBrain(brains=s_map1,template=template,mar=mar,mar_ind=mar_ind,row_ind=row_ind,col_ind=col_ind,tri_planar=TRUE,mask=mask)+ 219 | labs(title='Seed Correlation Map') + theme_black_bg() 220 | 221 | library(gridExtra) 222 | grid.arrange(dd_mask,dd_1) 223 | 224 | ``` 225 | 226 | 227 | 228 | --------------------------------------------------------------------------------