1
votes

This is my current epicurve:

enter image description here

and the code used to generate it:

# generate random sample of dates and sex
df = data.frame(dates = Sys.Date() + sample(-10:25, 100, replace = T), 
            sex = sample(c("M", "F"), 25, replace = T)) 

require(ggplot2); require(scales)

# set x-axis limits 
xlmts = c(Sys.Date() - 22, Sys.Date() + 30)

p = ggplot(df, aes(x = dates, fill  = sex))

p = p + geom_bar(stat = "bin", colour = "black")

p = p + scale_x_date(breaks = "1 day", labels=date_format("%a \n %d \n %m"),
                 limits = xlmts)

p

This is roughly what I want my epicruve to look like:

enter image description here

I have two issues with my x-axis:

Issue 1 - breaks

  1. Even though I've set 'breaks = 1day' in 'scale_x_date' multiple days have been grouped together

Issue 2 - major and minor tick labels

2.1 Is there any way to get the abbreviated day name at a 90-degree angle and keep the day number and month number at a 0-degree.

2.2 Is there any way to show just one month number (preferably centered in the middle of the month) so that it does not repeat on each major tick label as in the example above.

1

1 Answers

3
votes

This gets you a bit further (I didn't add the lines), but it's pretty manual work.

In the main plot, I:

  • use a random seed to make it reproducible :-)
  • pre-compute the M/F counts per day
  • rotate the X axis labels (just using day short name)
  • expand the plot margins to accommodate extra X axis annotations

Then I:

  • generate and add the non-rotated, in-month day #'s via annotation_custom
  • generate and add the non-rotated month numbers via annotation_custom
  • build the final plot grid structure
  • turn off the panel clip rect
  • draw the graph with grid.draw

You'll prbly want to play with the spacing a bit.

This should be enough to get you going (and adding the lines should be pretty doable with lineGrob).

library(dplyr)
library(ggplot2)
library(scales)
library(grid)
library(gridExtra)

set.seed(1492) # reproducible

df = data.frame(dates = Sys.Date() + sample(-10:25, 100, replace = T), 
                sex = sample(c("M", "F"), 25, replace = T)) 

# pre-compute the M/F counts per date

df.2 <- df %>% group_by(dates, sex) %>% summarise(count=n())

gg <- ggplot(df.2, aes(x=dates, y=count, fill=sex))
gg <- gg + geom_bar(color="black", position="stack", stat="identity")
gg <- gg + scale_x_date(breaks="1 day", 
                        labels=date_format("%a"),
                        limits = xlmts)
gg <- gg + labs(x=NULL)
gg <- gg + theme_bw()
gg <- gg + theme(axis.text.x=element_text(angle = 90, hjust = 1))
gg <- gg + theme(plot.margin=unit(c(1,1,5,1), "line"))

gg1 <- gg # keep base plot

# make & plot the day #'s

for (d in seq(from=as.Date("2014-09-06"), to=as.Date("2014-11-01"), by="1 day")) {
  d1 <- format(as.Date(d, origin="1970-01-01"), "%d")
  gg1 <- gg1 + annotation_custom(grob=textGrob(d1, hjust=0, gp=gpar(cex=0.7)), ymin=-0.8, ymax=-0.8, 
                                 xmin=as.numeric(d), xmax=as.numeric(d))  
}

# add month numbners

gg1 <- gg1 + annotation_custom(grob=textGrob("9", gp=gpar(cex=0.8)), ymin=-1.0, ymax=-1.0, 
                            xmin=as.numeric(as.Date("2014-09-17")), xmax=as.numeric(as.Date("2014-09-17")))
gg1 <- gg1 + annotation_custom(grob=textGrob("10", gp=gpar(cex=0.8)), ymin=-1.0, ymax=-1.0, 
                            xmin=as.numeric(as.Date("2014-10-12")), xmax=as.numeric(as.Date("2014-10-12")))

# build the plot

gg2 <- ggplot_gtable(ggplot_build(gg1))

# no panel clipping
gg2$layout$clip[gg2$layout$name=="panel"] <- "off"

# draw the plot 

grid.draw(gg2)

enter image description here