[R] mult.fig() utility [was "margin text mtext"]

Martin Maechler maechler at stat.math.ethz.ch
Mon Jun 11 08:54:44 CEST 2001


>>>>> "Paul" == Paul Murrell <paul at stat.auckland.ac.nz> writes:

    Paul> Hi
    >> Fiddling around with "mar" and "mtext" I got stuck:
    >> 
    >> plot.pcaX <- function(tit,lab) {
    >>  on.exit(par(oldpar <- par(oma=c(4, 2, 4, 2), mar = c(4, 4, 2, 1)))) # ??
    >>  split.screen(figs=c(3,3))
    >>  for (i in 1:9) {screen(i);  plot(rnorm(100),rnorm(100)) }
    >>  mtext(tit, side = 3, line = 1, outer = TRUE, cex = 1.5, adj = 0.5)
    >>  mtext(paste(lab,", ", date()),side = 1,line=0,outer=TRUE,cex=0.5,adj=1)
    >>  close.screen(all=T)
    >> }
    >> 
    >> plot.pcaX("test","test.ps")
    >> 
    >> The plots are arranged without any margins, and "test" and "test.ps" will
    >> not be printed on the plot.


    Paul> A couple of things ...

    Paul> (i) the code within on.exit() is not executed until the function
    Paul> exits which is why your margins are not affected during the
    Paul> function call

    Paul> (ii) you should probably be using par(mfrow) instead of screen()
    Paul> et al A suggested modification of your function is:

    Paul> plot.pcaX <- function(tit,lab) {
    Paul>   oldpar <- par(oma=c(4, 2, 4, 2), mar = c(4, 4, 2, 1)) # ??
    Paul>   on.exit(par(oldpar)) # ??
    Paul>   par(mfrow=c(3,3))
    Paul>   for (i in 1:9) { plot(rnorm(100),rnorm(100)) }
    Paul>   mtext(tit, side = 3, line = 1, outer = TRUE, cex = 1.5, adj = 0.5)
    Paul>   mtext(paste(lab,", ", date()),side = 1,line=0,outer=TRUE,cex=0.5,adj=1)
    Paul> }

    Paul> Hope that helps

Now that this is solved...
The task of setting up a multi-figure plot with a title
(and "fixing" mar a bit) is such a common thing that I had designed a
utility function for the job, ``back in the time of S-plus'' ;-)
and called it  mult.fig().

I (and few people here) have been using it for several years now
and it may be that it'd be worth to be put into one of those ``misc''
packages {{maybe we should rename ``stepfun'' to ``graphmisc'' and
	   add a few things, including the "plotCI" one?}}

Anyway here is the code and the doc:

-------------- next part --------------
mult.fig <-
function(nr.plots, mfrow, mfcol,
         marP = rep(0,4), mgp = c(1.5,.6,0),
         mar = marP + .1 + c(4,4,2,1),
         main = NULL,
         tit.wid = if (is.null(main)) 0 else 1 + 1.5*cex.main,
         quiet = .Device == "postscript",
         cex.main = par("cex.main"),
         col.main = par("col.main"),
         font.main = par("font.main"),
         ...)
{
  ## Purpose: 'MULTiple FIGures' incl. TITLE and other good defaults
  ## -------------------------------------------------------------------------
  ## Arguments: 
  ##             -- Either ONE of the first 3 arguments --
  ## -------------------------------------------------------------------------
  ## Author: Martin Maechler, 1990 (UW, Seattle) -- 1995
  ## -------------------------------------------------------------------------

  use.row <- missing(mfcol)
  if (use.row)
    if (missing(mfrow)) {
      if (missing(nr.plots))
        stop("must either specify 'nr.plots', 'mfrow' or 'mfcol' !")
      else  mfrow <- n2mfrow (nr.plots)
    }
  oma <- c(0, 0, tit.wid, 0)
  old.par <<-
    if(use.row) par(mfrow = mfrow, oma= oma, mar = mar, mgp= mgp)
    else        par(mfcol = mfcol, oma= oma, mar = mar, mgp= mgp)
  if(!quiet) cat("Execute\n\t par(old.par) \n later to restore graphical par\n")
  ##---- now go ahead :
  if(!is.R())
      frame()
  if (!is.null(main)) {# Do title *before* first plot!
      if(is.R()) plot.new()
      mtext(main, side = 3, outer = TRUE,
            line = cex.main, # was tit.wid - 4,
            cex = cex.main,
            font = font.main, col = col.main, ...)
      if(is.R()) par(new=TRUE)# reverse `plot.new()' above
  }
  invisible(list(new.par = par(c("mfrow","mfcol","oma","mar","mgp")),
                 old.par = old.par))
}
-------------- next part --------------
\name{mult.fig}
\alias{mult.fig}
\title{Plot Setup for MULTiple FIGures, incl. Main Title}
\description{
  Easy Setup for plotting multiple figures (in a rectangular layout) on
  one page.  It allows to specify a main title and uses \emph{smart}
  defaults for several \code{\link{par}} calls.
}
\usage{
mult.fig(nr.plots, mfrow, mfcol,
         marP = rep(0, 4),  mgp = c(1.5, 0.6, 0),
         mar = marP + 0.1 + c(4, 4, 2, 1),
         main = NULL,
         tit.wid = if (is.null(main)) 0 else 1 + 1.5*cex.main,
         quiet = .Device == "postscript",
         cex.main = par("cex.main"), \dots)
}
\arguments{
 \item{nr.plots}{integer; the number of plot figures you'll want to draw.}
 \item{mfrow}{\emph{instead} of \code{nr.plots}: integer(2) vector
   giving the rectangular figure layout for \code{\link{par}((mfrow= .)}}.}
 \item{mfcol}{\emph{instead} of \code{nr.plots}: integer(2) vector
   giving the rectangular figure layout for \code{\link{par}((mfcol= .)}}.}
 \item{marP}{numeric(4) vector of figure margins to \emph{add}
   (``\bold{P}lus'') to default \code{mar}, see below.}
 \item{mgp}{argument for \code{\link{par}((mpg= .)}} with a smaller
 default than usual.}
 \item{mar}{argument for \code{\link{par}((mar= .)}} with a smaller
 default than usual, using the \code{marP} argument, see above.}
 \item{main}{character.  The main title to be used for the whole graphic.}
 \item{tit.wid}{numeric; the vertical width to be used for the main title.}
 \item{cex.main}{numeric; the character size to be used for the main title.}
 \item{quiet}{logical; if \code{TRUE}, do \emph{not} write the reminder
   about resetting \code{\link{par}}.}
 \item{\dots}{Further arguments to \code{\link{mtext}} for the main title.}
}
\value{
  A \code{\link{list}} with two components that are lists themselves, a
  subset of \code{\link{par}()},
  \item{new.par}{the current \code{par} settings.}
  \item{old.par}{the \code{par} \emph{before} the call.}
}
\author{Martin Maechler, UW Seattle, 1990.}
\seealso{\code{\link{par}}, \code{\link{layout}}.}
\examples{
mult.fig(5, main= "Sinus Funktionen verschiedener Frequenzen")
x <- seq(0, 1, len = 201)
for (n in 1:5)
  plot(x, sin(n * pi * x), ylab ="", main = paste("n = ",n))
par(old.par)

rr <- mult.fig(mfrow=c(5,1), main= "Sinus Funktionen", cex = 1.5,
               marP = - c(0, 1, 2, 0))
for (n in 1:5)
  plot(x, sin(n * pi * x), type = 'l', col="red", ylab ="")
str(rr)
par(old.par)
## Look at the par setting *AFTER* the above:
str(do.call("par", as.list(names(rr$new.par))))
}
\keyword{hplot}
-------------- next part --------------


Martin Maechler <maechler at stat.math.ethz.ch>	http://stat.ethz.ch/~maechler/
Seminar fuer Statistik, ETH-Zentrum  LEO D10	Leonhardstr. 27
ETH (Federal Inst. Technology)	8092 Zurich	SWITZERLAND
phone: x-41-1-632-3408		fax: ...-1228			<><


More information about the R-help mailing list