Scale_x_date date_breaks 1st and 15th of the month

I'm using ggplot2 to make the graph below, specifically with the x date breaks formatted as shown, semimonthly on the 1st and 15th of every month.

Currently, I am using code similar to this to manually make a vector of x breaks from my data:

Dates <- c(as.Date("2016-08-03"),as.Date("2016-09-10"),as.Date("2016-12-18"),as.Date("2017-01-04"),as.Date("2017-07-14"))
x_breaks <- seq(as.Date(paste(year(min(Dates)),month(min(Dates)),1,sep="-")),
                as.Date(paste(year(max(Dates)),month(max(Dates))+1,1,sep="-")),
                by='1 month')
x_breaks <- c(x_breaks,x_breaks+14)

Is there any way (preferably using scale_x_date) to set this type of break in a more concise way? I've tried using this line in my ggplot call: scale_x_date(date_breaks = "2 weeks"), but that produces breaks every 14 days, instead of on the 1st and 15th of every month. What I really want is scale_x_date(date_breaks = "0.5 month") or something of that sort...

1 Like

Could you please try to making a reprex? It's easier to help if you provide R code that I can copy and paste into a running R session.

1 Like

library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following object is masked from 'package:base':
#> 
#>     date
library(ggplot2)

Effort_Combined_HI<-structure(list(Date = structure(c(17032, 17033, 17034, 17035, 
                                                      17036, 17037, 17038, 17039, 17040, 17041, 17042, 17043, 17044, 
                                                      17045, 17046, 17047, 17048, 17049, 17050, 17051, 17052, 17053, 
                                                      17054, 17055, 17056, 17057, 17058, 17059, 17060, 17061, 17062, 
                                                      17063, 17064, 17065, 17066, 17067, 17068, 17069, 17070, 17071, 
                                                      17072, 17073, 17074, 17075, 17076, 17077, 17078, 17079, 17080, 
                                                      17081, 17082, 17083, 17084, 17085, 17086, 17087, 17088, 17089), class = "Date"), 
                                   hours = c(0.45, 1.12, 1.12, 1.12, 1.12, 1.1, 
                                             1.07, 1.55, 1.22, 1.12, 1.12, 1.12, 1.12, 1.12, 1.12, 1.12, 1.1, 
                                             1.08, 1.12, 1.53, 1.22, 1.12, 1.12, 1.12, 1.37, 1.12, 1.12, 1.38, 
                                             1.12, 1.1, 1.13, 1.12, 1.12, 1.12, 1.12, 1.12, 1.12, 1.12, 1.12, 
                                             1.12, 1.12, 1.53, 1.2, 1.12, 1.12, 1.12, 1.12, 1.12, 1.12, 1.12, 
                                             1.12, 1.1, 1.55, 1.18, 1.12, 1.12, 1.12, 1.12), 
                                   ID = c("HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", "HI1 L", 
                                          "HI1 L")),
                              class = c("tbl_df", "tbl", "data.frame"), 
                              row.names = c(NA,-58L), 
                              .Names = c("Date", "hours", "ID"))

x_breaks <- seq(as.Date(paste(year(min(Effort_Combined_HI$Date)),month(min(Effort_Combined_HI$Date)),1,sep="-")),
                as.Date(paste(year(max(Effort_Combined_HI$Date)),month(max(Effort_Combined_HI$Date)),1,sep="-"))+months(1),
                by='1 month')
x_breaks <- c(x_breaks,x_breaks+14)
x_labels <- as.character(x_breaks, format="%d-%b-%y")

# plot & save Heron
Effort_Plot_Combined_HI<-ggplot(Effort_Combined_HI, aes(x=as.Date(Date), y=hours)) +
    facet_grid(ID ~.) + 
    geom_bar(stat="identity",width=1) + 
    xlab(NULL) +
    ylab(NULL) +
    ggtitle("Effort \n") +
    scale_x_date(breaks = x_breaks, labels = x_labels) +
    theme(legend.position="none",
          strip.text.y=element_text(angle=0),
          axis.text.x=element_text(angle=90,hjust=0.5,margin=margin(5,5,5,5)),
          axis.text.y=element_text(margin=margin(5,5,5,5)))

I'd recommend making a little helper function to make this easier. Something along these lines:

bimonthly <- function(x) {
  x_range <- range(x, na.rm = TRUE)
  
  date_range <- c(
    floor_date(x_range[1], "month"),
    ceiling_date(x_range[2], "month")
  )
  monthly <- seq(date_range[1], date_range[2], by = "1 month")
  
  sort(c(monthly, monthly + days(14)))
}

Then you can use that function as the argument to breaks:

ggplot(Effort_Combined_HI, aes(Date, hours)) +
  geom_bar(stat = "identity", width = 1) + 
  scale_x_date(breaks = bimonthly)
1 Like