Martin Maechler
1998-Jan-13  17:26 UTC
funny axis ranges; GPretty(.) vs. pretty(.) and all that...
[This is something like a bug report;
 maybe somewhat longish & technical ..]
As an introduction, just try the following code
(it should work both in R and S).
I think it screws up the postscript() driver both for S and R, but this is
not the issue here.
is.R <- function() { ## returns  'TRUE'  iff we are using 'R'
  exists("version") && !is.null(vl <- version$language)
&& vl == "R"
}
p.axis.range <- function(k.set = c(-100,-9:-6,-3,3,5,20),
                         y.k.add = 1)
{
  ## Purpose: Plot axis scaling & labeling with funny range(.)
  ## -------------------------------------------------------------------------
  ## Arguments: k.set: (0, 10^k  will be the ranges
  ## -------------------------------------------------------------------------
  ## Author: Martin Maechler, Date: 12 Jan 98, 18:15
  lk <- length(k.set); slk <- ceiling(sqrt(lk))
  op <- par(mfrow=c(slk,slk), mar = .2+c(3,2,1,1), oma=rep(1,4))
  on.exit(par(op))
  ##        oma does not really work
  if(is.R()) { colx <- rainbow(lk); coly <- terrain.colors(lk)
             } else colx <- lk + (coly <- 1:lk)
  for(i in 1:lk) {
    k <- k.set[i]
    if(is.R()) {
      plot.new()
      plot.window(xlim= c(0,10^ k),
                  ylim= c(0,10^(k+y.k.add)),"")
      box(lty='dashed')
    } else { ## S4 and S-plus
      plot.default(0,0,xlim= c(0,10^ k), ylim= c(0,10^(k+1)),
                   type = 'n', xlab='', ylab='')
    }
    cat("\n--------------------------------\n\n",
        "xlim= c(0, 10^", k,")    ==>
par('usr')[1:2]=", par("usr")[1:2],"\n")
    par(col=colx[i]); if(is.R()) axis(1, col.axis= colx[i]) else axis(1)
    mtext(paste("xlim= (0, 10^",k,")",sep=""),	   
line=-4)
    par(col=coly[i]); if(is.R()) axis(2, col.axis= coly[i]) else axis(2)
    mtext(paste("ylim= 10^",y.k.add," *
xlim",sep=""), line=-6)
    par(col=if(is.R())'black' else 1)
    mtext(paste("par(\"usr\")= 10 ^", k," *"),
line= -9, cex= .4)
    mtext(paste(format(par("usr")*10^-k),collapse=",  "),
line= -11, cex= .3)
  }
  invisible(NULL)
}
p.axis.range()
##-----------------------------------------------------------------------------
##>> Now, what's going on? [in R, don't know for S; this all
hidden in
##>> 			calls such as 
##>> 			.Internal(.Cur.picture(), "S_cur_pic", T, 1) ]
## The main problem is  GPretty() in  $RHOME/src/graphics/graphics.c !
##R: plot.default()  -->   plot.new();  plot.window(xlim, ylim, log)
##C: 1:  do_plot_window()   in  $RHOME/src/main/plot.c
##		checks its arguments and then
##		GCheckState(); GScale(xmin, xmax, 1); GScale(ymin, ymax, 2);
##   2:  GScale(.)	    in $RHOME/src/graphics/graphics.c
##		checks args; sets up 'xmin', 'xmax' depending on
'log',..axt'
##		then  GPretty(&xmin, &xmax, &n);
##		      ~~~~~~~
##		and puts its result  in  GP->[x/y]axp  -- i.e. par("xaxp") or
y.
##   3:  GPretty(.)   [also in ...graphics.c  is SIMILAR to but different from
##		       		$RHOME/src/appl/pretty.c
##		       which is called from
##		       		$RHOME/src/library/base/R/pretty
##	uses  FLT_EPSILON  (/usr/include/float.h)  in 3 places, where the above
##	pretty(.)  uses FLT_EPSILON only once ...
##
## Why use it at all (the way it is done)?
##
## S-plus's  pretty(.) is quite different;   also the  p.axis.range(.)
below:
## ---> Comparison of  pretty(.) and Gpretty(.)  : see below.
So it's the  FLT_EPSILON which is about 1e-7,
and leads to the funny  -1e-7, +1e-7  axis ranges.
%%>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>
%%>=>  Questions/Remarks						     %%
%%>=>  									     %%
%%>=>  1) Why (and how if..) should GPretty(.) be different from pretty?  
%%
%%>=>  									     %%
%%>=>  2) Couldn't we at least replace FLT_EPSILON  by DOUBLE_EPSILON
?	     %%
%%>=>  									     %%
%%>=>  3) axis(.) still has another bug: it draws the line and writes
labels %%
%%>=>  	   OUTSIDE the "usr" coordinates.				     %%
%%>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>
###------ Try the following code to find out about the differences
###------ of the 2 versions of  pretty(.) : ------------------------
Cpretty <- Cpretty1 <- function (x, n = 5)
  unlist(.C("pretty", l = min(x), u = max(x), n = as.integer(n)))
Cpretty2 <- function (x, n = 5) {
  ##-- return what  .C("pretty... doe
  n <- length(p <- pretty(x,n))
  c(l=p[1], u=p[n], n=n-1)
}
Cpretty(pi)
all(Cpretty1(pi) == Cpretty2(pi))
all(Cpretty1(c(0,pi)) == Cpretty2(c(0,pi)))
for(i in 1:100) {
  x_c(runif(1),pi)
  for(k in -14:14) {
    ok <- all(Cpretty1(x*10^k) == Cpretty2(x*10^k))
    if(!ok) cat("NOT ok:  x=",deparse(x),"
k=",k,"\n")
  }
}
Gpretty <- function (x, n = 5)
{
  plot.new(); op <- par(); on.exit(par(op))
  par(lab=c(n, par("lab")[-1]))
  plot.window(xlim=c(min(x),max(x)), ylim=0:1, "")
  par("xaxp")
}
##--- Gpretty() and Cpretty() are DIFFERENT much more than the same !!! -------
vcat <- function(vec, sep = " ", dig=2)
  paste(formatC(vec, dig=dig), collapse = sep)
show.ok <- TRUE
show.nok <- TRUE
show.nok <- !show.ok
for(i in 1:100) {
  x <<- sort(c(runif(1),4*rexp(1)))
  n <- max(1, rpois(1,lam=3))
  cat("\n")
  for(k in -14:14) { cat(".")
    ok <- all((cp <- Cpretty(x*10^k,n=n)) == (gp <-
Gpretty(x*10^k,n=n)))
    if(!ok && show.nok) cat("NOT the same: 
n=",n,"x=",vcat(x)," k=",k,
                "; Cp=",vcat(cp), "
Gp=",vcat(gp),"\n")
    else if(ok && show.ok) cat("the same: 
n=",n,"x=",deparse(x)," k=",k,
                              ";  Cp=Gp=",vcat(cp),"\n")
  }
}
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To:
r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
