Skip to content

Commit bf97b76

Browse files
authored
Merge pull request #167 from taiyun/col_interval
adjust assign-color algorithm
2 parents a87243c + dde56e5 commit bf97b76

5 files changed

Lines changed: 186 additions & 100 deletions

File tree

R/corrplot.R

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,19 @@
2727
#' otherwise a new plot is created.
2828
#'
2929
#' @param col Vector, the color of glyphs. It is distributed uniformly in
30-
#' \code{cl.lim}. If NULL, \code{col} will be
30+
#' \code{cl.lim} interval. If NULL, \code{col} will be
3131
#' \code{colorRampPalette(col2)(200)}, see example about col2.
3232
#'
33+
#' @param cl.lim The limits \code{(x1, x2)} interval for assigning color by
34+
#' \code{col}. If \code{NULL},
35+
#' \code{cl.lim} will be \code{c(-1, 1)} when \code{is.corr} is \code{TRUE}, .
36+
#' \code{cl.lim} will be \code{c(min(corr), max(corr))} when \code{is.corr}
37+
#' is \code{FALSE}
38+
#'
39+
#' NOTICE: if you set \code{cl.lim} when \code{is.corr TRUE}, the assigning color
40+
#' method is still distributed uniformly in [-1, 1], it only affect the display
41+
#' on colorlegend.
42+
#'
3343
#'
3444
#' @param bg The background color.
3545
#'
@@ -107,8 +117,6 @@
107117
#' \code{"full"}), \code{"b"} (default if \code{type=="lower"}) or \code{"n"},
108118
#' \code{"n"} means don't draw colorlabel.
109119
#'
110-
#' @param cl.lim The limits \code{(x1, x2)} in the colorlabel.
111-
#'
112120
#' @param cl.length Integer, the number of number-text in colorlabel, passed to
113121
#' \code{\link{colorlegend}}. If \code{NULL}, \code{cl.length} is
114122
#' \code{length(col) + 1} when \code{length(col) <=20}; \code{cl.length} is 11
@@ -241,7 +249,7 @@
241249
corrplot <- function(corr,
242250
method = c("circle", "square", "ellipse", "number", "shade", "color", "pie"),
243251
type = c("full", "lower", "upper"), add = FALSE,
244-
col = NULL, bg = "white", title = "", is.corr = TRUE,
252+
col = NULL, cl.lim = NULL, bg = "white", title = "", is.corr = TRUE,
245253
diag = TRUE, outline = FALSE, mar = c(0, 0, 0, 0),
246254
addgrid.col = NULL, addCoef.col = NULL, addCoefasPercent = FALSE,
247255

@@ -253,9 +261,8 @@ corrplot <- function(corr,
253261
tl.pos = NULL, tl.cex = 1,
254262
tl.col = "red", tl.offset = 0.4, tl.srt = 90,
255263

256-
cl.pos = NULL, cl.lim = NULL,
257-
cl.length = NULL, cl.cex = 0.8, cl.ratio = 0.15,
258-
cl.align.text = "c", cl.offset = 0.5,
264+
cl.pos = NULL, cl.length = NULL, cl.cex = 0.8,
265+
cl.ratio = 0.15, cl.align.text = "c", cl.offset = 0.5,
259266

260267
number.cex = 1, number.font = 2, number.digits = NULL,
261268

@@ -282,6 +289,8 @@ corrplot <- function(corr,
282289
insig <- match.arg(insig)
283290
plotCI <- match.arg(plotCI)
284291

292+
293+
285294
# rescale symbols within the corrplot based on win.asp parameter
286295
if (win.asp != 1 && !(method %in% c("circle", "square"))) {
287296
stop("Parameter 'win.asp' is supported only for circle and square methods.")
@@ -304,25 +313,45 @@ corrplot <- function(corr,
304313
stop("color limits should cover matrix")
305314
}
306315

316+
307317
if (is.null(cl.lim)) {
308318
if (is.corr) {
309319
# if the matrix is expected to be a correlation matrix
310320
# it MUST be within the interval [-1,1]
311-
cl.lim <- c(-1,1)
321+
cl.lim <- c(-1, 1)
312322
} else {
313323
# Issue #91
314324
# if not a correlation matrix and the diagonal is hidden,
315325
# we need to compute limits from all cells except the diagonal
316-
corr_tmp <- corr
317-
diag(corr_tmp) <- ifelse(
318-
rep(diag, length(diag(corr_tmp))),
319-
diag(corr_tmp),
320-
NA
321-
)
322-
cl.lim <- c(min(corr_tmp, na.rm = TRUE), max(corr_tmp, na.rm = TRUE))
326+
327+
if(!diag) {
328+
diag(corr) = NA
329+
}
330+
331+
cl.lim <- c(min(corr, na.rm = TRUE), max(corr, na.rm = TRUE))
332+
}
333+
}
334+
335+
# if the mat have both negative and positive values, it is a SpecialCorr
336+
SpecialCorr = 0
337+
338+
if(is.corr) {
339+
# check the interval if expecting a correlation matrix
340+
# otherwise, the values can be any number
341+
if (min(corr, na.rm = TRUE) < -1 - .Machine$double.eps ^ .75 ||
342+
max(corr, na.rm = TRUE) > 1 + .Machine$double.eps ^ .75 ) {
343+
stop("The matrix is not in [-1, 1]!")
344+
}
345+
346+
347+
SpecialCorr = 1
348+
349+
if(cl.lim[1] < -1 | cl.lim[2] > 1) {
350+
stop('cl.lim should be within the interval [-1,1]')
323351
}
324352
}
325353

354+
326355
intercept <- 0
327356
zoom <- 1
328357

@@ -331,46 +360,41 @@ corrplot <- function(corr,
331360
c_max <- max(corr, na.rm = TRUE)
332361
c_min <- min(corr, na.rm = TRUE)
333362

334-
# The following if-elseif-else code should exhaustively cover all 9
335-
# combinations of c_min and c_max variables. Each variable can be either
336-
# zero (0), positive (+) or negative (-).
337-
338-
# c_min c_max
339-
340-
# 00
341-
# -0
342-
# +0
343-
# --
344-
# 0-
345-
if (c_max <= 0) {
346-
intercept <- -cl.lim[2]
347-
zoom <- 1 / (diff(cl.lim))
363+
if(diff(cl.lim)/(c_max - c_min)> 2) {
364+
warning("cl.lim interval too wide, please set a suitable value")
348365
}
349366

350-
# ++
351-
# +-
352-
# 0+
353-
else if (c_min >= 0) {
354-
intercept <- -cl.lim[1]
367+
# all negative or positive, trans to [0, 1]
368+
if (c_max <= 0 | c_min>=0) {
369+
intercept <- -c_min
355370
zoom <- 1 / (diff(cl.lim))
371+
372+
373+
if(cl.lim[1] * cl.lim[2] < 0) {
374+
warning("cl.lim interval not suitable to the matrix")
375+
}
376+
356377
}
357378

358-
# -+
379+
380+
# mixed negative and positive, remain its sign, e.g. [-0.8, 1] or [-1, 0.7]
359381
else {
360382

361383
# expression from the original code as a sanity check
362384
stopifnot(c_max * c_min < 0)
363-
364-
# newly derived expression which covers the single remainig case
385+
# newly derived expression which covers the single remaining case
365386
stopifnot(c_min < 0 && c_max > 0)
366387

388+
389+
367390
intercept <- 0
368391
zoom <- 1 / max(abs(cl.lim))
392+
SpecialCorr <- 1
369393
}
370394

371-
# now, the zoom might still be Inf when cl.lim were both zero
395+
# now, the zoom might still be Inf when c_max and c_min were both zero
372396
if (zoom == Inf) {
373-
stopifnot(cl.lim[1] == 0 && cl.lim[2] == 0) # check the assumption
397+
stopifnot(c_max == 0 && c_min == 0) # check the assumption
374398
zoom <- 0
375399
}
376400

@@ -380,14 +404,7 @@ corrplot <- function(corr,
380404
cl.lim2 <- (intercept + cl.lim) * zoom
381405
int <- intercept * zoom
382406

383-
if (is.corr) {
384-
# check the interval if expecting a correlation matrix
385-
# otherwise, the values can be any number
386-
if (min(corr, na.rm = TRUE) < -1 - .Machine$double.eps ^ .75 ||
387-
max(corr, na.rm = TRUE) > 1 + .Machine$double.eps ^ .75 ) {
388-
stop("The matrix is not in [-1, 1]!")
389-
}
390-
}
407+
391408

392409
if (is.null(col)) {
393410
col <- colorRampPalette(c("#67001F", "#B2182B", "#D6604D", "#F4A582",
@@ -494,8 +511,14 @@ corrplot <- function(corr,
494511

495512

496513
## assign colors
497-
assign.color <- function(dat = DAT, color = col) {
498-
newcorr <- (dat + 1) / 2
514+
assign.color <- function(dat = DAT, color = col, isSpecialCorr = SpecialCorr) {
515+
516+
if(isSpecialCorr) {
517+
newcorr <- (dat + 1) / 2
518+
} else {
519+
newcorr <- dat
520+
}
521+
499522
newcorr[newcorr <= 0] <- 0
500523
newcorr[newcorr >= 1] <- 1 - 1e-16
501524
color[floor(newcorr * length(color)) + 1] # new color returned
@@ -889,6 +912,8 @@ corrplot <- function(corr,
889912
### color legend
890913
if (cl.pos != "n") {
891914
colRange <- assign.color(dat = cl.lim2)
915+
916+
892917
ind1 <- which(col == colRange[1])
893918
ind2 <- which(col == colRange[2])
894919
colbar <- col[ind1:ind2]

man/corrplot.Rd

Lines changed: 41 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-corrplot.R

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,7 @@ test_that("Issue #7: Enable to plot a matrix with NA", {
6767
expect_equal(corrplot(M), M)
6868
})
6969

70-
test_that("Issue #70: Enable to plot a matrix with NA when 'is.corr = FALSE'", {
71-
M <- matrix(0, ncol = 5, nrow = 5)
72-
M[1,1] <- NA
73-
expect_true(is.matrix(corrplot(M, is.corr = FALSE)))
74-
})
70+
7571

7672
test_that("Issue #20: plotmath expressions in rownames / colnames", {
7773
M <- cor(mtcars)[1:5,1:5]

0 commit comments

Comments
 (0)