
## generate data
set.seed(1L);
N <- 28e3L;
dts <- sort(as.POSIXct('2014-02-01')+86400L*(sample(7L*3L,N,T,rep(c(1L,2L,rep(10L,5L)),3L))-1L)+rnorm(N,86400/2,86400/8));
## bucket into hours and table
dts.cut <- cut(dts,'hour');
dts.freq <- table(dts.cut);
## precompute plot parameters
xlim <- range(dts); xlim <- as.POSIXct(c(round(xlim[1L]-86400/2,'day'),round(xlim[2L]+86400/2,'day'))); ## must convert back from POSIXlt to POSIXct, otherwise plot() fails on xlim
xticks.day <- seq(xlim[1L],xlim[2L],'day');
xticks.week <- xticks.day[setdiff(which(weekdays(xticks.day)=='Saturday'),c(1L,length(xticks.day)))];
xticks <- rep(xticks.day,each=3L)+1:3*60*60*6;
ylim <- range(dts.freq); ylim <- c(0,(ylim[2L]+9L)%/%10L*10L);
yticks <- seq(0,ylim[2L],10L);
col <- 'red';
## helper function, from <http://stackoverflow.com/questions/29125019/get-margin-line-locations-mgp-in-user-coordinates>
line2user <- function(line,side) {
lh <- par('cin')[2L]*par('cex')*par('lheight');
x1 <- diff(grconvertX(0:1,'inches','user'));
y1 <- diff(grconvertY(0:1,'inches','user'));
switch(side,
`1`=par('usr')[3L]-line*y1*lh,
`2`=par('usr')[1L]-line*x1*lh,
`3`=par('usr')[4L]+line*y1*lh,
`4`=par('usr')[2L]+line*x1*lh,
stop('side must be 1, 2, 3, or 4',call.=FALSE)
);
}; ## end line2user()
## draw plot
par(mar=c(5,4,4,2)+0.1+c(2,0,0,0));
plot(NA,xlim=xlim,ylim=ylim,axes=F,xaxs='i',yaxs='i',ann=F);
abline(v=xticks,col='lightgrey');
segments(xticks.day,ylim[2L],y1=line2user(4,1L),col='darkgrey',lwd=2,xpd=NA);
segments(xticks.week,ylim[2L],y1=line2user(4,1L),col='black',lwd=2,xpd=NA);
abline(h=yticks,col='lightgrey');
abline(h=0);
axis(1L,xticks,format(xticks,'%H:00'),las=2L,cex.axis=0.7);
axis(2L,yticks,las=2L,cex.axis=0.7);
mtext('Time',1L,5,font=3L);
mtext('Frequency',2L,2.75,font=3L);
mtext(format(xticks.day[-length(xticks.day)],'%a %b %d'),1L,2.75,at=xticks.day[-length(xticks.day)]+12*60*60,cex=0.7,font=2L);
x <- as.POSIXct(names(dts.freq));
y <- dts.freq;
lines(x,y,col=col,xpd=NA);
points(x,y,pch=16L,cex=0.7,col=col,xpd=NA);
title(paste0('Events per hour, ',format(xlim[1L],'%Y-%m-%d'),' to ',format(xticks.day[length(xticks.day)-1L],'%Y-%m-%d')));