Robert
Robert

Reputation: 133

Setting x-axis limits for datetime in ggplot

I want to plot occupancy rates for a particular parking garage on a particular day in a line chart making use of ggplot.

My dataframe looks as follows:

head(ParkingSub4)
    FreeSpaceShort ShortCapacity            DateTime OccupancyRateShort       Date  Weekday WeekNumber  Week
310801            257           373 2017-02-25 00:04:41          0.3109920 2017-02-25 Saturday         08 FALSE
310843            260           373 2017-02-25 00:09:41          0.3029491 2017-02-25 Saturday         08 FALSE
310885            261           373 2017-02-25 00:14:41          0.3002681 2017-02-25 Saturday         08 FALSE
310927            260           373 2017-02-25 00:19:41          0.3029491 2017-02-25 Saturday         08 FALSE
310969            260           373 2017-02-25 00:24:41          0.3029491 2017-02-25 Saturday         08 FALSE
311011            263           373 2017-02-25 00:29:41          0.2949062 2017-02-25 Saturday         08 FALSE

class(ParkingSub4$DateTime)
[1] "POSIXlt" "POSIXt" 

When I try to plot an overview of a particular day, let's say 23rd of February, 2017 I use the following code:

ggplot(data = ParkingSub4, 
       aes(x=DateTime, y=OccupancyRateShort)) + geom_line(size = 1.25) + facet_wrap(~Weekday) +
      scale_x_datetime(labels=date_format("%H:%m"), breaks = date_breaks("2 hours")) +
      theme_linedraw()

Then what I get is the following plot:

enter image description here

As you can see, the plot starts and ends at 23:02. I want the plot to start at 00:00:00 and end at 23:59:59 on that particular day. How can I do that?

Many thanks in advance!

EDIT/UPDATE: Adding the following does lead to the x-axis starting and ending with 00:00:

ggplot(data = ParkingSub4, 
   aes(x=DateTime, y=OccupancyRateShort)) + geom_line(size = 1.25) + facet_wrap(~Weekday) +
  scale_x_datetime(labels=date_format("%H:%m"), breaks = date_breaks("2 hours"), expand=c(0,0)) +
  xlim(c(as.POSIXct('2017-02-23 00:00:00', format = "%Y-%m-%d %H:%M:%S"),
     as.POSIXct('2017-02-24 00:00:00', format = "%Y-%m-%d %H:%M:%S"))) +
  theme_linedraw()

Only thing is I get the following message after executing: 'Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.'

This means that scale_x_datetime(labels=date_format("%H:%m"), breaks = date_breaks("2 hours") is overwritten by: xlim(c(as.POSIXct('2017-02-23 00:00:00', format = "%Y-%m-%d %H:%M:%S"), as.POSIXct('2017-02-24 00:00:00', format = "%Y-%m-%d %H:%M:%S")).

That's also not what I want, as now the breaks are set at 6 hours instead of 2 hours, and I can also not specify what information ("%H:%m") is set on the labels.

Upvotes: 12

Views: 19911

Answers (4)

filups21
filups21

Reputation: 1917

I'm adding another answer to clarify the difference between using scale_x_datetime and coordinate_cartesian. Unlike scale_x_datetime, coordinate_cartesian will zoom the plot without removing any data that falls outside the plot limits.

For example. If we use the plot above:

library(ggplot2)
library(scales)

set.seed(1)
ParkingSub4 <- data.frame(DateTime = seq(as.POSIXlt('2017-02-22 23:00', tz = 'UTM'), 
                                         as.POSIXlt('2017-02-24 01:00', tz = 'UTM'), 
                                         len = 42), 
                          OccupancyRateShort = runif(42, 0, 1))
ParkingSub4$Weekday <- weekdays(ParkingSub4$DateTime)

lims <- as.POSIXct(strptime(c("2017-02-23 00:00", 
                              "2017-02-23 23:59"), 
                               format = "%Y-%m-%d %H:%M"), 
                   tz = 'UTM')
ggplot(data = ParkingSub4, 
       aes(x = DateTime, y = OccupancyRateShort)) + 
   geom_line(size = 1.25) +            
   scale_x_datetime(labels = date_format("%H:%M"), 
                    breaks = date_breaks("2 hours"), 
                    limits = lims, 
                    expand = c(0, 0)) +
   geom_smooth()+
   theme_linedraw()

Original plot (with a smoothing line to more easily see the difference between scale_x_datetime and coordinate_cartesian): enter image description here

If, for some reason, you wanted to focus on 7am to 7pm, you have 2 options. You can use scale_x_datetime (or xlim) to remove extra data:

lims2 <- as.POSIXct(strptime(c("2017-02-23 07:00", 
                               "2017-02-23 19:00"), 
                             format = "%Y-%m-%d %H:%M"), 
                    tz = 'UTM')

ggplot(data = ParkingSub4, 
       aes(x = DateTime, y = OccupancyRateShort)) + 
   geom_line(size = 1.25) +            
   scale_x_datetime(labels = date_format("%H:%M"), 
                    breaks = date_breaks("2 hours"), 
                    limits = lims2, 
                    expand = c(0, 0)) +
   geom_smooth()+
   theme_linedraw()

Which produces this plot: enter image description here

Alternatively, you can use coordinate_cartesian to zoom in on the plot without removing any of the data:

ggplot(data = ParkingSub4, 
       aes(x = DateTime, y = OccupancyRateShort)) + 
   geom_line(size = 1.25) +            
   scale_x_datetime(labels = date_format("%H:%M"), 
                    breaks = date_breaks("2 hours"), 
                    limits = lims, 
                    expand = c(0, 0)) +
   coord_cartesian(xlim = lims2) +
   geom_smooth()+
   theme_linedraw()

Note that the smooth is the same as in the original plot: enter image description here

Upvotes: 1

makeyourownmaker
makeyourownmaker

Reputation: 1833

First things first, here is some reproducible data:

set.seed(1)
ParkingSub4 <- data.frame(DateTime = seq(as.POSIXlt('2017-02-22 23:00'), 
                                         as.POSIXlt('2017-02-24 01:00'), 
                                         len = 42), 
                          OccupancyRateShort = runif(42, 0, 1))
ParkingSub4$Weekday <- weekdays(ParkingSub4$DateTime)

Next, here is how to reproduce the problem with this data:

library(ggplot2)
library(scales)
ggplot(data = ParkingSub4[ParkingSub4$Weekday == "Thursday",], 
       aes(x = DateTime, y = OccupancyRateShort)) + 
       geom_line(size = 1.25) + 
       facet_wrap(~Weekday) +
       scale_x_datetime(labels = date_format("%H:%m"), 
                        breaks = date_breaks("2 hours")) +
       theme_linedraw()

Finally, here is a solution using the limits option to scale_x_datetime:

lims <- as.POSIXct(strptime(c("2017-02-23 00:00", "2017-02-24 00:00"), 
                   format = "%Y-%m-%d %H:%M"))
ggplot(data = ParkingSub4[ParkingSub4$Weekday == "Thursday",], 
       aes(x = DateTime, y = OccupancyRateShort)) + 
       geom_line(size = 1.25) + 
       facet_wrap(~Weekday) +
       scale_x_datetime(labels = date_format("%H:%m"), 
                        breaks = date_breaks("2 hours"), 
                        limits = lims) +
       theme_linedraw()

UPDATE: The following will remove the whitespace on the left and right of the graph and the breaks will be on the hour instead of at 2 minutes past:

lims <- as.POSIXct(strptime(c("2017-02-23 00:00", "2017-02-23 23:59"), 
                   format = "%Y-%m-%d %H:%M"))
ggplot(data = ParkingSub4, 
       aes(x = DateTime, y = OccupancyRateShort)) + 
       geom_line(size = 1.25) +            
       scale_x_datetime(labels = date_format("%H:%M"), 
                        breaks = date_breaks("2 hours"), 
                        limits = lims, 
                        expand = c(0, 0)) +
       theme_linedraw()

Upvotes: 8

lukeA
lukeA

Reputation: 54237

In addition to my comment:

library(ggplot2)
library(lubridate)
df <- data.frame(x = seq(Sys.time(), Sys.time()+days(1), by = "2 mins"))
df$y = runif(nrow(df))

lims <- c(floor_date(min(df$x), "day"), ceiling_date(max(df$x), "day"))
f <- function(lims)
  ggplot(data = df, aes(x, y)) + 
    geom_line() +  
    scale_x_datetime(
      date_labels = "%H:%M", 
      date_breaks = "2 hours", 
      limits = lims,
      timezone = Sys.timezone(),
      expand = c(0,0)
    ) + 
    theme(
      plot.margin = margin(10,20,10,10), 
      axis.text.x = element_text(angle=90, vjust=.5)
    )

f(lims)
f(lims-c(days(1),0))

Upvotes: 1

drmariod
drmariod

Reputation: 11762

Use expand parameter in your scale_x_datetime and set it to 0.

scale_x_datetime(labels=date_format("%H:%m"), breaks = date_breaks("2 hours"), expand=c(0,0))

Upvotes: 2

Related Questions