R/cor.plot.R

#developed April 24, 2009
#modifed November 14, 2009 to add legends
#completely revised June 20, 2011 to do more reds for less than 0, blues for above 0
#also switched to using layout to make legend clearer
#modified May 5, 2012 to add the keep.par option to allow more control of small graphics
#Corrected feb 22, 2014 to not double plot text (reported by David Condon)
#modified May 12 to allow for selection
#modified March 28, 2016 to add the upper option 
#modified Feb 4, 2017 to label plots and to find correlations by default
#modified April 15, 2017 to allow for non-symmetric matrices
#modified April 15, 2017 to allow more plotting control on the x and y rotation options
#modified November 29th, 2017 to allow for semi-transparency by adjusting alpha
#Finally changed the default to be numbers=TRUE (9/17/19)
#Added the sort option 6/13/23
#Added the ability to rotate x labels xsrt  if xlas =0
#fixed the stars option for the case of lower diagonal so that it works
#Added the n.obs paramter for people who like stars for correlation input  8/6/23


"cor.plot" <- "corPlot" <- 
function(r,numbers=TRUE,colors=TRUE, n=51,main=NULL,zlim=c(-1,1),show.legend=TRUE,
  labels=NULL,
    n.legend=10,keep.par=TRUE,select=NULL,
    pval=NULL,digits=2, trailing=TRUE,
    cuts=c(.001,.01),scale=TRUE,cex,MAR,upper=TRUE,
    diag=TRUE,symmetric=TRUE,stars=FALSE,adjust="holm",
    xaxis =1, xlas=0,ylas=2,ysrt=0, xsrt=0, gr=NULL,alpha =.75,
    min.length=NULL, sort=FALSE, n.obs=NULL, ...){
if(keep.par) op <- par(no.readonly=TRUE)
if(missing(MAR)) MAR <- 5
if(!is.matrix(r) & (!is.data.frame(r))) {if((length(class(r)) > 1) & (inherits(r, "psych")))  {
switch(class(r)[2],
   omega  = {r <- r$schmid$sl
             nff <- ncol(r)
            r <- r[,1:(nff-3)]
           if(is.null(main)) {main <- "Omega plot" }},
  cor.ci ={ pval <- 2*(1-r$ptci)
           r <- r$rho},
  fa = {r <- r$loadings
         if(is.null(main)) {main <- "Factor Loadings plot" }},
  pc = {r <- r$loadings
       if(is.null(main)) {main <- "PCA Loadings plot" }
            },
  principal = {r <- r$loadings
        if(is.null(main)) {main <- "PCA Loadings plot" }}    
  )  #end switch
  }
  } else { if(symmetric & !isCorrelation(r) & (nrow(r) !=ncol(r))) {
    cp <- corr.test(r,adjust=adjust)  #find the corelations
    r <- cp$r
    pval <- cp$p
    if(is.null(main)) {main <- "Correlation plot from data" }
    } else {scale<- FALSE 
      if(is.null(main)) {main <- "Correlation plot"}  
   } 
    if(isCorrelation(r)& !is.null(n.obs) )  pval <- corr.p(r,n.obs)$p 
     }
R <- r <- as.matrix(r)
if(!is.null(select)) r <- r[select,select]
if(sort) {ord <- iclust(r,plot=FALSE)$ord
    r <- r[ord,ord]}
if(min(dim(r)) < 2) {stop ("You need at least two dimensions to make a meaningful plot")}

if(is.null(n)) {n <- dim(r)[2]}
nf <- dim(r)[2]
nvar <- dim(r)[1]

if(!upper) r[col (r) > row(r) ] <- NA   #blank out the upper diagonal
if(!diag) r[col(r) == row(r)] <- NA     #and the diagonal
if(nf == nvar) r <- t(r)  # flip the matrix because grid requires it  but don't flip if a loadings matrix
if(missing(pval)|is.null(pval)) {pval <- matrix(rep(1,nvar*nf),nvar)} else {if (length(pval) != nvar*nf) {
        pr = matrix(0,nvar,nf)
        pr [row(pr) > col(pr)] <- pval # pr[pval[pr]] <- pval
        pr <- pr + t(pr)
        diag(pr) <- 0
        pval <- pr}
       
        if(!stars) {pval <- con2cat(pval,cuts=cuts)
        pval <- (length(cuts)+1-pval)/length(cuts)}
        pval <- t(pval)  #flip these so that the lower off diagonal will be unadjusted
        }

if(is.null(labels)) {
if(is.null(rownames(r))) rownames(r) <- paste("V",1:nvar)
if(is.null(colnames(r))) colnames(r) <- paste("V",1:nf)
} else {rownames(r) <-  colnames(r) <- labels}
if(!is.null(min.length)) {
    rownames(r) <- abbreviate(rownames(r),minlength = min.length)
    colnames(r) <- abbreviate(colnames(r),minlength = min.length)
    }
 max.len <- max(nchar(rownames(r)))/6
#max.len <- max( strwidth(rownames(r)))
if(is.null(zlim)) {zlim <- range(r)}
if(colors) { 
   if(missing(gr))  {gr <- colorRampPalette(c("red","white","blue"))}  #added June 20, 2018? 
   if(max(r,na.rm=TRUE) > 1) {#add a fudge to make all the big ones the same
   maxr <- max(r)
   n1 <- n*(zlim[2]- zlim[1])/(maxr- zlim[1]) 
   colramp <- rep(NA,n)
   n1 <- ceiling(n1)
   colramp[1:(n1+1)] <- gr(n1+1)
   colramp[(n1+1):n] <- colramp[n1+1] 
 zlim[2] <- maxr 
   } else {
    colramp  <- gr(n)}
      } else {
    colramp <- grey((n:0)/n)}
 colramp <- adjustcolor(colramp,alpha.f =alpha)   
if(nvar != nf) {  r <- t(r) }
#if(!is.null(select)) {r <- r[select,select]
#                      pval <- pval[select,select]
#                      nvar <- length(select)
#                      }
#reverse the order of the columns (if square)
 ord1 <- seq(nvar,1,-1)  
 
if(nf == nvar) {r <- r[,ord1] 
 pval <- pval[,ord1]} else {r <- r[,ord1] 
 pval <- t(pval[ord1,])}
 #reorder the columns to allow image to work
#MAR <- 5
par(mar = c(MAR +max.len,MAR+max.len, 4, .5))

if(show.legend) {   #set it up to do two plots
     layout(matrix(c(1,2),nrow=1),widths=c(.9,.1),heights=c(1,1))
    }

image(r,col=colramp,axes=FALSE,main=main,zlim=zlim)
box()
#if(nf < nvar) {
 			at1 <- (0:(nf-1))/(nf-1)
               at2 <- (0:(nvar-1)) /(nvar-1)
               lab1 <- rownames(r)
               lab2 <- colnames(r)
# } else {
#              at1 <- (0:(nf-1)) /(nf-1)
#              at2 <- (0:(nvar-1)) /(nvar-1)
#               lab1 <- rownames(r)
#               lab2 <- colnames(r)
#              }


#if(nvar != nf) {  r <- t(r) }
if(xaxis == 3) {line <- -.5
 tick <- FALSE} else {line <- NA
 tick <- TRUE}

if(max.len >.5) {axis(2,at=at2,labels=lab2,las=ylas,...)
          if(xsrt==0)  {  axis(xaxis,at=at1,labels=lab1,las=xlas,line=line,tick=tick,...)} else {
            axis(xaxis,at=at1,labels=FALSE,las=xlas,line=line,tick=tick,...)
          text(at1, par("usr")[3]*3, labels = lab1, srt = xsrt, xpd=TRUE,...) }} else {
              axis(2,at=at2,labels=lab2,las=ylas,...)
           if(xsrt==0)  { axis(xaxis,at=at1,labels=lab1,las=xlas,line=line,tick=tick,...)} else {
               axis(xaxis,at=at1,labels=FALSE,las=xlas,line=line,tick=tick,...)
              text(at1, par("usr")[3]*3, labels = lab1, srt = xsrt, xpd=TRUE,...) }
              }
#at1 <- (0:(nf-1))/(nf-1)

if(numbers) {rx <- rep(at1,ncol(r))
            ry <-rep(at2,each=nrow(r))
# rv <- round(r*100)
rv <- round(r,digits) 
 if(trailing) {rv <- sprintf("%.2f", rv)# format with trailing 0rv
              rv[rv=="NA"] <- ""     #drop the NAs  for lower Cors
              }

 if(stars) {#pval <- corr.p1(r,npairs,"none"
           
            symp <- symnum(pval, corr = FALSE,cutpoints = c(0,  .001,.01,.05, 1),
                symbols = c("***","**","*"," "),legend=FALSE)
                rv[(!is.na(rv))] <- paste0(rv[(!is.na(rv))],symp[!is.na(rv)])
                rv <- matrix(rv,ncol=ncol(pval))
                if(!upper) rv[ncol(rv)+diag - row(rv) < col(rv)] <- ""
                 if(missing(cex))  cex = 9/max(nrow(r),ncol(r))
                 text(rx,ry,rv,cex=cex,...)  } else {

 if(missing(cex))  cex = 9/max(nrow(r),ncol(r))
 
 
if(scale) { text(rx,ry,rv,cex=pval*cex,...) } else { text(rx,ry,rv,cex= 1.5*cex,...) }}
 }
if(show.legend) {
    leg <- matrix(seq(from=zlim[1],to=zlim[2],by =(zlim[2] - zlim[1])/n),nrow=1)
#screen(2) 
   par(mar=c(MAR,0, 4,3)) 
   image(leg,col=colramp,axes=FALSE,zlim=zlim)  
   at2 <- seq(0,1,1/n.legend)
    labels =seq(zlim[1],zlim[2],(zlim[2]-zlim[1])/(length(at2)-1))
    axis(4,at=at2,labels =labels,las=2,...)
   }  
if(keep.par) par(op)  #return the parameters to where we started 
invisible(R)    #added 11/26/18
}

 #used to find p values for corPlot
 #just an internal function

#notice that the matrix is flipped to do the plotting
#we need to find the lowerright
 "corr.p1" <-
function(r,n,adjust="holm") {
t <- (r*sqrt(n-2))/sqrt(1-r^2)
p <- 2*(1 - pt(abs(t),(n-2)))
p[p>1] <- 1
if (adjust !="none") {
  p[] <- p.adjust(p ,adjust)  #the case of an asymmetric matrix
 }
result <- p
return(result)
}


"reflect" <- function(m) {
  NR <- NROW(m)
  NC <- NCOL(m)
  m[NR+1 - row(m)] <- m[row(m)]
  m[NC +1 - col(m)] <- m[col(m)]}

Try the psych package in your browser

Any scripts or data that you put into this service are public.

psych documentation built on Sept. 26, 2023, 1:06 a.m.