Home > database >  Difference between "as.numeric" and "as.POSIXct.numeric" (only the first seems t
Difference between "as.numeric" and "as.POSIXct.numeric" (only the first seems t

Time:06-21

I am struggling with as.POSIXct.numeric. The following code works:

dates <- structure(c(1649285787, 1651134684), class = c("POSIXct", "POSIXt"), 
                   tzone = "UTC")
lims <- as.numeric(dates)
limits <- as.POSIXct.numeric(lims, origin = as.POSIXct("1970-01-01", tz = "UTC"))
plot(stepfun(x = dates, # OK
             y = c(0, 1, 2)),
     do.points = FALSE)
plot(stepfun(x = dates, # OK 
             y = c(0, 1, 2)),
     do.points = FALSE, 
     xlim = lims)

However, the following fails and I don't understand why (I need to specify the limits):

plot(stepfun(x = dates, # Not OK
             y = c(0, 1, 2)),
     do.points = FALSE, 
     xlim = dates)
# Error in as.POSIXct.numeric(e) : 'origin' must be supplied
plot(stepfun(x = dates, # Not OK
             y = c(0, 1, 2)),
     do.points = FALSE, 
     xlim = limits)
# Error in as.POSIXct.numeric(e) : 'origin' must be supplied

Does anybody understand this behavior? I explicitly specified the origin in as.POSIXct.numeric(lims, origin = ...)!

CodePudding user response:

The reason why the first chunk works is because stepfun(x = dates, y = c(0, 1, 2)) returns an object of class "stepfun" (you can check it by running class(stepfun(x = dates, y = c(0, 1, 2)))) and the plot method for stepfun objects will make a plot setting the X and Y axis as numerical. In other words, your first chunk works because the xlim was set as numerical (which is what plot method for stepfun objects expects). Conversely, when you set the xlim with a POSIX vector (dates or limits), the plot method simply does not what to do with them because it is expecting a numeric vector.

If you need to change the axis labels, I suggest doing it externaly as follows:

plot(stepfun(x = dates, 
             y = c(0, 1, 2)),
     do.points = FALSE, 
     xlim = lims, axes = FALSE)

xLabels <- pretty(limits)
axis(side = 1, at = as.numeric(xLabels), labels = xLabels)
axis(side = 2)
box()

pretty function is just a quickly way to find out vector of "pretty" (rounded) break points, but can use another way to set that values.

CodePudding user response:

We might try to hack the plot.stepfun function by doing some date conversion stuff from line 30 on. More specifically we convert the xlim= in "POSIXt" format to a sequence of dates and use it in line 63 as values for the axis.

plot_stepfun <- function(x, xval, xlim, ylim=range(c(y, Fn.kn)), xlab="x", 
                         ylab="f(x)", main=NULL, add=FALSE, verticals=TRUE, 
                         do.points=(n < 1000), pch=par("pch"), col=par("col"), 
                         col.points=col, cex.points=par("cex"), col.hor=col, 
                         col.vert=col, lty=par("lty"), lwd=par("lwd"), ...) {
  if (!is.stepfun(x)) {
    if (is.numeric(x)) {
      sarg <- substitute(x)
      x <- ecdf(x)
      attr(x, "call") <- call("ecdf", sarg)
    }
    else stop("'plot.stepfun' called with wrong type of argument 'x'")
  }
  if (missing(main)) {
    cl <- attr(x, "call")
    main <- if (is.null(cl)) sys.call() else cl
  }
  knF <- knots(x)
  xval <- if (missing(xval)) 
    knF
  else sort(xval)
  if (missing(xlim)) {
    rx <- range(xval)
    dr <- if (length(xval) > 1L) 
      max(0.08 * diff(rx), median(diff(xval)))
    else abs(xval)/16
    xlim <- rx   dr * c(-1, 1)
  }
  else {
    xlim1 <- xlim
    xlim <- as.numeric(xlim)
    if (inherits(xlim1, c('Date', "POSIXt"))) {
      tz <- attributes(as.POSIXlt(xlim1))$tzone
      xlim2 <- as.POSIXct(paste(strftime(xlim1, '%F')), tz=tz[length(tz)])
      if (as.numeric(difftime(xlim2[2], xlim2[1], units='secs')) < 86400) {
        stop('will be implemented soon :)')
      } else {
        xseq <- seq.POSIXt(xlim2[1], xlim2[2], by='days')
        if (length(xseq) > 6) {
          xseq <- xseq[(seq_along(xseq) - 5) %% ceiling(length(xseq)/6) == 0]
        }
      }
    }
    dr <- diff(xlim)
  }
  xval <- xval[xlim[1L] - dr <= xval & xval <= xlim[2L]   dr]
  ti <- c(xlim[1L] - dr, xval, xlim[2L]   dr)
  ti.l <- ti[-length(ti)]
  ti.r <- ti[-1L]
  y <- x(0.5 * (ti.l   ti.r))
  n <- length(y)
  Fn.kn <- x(xval)
  dev.hold()
  on.exit(dev.flush())
  if (add) 
    segments(ti.l, y, ti.r, y, col=col.hor, lty=lty, 
             lwd=lwd, ...)
  else {
    if (missing(ylim)) 
      ylim <- range(c(y, Fn.kn))
    plot(NA, NA, type="n", xlim=xlim, ylim=ylim, xlab=xlab, 
         ylab=ylab, main=main, xaxt='n', ...)
    if (exists('xseq')) {
      axis(1, xseq, xseq)
    } else {
      axis(1, at=axTicks(1), labels=axTicks(1))
    }
    segments(ti.l, y, ti.r, y, col=col.hor, lty=lty, 
             lwd=lwd)
  }
  if (do.points) 
    points(xval, Fn.kn, pch=pch, col=col.points, cex=cex.points)
  if (verticals) 
    segments(xval, y[-n], xval, y[-1L], col=col.vert, lty=lty, 
             lwd=lwd)
  invisible(list(t=ti, y=y))
}

plot_stepfun(stepfun(x=dates, y=c(0, 1, 2)), do.points=FALSE)  ## works!
plot_stepfun(stepfun(x=dates, y=c(0, 1, 2)), do.points=FALSE, xlim=lims)  ## works!
plot_stepfun(stepfun(x=dates, y=c(0, 1, 2)), do.points=FALSE, xlim=dates)  ## works!
plot_stepfun(stepfun(x=dates, y=c(0, 1, 2)), do.points=FALSE, xlim=limits)  ## works!

enter image description here


Data:

dates <- structure(c(1649285787, 1651134684), class = c("POSIXct", "POSIXt"
), tzone = "UTC")
lims <- as.numeric(dates)
limits <- as.POSIXct.numeric(lims, origin=as.POSIXct("1970-01-01", tz="UTC"))
  • Related