17

I'm trying to create a plot of POSIXct times using ggplot, and would like to reverse the axis, but am struggling to make it work. I've been using scale_y_datetime, because in my real application, it's important that I have control of the breaks on this axis.

Here's an example of my problem, first with normal ordering, and then my attempt to reverse the axis.

# Some random dates and values to plot
MyData <-
  structure(list(Date = structure(c(1492979809.99827, 1492602845.68722, 
  1493093428.90318, 1492605578.0691, 1492961342.65056, 1492771976.83545, 
  1493020588.88485, 1493057018.85104, 1492852011.23873, 1492855996.55059
  ), class = c("POSIXct", "POSIXt")), Value = c(4.52885504579172, 
  6.0024610790424, 8.96430060034618, 7.06435370026156, 5.08460514713079, 
  3.47828012891114, 6.29844291834161, 0.898315710946918, 1.44857675535604, 
  5.74641009094194)), .Names = c("Date", "Value"), row.names = c(NA, 
  -10L), class = "data.frame")

library(ggplot2)
library(scales)
ggplot(MyData, aes(x=Value, y=Date)) +
  geom_point() + 
  scale_y_datetime(limits=c(min(MyData$Date),max(MyData$Date)))

which produces this: DateTime MinMax Limits

If I attempt to reverse the Y axis, by reversing limits, I lose all breaks and data, like this:

ggplot(MyData, aes(x=Value, y=Date)) +
  geom_point() +
  scale_y_datetime(limits=c(max(MyData$Date),min(MyData$Date)))

DateTime MaxMin Limits

Is there a simple way to reverse the datetime axis?

David
  • 555
  • 5
  • 13
  • I'd question whether this is an appropriate visualization. Dates are usually independent variables and so (1) most people would expect to see them on the x-axis and (2) in that case, reversal would not make sense. Perhaps you could reverse by converting to "time since most recent date", _e.g._ `max(Date) - Date` ? – neilfws Apr 26 '17 at 05:37
  • 1
    @neilfws I don't disagree with you. My example was just to illustrate the problem that I was having, and isn't exactly what I'm trying to achieve. My ultimate goal is to generate something which is more of a calendar style output, where I have Weeks on the Y axis, and days along the X axis. As when looking at a calendar, it makes more sense to show weeks progressing from top-to-bottom. Thanks! – David Apr 26 '17 at 18:20
  • In that case I'd do a search for "ggplot2 calendar", sure to be a problem that others have thought about and addressed. – neilfws Apr 26 '17 at 21:30

2 Answers2

24

With the help from this post from Hadley Wickham here is how you can get a reverse datetime scale:

library(scales)
c_trans <- function(a, b, breaks = b$breaks, format = b$format) {
  a <- as.trans(a)
  b <- as.trans(b)
  
  name <- paste(a$name, b$name, sep = "-")
  
  trans <- function(x) a$trans(b$trans(x))
  inv <- function(x) b$inverse(a$inverse(x))
  
  trans_new(name, trans, inverse = inv, breaks = breaks, format=format)

}

rev_date <- c_trans("reverse", "time")

ggplot(MyData, aes(x=Value, y=Date)) +
  geom_point() + 
  scale_y_continuous(trans = rev_date)

Here is the plot: enter image description here

Oliver
  • 8,169
  • 3
  • 15
  • 37
Marcelo
  • 4,234
  • 1
  • 18
  • 18
3

The accepted answer doesn't work for me anymore (R version 4.2.1). An option to fix this is by slightly modifying the function coord_x_datetime from the tidyquant package to reverse the datetime for your y-axis. Here is the function called coord_y_datetime:

coord_y_datetime <- function(xlim = NULL, ylim = NULL, expand = TRUE) {
  if (!is.null(ylim)) {
    ylim <- lubridate::as_datetime(ylim)
  }
  ggplot2::coord_cartesian(xlim = xlim, ylim = ylim, expand = expand)
}

Here is a reproducible example:

library(ggplot2)
ggplot(MyData, aes(x = Value, y = Date)) +
  geom_point() + 
  coord_y_datetime(ylim = c(max(MyData$Date), min(MyData$Date)))

Created on 2022-11-14 with reprex v2.0.2

As you can see the y-axis datetime is now reversed.

Quinten
  • 35,235
  • 5
  • 20
  • 53