How to colourise some cell borders in R corrplot?

2019-02-28 14:57发布

问题:

I would like to keep some cells in attention by making their borders clearly distinct from anything else.

The parameter rect.col is used to colorise all borders but I want to colorise only borders of the cells (3,3) and (7,7), for instance, by any halo color etc heat.colors(100) or rainbow(12).

Code:

library("corrplot")
library("psych")

ids <- seq(1,11) 

M.cor <- cor(mtcars)
colnames(M.cor) <- ids
rownames(M.cor) <- ids

p.mat <- psych::corr.test(M.cor, adjust = "none", ci = F)
p.mat <- p.mat[["r"]]

corrplot(M.cor, 
  method = "color", 
  type = "upper", 
  tl.col = 'black', 
  diag = TRUE, 
  p.mat = p.mat, 
  sig.level = 0.0000005
)

Fig. 1 Output of the top code without cell bordering, Fig. 2 Output after manually converting all coordinates to upper triangle but artifact at (10,1),
Fig. 3 Output with window size fix

Input: locations by ids (3,3) and (7,7)
Expected output: two cells where borders marked on upper triangle

Pseudocode

# ids must be id.pairs  
# or just a list of two lists
createBorders <- function(id.pairs) {

  labbly(id.pairs,function(z){
    x <- z$V1
    y <- z$V2
    rect(x+0.5, y+0.5, x+1.5, y+1.5) # user20650

  })
}

corrplot(...)
# TODO Which datastructure to use there in the function as the paired list of ids? 
createBorders(ids.pairs)

Testing user20650's proposal

rect(2+0.5, 9+0.5, 3+0.5, 10+0.5, border="white", lwd=2)

Output in Fig. 2. It would be great to have a function for this. Assume you have a list of IDs.

I think there is something wrong with the placement because (2,3),(9,10) leads to the point in (2,3),(2,3).

Iterating user20650's Proposal in Chat

library("corrplot")
library("psych")

ids <- seq(1,11)

M.cor <- cor(mtcars)
colnames(M.cor) <- ids
rownames(M.cor) <- ids

p.mat <- psych::corr.test(M.cor, adjust = "none", ci = F)
p.mat <- p.mat[["r"]]

# Chat of http://stackoverflow.com/q/40538304/54964 user20650
cb <- function(corrPlot, ..., rectArgs = list() ){
        lst <- list(...)
                n <- ncol(corrPlot)
                nms <- colnames(corrPlot)
                colnames(corrPlot) <- if(is.null(nms)) 1:ncol(corrPlot) else nms

                xleft <- match(lst$x, colnames(corrPlot)) - 0.5
                ybottom <- n - match(lst$y, colnames(corrPlot)) + 0.5

                lst <- list(xleft=xleft, ybottom=ybottom, xright=xleft+1, ytop=ybottom+1)
                do.call(rect, c(lst, rectArgs))
}
plt <- corrplot(M.cor,
                method = "color",
                type = "upper",
                tl.col = 'black',
                diag = TRUE,
                p.mat = p.mat,
                sig.level = 0.0000005
               )
cb(plt, x=c(1, 3, 5), y=c(10, 7, 4), rectArgs=list(border="white", lwd=3))

Output where only one cell border marked in Fig. 3.

Expected output: three cell borders marked

Restriction in Fig. 2 approach

You have to work all coordinates first to upper triangle. So you can now call only the following where output has an artifact at (10,1) in Fig. 2

cb(plt, x=c(10, 7, 5), y=c(1, 3, 4), rectArgs=list(border="white", lwd=3))

Expected output: no artifact at (10,1)

The cause of the artifact can be white background, but it occurs also if the border color is red so most probably it is not the cause. Solution - fix the window size and its output in Fig. 3

pdf("Rplots.pdf", height=10, width=10)
plt <- corrplot(M.cor,
                method = "color",
                type = "upper",
                tl.col = 'black',
                diag = TRUE,
                p.mat = p.mat,
                sig.level = 0.0000005
               )
cb(plt, x=c(10, 7, 5), y=c(1, 3, 4), rectArgs=list(border="red", lwd=3))
dev.off()

R: 3.3.1
OS: Debian 8.5
Docs corrplot: here

回答1:

My proposal where still pseudocode mark.ids. I found best to have plt and mark.ids as the options of corrplotCellBorders which creates corrplot with bordered wanted cells

mark.ids <- {x <- c(1), y <- c(2)} # TODO pseudocode
corrplotCellBorders(plt, mark.ids)
cb(plt, x, y, rectArgs=list(border="red", lwd=3))

# Chat of https://stackoverflow.com/q/40538304/54964 user20650
# createBorders.r, test.createBorders. 
cb <- function(corrPlot, ..., rectArgs = list() ){ 
# ... pass named vector of x and y names 
# for upper x > y, lower x < y 
  lst <- list(...) 

  n <- ncol(corrPlot) 
  nms <- colnames(corrPlot) 
  colnames(corrPlot) <- if(is.null(nms)) 1:ncol(corrPlot) else nms 

  xleft <- match(lst$x, colnames(corrPlot)) - 0.5 
  ybottom <- n - match(lst$y, colnames(corrPlot)) + 0.5 

  lst <- list(xleft=xleft, ybottom=ybottom, xright=xleft+1, ytop=ybottom+1) 
  do.call(rect, c(lst, rectArgs)) 
}

corrplotCellBorders <- function(plt, mark.ids) {
  x <- mark.ids$x
  y <- mark.ids$y
  cb(plt, x, y, rectArgs=list(border="red", lwd=3))
}

Open

  • How to create mark.ids such that you can call its items by mark.ids$x and mark.ids$y?
  • Integrate point order neutrality for the upper triangle here