[R] verInd= and HorInd= arguments to pairs() function

Martin Maechler m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Fri Jun 8 11:13:24 CEST 2018


>>>>> Martin Maechler 
>>>>>     on Thu, 7 Jun 2018 18:35:48 +0200 writes:

>>>>> Gerrit Eichner 
>>>>>     on Thu, 7 Jun 2018 09:03:46 +0200 writes:

    >> Hi, Chris, had the same problem (and first thought it was
    >> my fault), but there seems to be a typo in the code of
    >> pairs.default. Below is a workaround.  Look for two
    >> comments (starting with #####) in the code to see what I
    >> have changed to make it work at least the way I'd expect
    >> it in one of your examples.

    >> Hth -- Gerrit


> > mypairs <- function (x, labels, panel = points, ...,
> >      horInd = 1:nc, verInd = 1:nc,
> >      lower.panel = panel, upper.panel = panel, diag.panel = NULL,
> >      text.panel = textPanel, label.pos = 0.5 + has.diag/3, line.main = 3,
> >      cex.labels = NULL, font.labels = 1, row1attop = TRUE, gap = 1,
> >      log = "") {
> >      if (doText <- missing(text.panel) || is.function(text.panel))
> >          textPanel <- function(x = 0.5, y = 0.5, txt, cex, font) text(x,
> >              y, txt, cex = cex, font = font)
> >      localAxis <- function(side, x, y, xpd, bg, col = NULL, main,
> >          oma, ...) {
> >          xpd <- NA
> >          if (side%%2L == 1L && xl[j])
> >              xpd <- FALSE
> >          if (side%%2L == 0L && yl[i])
> >              xpd <- FALSE
> >          if (side%%2L == 1L)
> >              Axis(x, side = side, xpd = xpd, ...)
> >          else Axis(y, side = side, xpd = xpd, ...)
> >      }
> >      localPlot <- function(..., main, oma, font.main, cex.main) plot(...)
> >      localLowerPanel <- function(..., main, oma, font.main, cex.main) lower.panel(...)
> >      localUpperPanel <- function(..., main, oma, font.main, cex.main) upper.panel(...)
> >      localDiagPanel <- function(..., main, oma, font.main, cex.main) diag.panel(...)
> >      dots <- list(...)
> >      nmdots <- names(dots)
> >      if (!is.matrix(x)) {
> >          x <- as.data.frame(x)
> >          for (i in seq_along(names(x))) {
> >              if (is.factor(x[[i]]) || is.logical(x[[i]]))
> >                  x[[i]] <- as.numeric(x[[i]])
> >              if (!is.numeric(unclass(x[[i]])))
> >                  stop("non-numeric argument to 'pairs'")
> >          }
> >      }
> >      else if (!is.numeric(x))
> >          stop("non-numeric argument to 'pairs'")
> >      panel <- match.fun(panel)
> >      if ((has.lower <- !is.null(lower.panel)) && !missing(lower.panel))
> >          lower.panel <- match.fun(lower.panel)
> >      if ((has.upper <- !is.null(upper.panel)) && !missing(upper.panel))
> >          upper.panel <- match.fun(upper.panel)
> >      if ((has.diag <- !is.null(diag.panel)) && !missing(diag.panel))
> >          diag.panel <- match.fun(diag.panel)
> >      if (row1attop) {
> >          tmp <- lower.panel
> >          lower.panel <- upper.panel
> >          upper.panel <- tmp
> >          tmp <- has.lower
> >          has.lower <- has.upper
> >          has.upper <- tmp
> >      }
> >      nc <- ncol(x)
> >      if (nc < 2L)
> >          stop("only one column in the argument to 'pairs'")
> >      if (!all(horInd >= 1L && horInd <= nc))
> >          stop("invalid argument 'horInd'")
> >      if (!all(verInd >= 1L && verInd <= nc))
> >          stop("invalid argument 'verInd'")
> >      if (doText) {
> >          if (missing(labels)) {
> >              labels <- colnames(x)
> >              if (is.null(labels))
> >                  labels <- paste("var", 1L:nc)
> >          }
> >          else if (is.null(labels))
> >              doText <- FALSE
> >      }
> >      oma <- if ("oma" %in% nmdots)
> >          dots$oma
> >      main <- if ("main" %in% nmdots)
> >          dots$main
> >      if (is.null(oma))
> >          oma <- c(4, 4, if (!is.null(main)) 6 else 4, 4)
> >      opar <- par(mfcol = c(length(horInd), length(verInd)),
> > ##### Changed from mfrow to mfcol
> >                  mar = rep.int(gap/2, 4), oma = oma)
> >      on.exit(par(opar))
> >      dev.hold()
> >      on.exit(dev.flush(), add = TRUE)
> >      xl <- yl <- logical(nc)
> >      if (is.numeric(log))
> >          xl[log] <- yl[log] <- TRUE
> >      else {
> >          xl[] <- grepl("x", log)
> >          yl[] <- grepl("y", log)
> >      }
> >      for (j in if (row1attop) verInd else rev(verInd))
> >       for (i in horInd) {
> > ##### Exchanged i and j. (i used to be in
> > ##### the outer and j in the inner loop!)
> >          l <- paste0(ifelse(xl[j], "x", ""), ifelse(yl[i], "y", ""))
> >          localPlot(x[, j], x[, i], xlab = "", ylab = "", axes = FALSE,
> >              type = "n", ..., log = l)
> >          if (i == j || (i < j && has.lower) || (i > j && has.upper)) {
> >              box()
> >              if (i == 1 && (!(j%%2L) || !has.upper || !has.lower))
> >                  localAxis(1L + 2L * row1attop, x[, j], x[, i],
> >                    ...)
> >              if (i == nc && (j%%2L || !has.upper || !has.lower))
> >                  localAxis(3L - 2L * row1attop, x[, j], x[, i],
> >                    ...)
> >              if (j == 1 && (!(i%%2L) || !has.upper || !has.lower))
> >                  localAxis(2L, x[, j], x[, i], ...)
> >              if (j == nc && (i%%2L || !has.upper || !has.lower))
> >                  localAxis(4L, x[, j], x[, i], ...)
> >              mfg <- par("mfg")
> >              if (i == j) {
> >                  if (has.diag)
> >                    localDiagPanel(as.vector(x[, i]), ...)
> >                  if (doText) {
> >                    par(usr = c(0, 1, 0, 1))
> >                    if (is.null(cex.labels)) {
> >                      l.wid <- strwidth(labels, "user")
> >                      cex.labels <- max(0.8, min(2, 0.9/max(l.wid)))
> >                    }
> >                    xlp <- if (xl[i])
> >                      10^0.5
> >                    else 0.5
> >                    ylp <- if (yl[j])
> >                      10^label.pos
> >                    else label.pos
> >                    text.panel(xlp, ylp, labels[i], cex = cex.labels,
> >                      font = font.labels)
> >                  }
> >              }
> >              else if (i < j)
> >                  localLowerPanel(as.vector(x[, j]), as.vector(x[,
> >                    i]), ...)
> >              else localUpperPanel(as.vector(x[, j]), as.vector(x[,
> >                  i]), ...)
> >              if (any(par("mfg") != mfg))
> >                  stop("the 'panel' function made a new plot")
> >          }
> >          else par(new = FALSE)
> >      }
> >      if (!is.null(main)) {
> >          font.main <- if ("font.main" %in% nmdots)
> >              dots$font.main
> >          else par("font.main")
> >          cex.main <- if ("cex.main" %in% nmdots)
> >              dots$cex.main
> >          else par("cex.main")
> >          mtext(main, 3, line.main, outer = TRUE, at = 0.5, cex = cex.main,
> >              font = font.main)
> >      }
> >      invisible(NULL)
> > }
> > 
> > 
> > 
> > ## Example:
> > 
> > mypairs(xmat, xlim=lim, ylim=lim, verInd=1:2, horInd=1:4)
> 
> Thank you, Chris, for the report and
> Gerrit for your proposed fix !!
> 
> It looks good to me,  but I will test some more (also with
> 'row1attop=FALSE')  before committing the bug fix.

and there, another change was needed:  Instead of your

    for (j in if (row1attop) verInd else rev(verInd))
        for (i in horInd) {

we do now need

    for(j in verInd)
        for(i in if(row1attop) horInd else rev(horInd)) {

and the difference is of course only relevant for the
non-default  'row1attop = FALSE'

  (which some graphic experts argue to be clearly *better* than the default,
   as only in that case,  the upper and lower triangles of the
   matrix are nicely "mirrors of each other", and that is also
   the reason why  lattice::splom()  uses the equivalent of
   'row1attop=FALSE')

I will commit the change to R-devel today - and intend to port
to R-patched in time to make it into the upcoming R 3.5.1.

Thank you once more !
Martin




More information about the R-help mailing list