Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a monthly/yearly calendar image with ggplot2

Tags:

r

ggplot2

I started to make a calendar in Excel, but thought it might be easy to do in R instead. (Note: I'm aware of various heatmap calendar packages but I prefer to use ggplot2.) Ultimately I want to make a calendar that shows 12 months starting from a given date, with each month as a small box showing 4 or 5 weeks on the y-axis (week 1 at the top, week 4 or 5 at the bottom) and the days of the week (starting from Monday) along the x-axis.

I thought this would be a 15-minute job (create data for all months, format a bit using reshape then use facet_wrap) but ran into problems almost immediately as the plot below shows - the days of the month are not in order, although the days of the week seem okay. Ordering data in R is my nemesis; I really should get a handle on this. Anyway, the image below shows what I have so far and the code is below that. This is just a fun project, not urgent, but any help and/or embellishments welcome.

calendar

require(ggplot2)
require(scales)
require(lubridate)

date.start <- as.Date('2013-09-01')
date.end <- date.start + months(1)

mydf <- data.frame(mydate = seq(as.Date(date.start),
                       as.Date(date.end) - days(1),
                       by = 'day'))

mydf$month <- month(mydf$mydate)
mydf$week <- week(mydf$mydate)
mydf$day <- day(mydf$mydate)
mydf$dow <- as.factor(format(mydf$mydate, format = "%a"))
levels(mydf$dow) <- c('Mon','Tue','Wed','Thu','Fri','Sat','Sun')

ggplot(mydf, aes(x = dow, y = as.factor(week))) +
    geom_tile(colour = "black", fill = "white", label = mydf$day) +
    geom_text(label = mydf$day, size = 4, colour = "black") +
    scale_x_discrete(expand = c(0,0)) +
    theme(axis.ticks = element_blank()) +
    theme(axis.title.y = element_blank()) +
    theme(axis.title.x = element_blank()) +
    theme(panel.background = element_rect(fill = "transparent"))+
    theme(legend.position = "none") +
    theme()
like image 445
SlowLearner Avatar asked Sep 11 '13 12:09

SlowLearner


1 Answers

Create the week.f column with levels in reverse order. We have used "%U" (assuming US convention but if you want the UK convention use "%W" and also change the order of the factor levels of dow). Also we have allowed arbitrary date input calculating the start of the month and have simplified the ggplot call slightly.

library(ggplot2)

input <- as.Date("2013-09-11") # input date

st <- as.Date(cut(input, "month")) # calculate start of month
dates31 <- st + 0:30 # st and next 30 dates (31 in all)
dates <- dates31[months(dates31) == months(st)] # keep only dates in st's month

week.ch <- format(dates, "%U") # week numbers

mydf <- data.frame(
   day = as.numeric(format(dates, "%d")),
   week.f = factor(week.ch, rev(unique(week.ch))),
   dow = factor(format(dates, "%a"), c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"))
)

ggplot(mydf, aes(x = dow, y = week.f)) +
    geom_tile(colour = "black", fill = "white") +
    geom_text(label = mydf$day, size = 4) + 
    scale_x_discrete(expand = c(0,0)) +
    theme(axis.ticks = element_blank()) +
    theme(axis.title = element_blank()) +
    theme(panel.background = element_rect(fill = "transparent"))+
    theme(legend.position = "none")

enter image description here

By the way, there is a cal function in the TeachingDemos package that can construct a one month calendar using classic graphics.

like image 199
G. Grothendieck Avatar answered Sep 20 '22 15:09

G. Grothendieck