From felix at nfrac.org  Fri May 21 02:48:00 2010
From: felix at nfrac.org (Felix Andrews)
Date: Fri, 21 May 2010 10:48:00 +1000
Subject: [Rd] pretty.Date(): changes to axis() methods?
Message-ID: <AANLkTikeI5LoFJRbqgnlvPd1fjDsPKujVfUkIoCADYAs@mail.gmail.com>

Hi all.

pretty() is now generic in R-2.12 and there are new methods for Date
and POSIXt classes.  These methods could potentially be used inside
axis.Date and axis.POSIXt (and Axis methods), although that has not
been decided yet.

The main advantage of the new method is that it is flexible, in the
sense that users can specify the desired number of ticks on an axis.
(e.g. one could easily draw, say, labelled ticks with n = 5, and then
sub-ticks with n = 15).  Of course one can do this manually but
it is not so convenient.

[[ On this issue: I don't use base graphics much, but given how
awkward it is to specify par("xaxp") / par("yaxp"), perhaps a new
axis.Date() should gain arguments 'n' and 'min.n' to pass on to
pretty(). Example given below. ]]

The current version of pretty.Date / pretty.POSIXt gives different
results in some cases to axis.Date / axis.POSIXt: the format strings
for time steps of 1 day, 12 hours and 6 hours are different; and some
different time steps are allowed, such as 10 minutes, 3 hours, 3
months... the full list of possible time steps and their current
default format strings is listed at:
http://svn.r-project.org/R/trunk/src/library/grDevices/R/prettyDate.R
The current axis.Date / axis.POSIXt code, including format strings, is
http://svn.r-project.org/R/trunk/src/library/graphics/R/datetime.R

These settings reflect my personal choices, but are somewhat
arbitrary. I would encourage R-core to make this function their own,
by choosing default format strings and time steps with which they are
comfortable. It could be made more similar to the current axis
methods. E.g. it wouldn't much bother me to remove the "15 mins" time
steps altogether, and a "20 mins" time step could be added.

Here is an example of changing the number of requested ticks on an
axis: (this example does not depend on R 2.12)

source("http://svn.r-project.org/R/trunk/src/library/grDevices/R/prettyDate.R")

times <- as.Date(c("2000-04-02", "2000-06-02"))
devAskNewPage(TRUE)

lapply(c(2,4,6,8,10,20,60), function(n) {
   plot(0:1 ~ times, type = "n", yaxt = "n", ylab = "")
   x <- par("usr")[1:2]
   text(x[1], 0.5, format(times[1]), pos = 4)
   text(x[2], 0.5, format(times[2]), pos = 2)
   text(mean(x), 0.05, "current axis.Date()")
   text(mean(x), 0.95, "proposed new pretty() axis, with")
   text(mean(x), 0.85, paste("n =", n), cex = 1.5)
   ## draw new proposed axis function at top of plot
   timelim <- par("usr")[1:2]
   mostattributes(timelim) <- attributes(times)
   at <- prettyDate(timelim, n = n)
   axis(side = 3, at = at, labels = attr(at, "labels"))
})


Here is a posible modification to axis.Date. As it calls pretty(), it
will only work in R 2.12.

axis.Date <- function(side, x = NA, at, format, labels = TRUE, n = NULL, ...)
{
    mat <- missing(at) || is.null(at)
    if(!mat) x <- as.Date(at) else x <- as.Date(x)
    range <- par("usr")[if(side %%2) 1L:2L else 3:4L]
    range[1L] <- ceiling(range[1L])
    range[2L] <- floor(range[2L])
    class(range) <- "Date"
    ## not sure why we need this (from axis.Date):
    z <- c(range, x[is.finite(x)])
    class(z) <- "Date"
    if (!mat) {
        ## tick mark locations given
        z <- x[is.finite(x)]
        if (missing(format)) format <- ""
    } else {
        ## calculate about 'n' pretty intervals
        if (is.null(n)) {
            is.x <- side %% 2 == 1
            axp <- par(if (is.x) "xaxp" else "yaxp")
            n <- abs(axp[3L])
        }
        z <- pretty(z, n = n)
        if (missing(format) && identical(labels, TRUE))
            labels <- attr(z, "labels")
    }
    keep <- z >= range[1L] & z <= range[2L]
    z <- z[keep]
    z <- sort(unique(z)); class(z) <- "Date"
    if (!is.logical(labels)) labels <- labels[keep]
    else if (identical(labels, TRUE))
	labels <- format.Date(z, format = format)
    else if (identical(labels, FALSE))
	labels <- rep("", length(z)) # suppress labelling of ticks
    axis(side, at = z, labels = labels, ...)
}

Whether to modify axis() methods is up to R-core of course, but I
thought it was worth discussing.

By the way, this new functionality is already included in lattice
0.18-5, which was released with, and depends on, R 2.11.0. (There is
one known issue: the Date method in lattice 0.18-5 can miss a tick at
one end of the axis if your local time zone is not "GMT". Also that
version does not include the new "halfmonth" time step.)

-Felix

-- 
Felix Andrews / ???
Postdoctoral Fellow
Integrated Catchment Assessment and Management (iCAM) Centre
Fenner School of Environment and Society [Bldg 48a]
The Australian National University
Canberra ACT 0200 Australia
M: +61 410 400 963
T: + 61 2 6125 4670
E: felix.andrews at anu.edu.au
CRICOS Provider No. 00120C
-- 
http://www.neurofractal.org/felix/



[Rd] pretty.Date(): changes to axis() methods?
Felix Andrews