From Achim.Zeileis at uibk.ac.at  Thu May 13 22:18:26 2010
From: Achim.Zeileis at uibk.ac.at (Achim Zeileis)
Date: Thu, 13 May 2010 22:18:26 +0200 (CEST)
Subject: [Rd] cdplot() with 'POSIXct' x
In-Reply-To: <8739xv642v.fsf@kolob.sebmags.homelinux.org>
References: <8739xv642v.fsf@kolob.sebmags.homelinux.org>
Message-ID: <alpine.DEB.2.00.1005132208160.4063@paninaro.uibk.ac.at>

On Thu, 13 May 2010, Sebastian P. Luque wrote:

> Hi,
>
> Given that cdplot() is used to produce the conditional density of a
> categorical y along a numerical x, it seems natural that it could be
> used with a date or time x (such as 'POSIXct').  Is this desirable?  If
> so, I've created a patch that would allow this, by coercing the POSIXct
> x variable to produce the density, but use the original POSIXct x to
> draw the x axis.

I don't think we should special case "POSIXct". The general question would 
be whether we allow "x" variables that can be coerced to numeric. The 
approach would be:
   - Omit all checking of the original "x".
   - Compute
       xorig <- x
       x <- as.numeric(xorig)
     and then proceed as before except for one change.
   - For drawing the axis use
       Axis(xorig, side = 1)
     rather than axis(1).

This would work for POSIXct, Date, and other classes of the same type, 
e.g., yearmon in package "zoo". Also, we could easily write time series 
methods for cdplot() and spineplot() in package "zoo".

The downside is that there is no more checking of the "x" argument and 
weird things could happen without a useful error message when users 
specify awkward x arguments.

I played around with modified versions of cdplot() and also spineplot() 
(where the new labeling is a bit more involved but based on the same 
principles) and could supply code/docs for both.

So the question is whether the more flexible code with reduced checking is 
suitable/acceptable for base R or not.

Best,
Z

>
> Index: src/library/graphics/R/cdplot.R
> ===================================================================
> --- src/library/graphics/R/cdplot.R	(revision 51984)
> +++ src/library/graphics/R/cdplot.R	(working copy)
> @@ -43,8 +43,8 @@
>     if(!is.null(ylevels))
>       y <- factor(y, levels = if(is.numeric(ylevels)) levels(y)[ylevels] else ylevels)
>     x <- mf[,2]
> -    if(!is.numeric(x))
> -        stop("explanatory variable should be numeric")
> +    if (!(is.numeric(x) || is(x, "POSIXct")))
> +        stop("explanatory variable should be numeric or POSIXct")
>
>     ## graphical parameters
>     if(is.null(xlab)) xlab <- names(mf)[2L]
> @@ -66,7 +66,8 @@
>          yaxlabels = NULL, xlim = NULL, ylim = c(0, 1), ...)
> {
>     ## check x and y
> -    if(!is.numeric(x)) stop("explanatory variable should be numeric")
> +    if (!(is.numeric(x) || is(x, "POSIXct")))
> +        stop("explanatory variable should be numeric or POSIXct")
>     if(!is.factor(y)) stop("dependent variable should be a factor")
>     if(!is.null(ylevels))
>       y <- factor(y, levels = if(is.numeric(ylevels)) levels(y)[ylevels] else ylevels)
> @@ -79,10 +80,12 @@
>     if(is.null(yaxlabels)) yaxlabels <- levels(y)
>
>     ## unconditional density of x
> -    dx <- if(is.null(from) & is.null(to))
> -        stats::density(x, bw = bw, n = n, ...)
> -    else
> -        stats::density(x, bw = bw, from = from, to = to, n = n, ...)
> +    xnum <- as.numeric(x)
> +    dx <- if (is.null(from) & is.null(to)) {
> +        stats::density(xnum, bw = bw, n = n, ...)
> +    } else {
> +        stats::density(xnum, bw = bw, from = from, to = to, n = n, ...)
> +    }
>     x1 <- dx$x
>
>     ## setup conditional values
> @@ -94,7 +97,7 @@
>     rval <- list()
>
>     for(i in seq_len(ny-1L)) {
> -        dxi <- stats::density(x[y %in% levels(y)[seq_len(i)]], bw = dx$bw, n = n,
> +        dxi <- stats::density(xnum[y %in% levels(y)[seq_len(i)]], bw = dx$bw, n = n,
>                               from = min(dx$x), to = max(dx$x), ...)
>         y1[i,] <- dxi$y/dx$y * yprop[i]
>         rval[[i]] <- stats::approxfun(x1, y1[i,], rule = 2)
> @@ -103,8 +106,8 @@
>
>     ## use known ranges
>     y1 <- rbind(0, y1, 1)
> -    y1 <- y1[,which(x1 >= min(x) & x1 <= max(x))]
> -    x1 <- x1[x1 >= min(x) & x1 <= max(x)]
> +    y1 <- y1[,which(x1 >= min(xnum) & x1 <= max(xnum))]
> +    x1 <- x1[x1 >= min(xnum) & x1 <= max(xnum)]
>
>     if(is.null(xlim)) xlim <- range(x1)
>     if(any(ylim < 0) || any(ylim > 1)) {
> @@ -120,7 +123,9 @@
>         for(i in seq_len(NROW(y1)-1))
>             polygon(c(x1, rev(x1)), c(y1[i+1,], rev(y1[i,])), col = col[i],
>                     border = border)
> -        axis(1)
> +        if (is(x, "POSIXct")) {
> +            axis.POSIXct(1, x)
> +        } else axis(1)
>
>         equidist <- any(diff(y1[,1L]) < tol.ylab)
>         if(equidist)
>
>
> -- 
> Seb
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>



[Rd] cdplot() with 'POSIXct' x
Achim Zeileis