Create a monthly / annual calendar image with ggplot2

I started making a calendar in Excel, but thought it could be easily done in R instead. (Note: I am aware of the various packages of ggplot2 calendars, but I prefer to use ggplot2 .) Ultimately, I want to create a calendar that shows 12 months starting from a specific date, each month in the form of a small box showing 4 or 5 weeks on the y axis (week 1 above, week 4 or 5 below) and days of the week (starting on Monday) along the x axis.

I thought it would be a 15-minute job (create data for all months, format it a bit with reshape , then use facet_wrap ), but I ran into problems almost immediately, as the chart below shows - the days of the month are out of order, although the days of the week look fine. Ordering data in R is my sworn enemy; I really need to deal with this. Anyway, the image below shows that I am still, and the code below that. This is just a fun project, not an urgent one, but any help and / or decorations are 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() 
+4
source share
3 answers

Create a week.f column with levels in reverse order. We used "%U" (assuming a US agreement, but if you want the British convention to use "%W" and also dow factor dow ). We also allowed arbitrary date entry, which calculates the beginning of the month, and slightly simplified the call to ggplot .

 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 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, the TeachingDemos package has a cal function that can create a calendar for one month using classic graphics.

+4
source

This line of your code is incorrect:

 levels(mydf$dow) <- c('Mon','Tue','Wed','Thu','Fri','Sat','Sun') 

This is because mydf$dow already a factor, and with levels you simply rename the current levels. In this case, you simply rename "Fri" "Mon" "Sat" "Sun" "Thu" "Tue" "Wed" to 'Mon','Tue','Wed','Thu','Fri','Sat','Sun' and that will create the mess that you get at the end.

If you look at mydf in your example, you will see:

  mydate month week day dow 1 2013-09-01 9 35 1 Thu 2 2013-09-02 9 36 2 Tue 3 2013-09-03 9 36 3 Sat 4 2013-09-04 9 36 4 Sun 5 2013-09-05 9 36 5 Fri 6 2013-09-06 9 36 6 Mon 7 2013-09-07 9 36 7 Wed 

Due to renaming, day names no longer match dates.

After the fix, everything works as expected:

 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")) mydf$dow <- factor(mydf$dow, levels=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() 

enter image description here

+7
source

Here you go:

 start <- as.Date("2013-09-1") numdays <- 30 weeknum <- function(date){ z <- as.Date(date, format="%Y-%m-%d") as.numeric( format(z-1, "%U")) } dates <- data.frame(date=seq(start, length.out=numdays, by="1 day")) dates <- within(dates, { weeknum <- weeknum(date) month <- format(date, "%m") weekday <- format(date, "%a") day <- format(date, "%d") }) dates$weekday <- factor(dates$weekday, levels=c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")) library(ggplot2) ggplot(dates, aes(x=weekday, y=weeknum)) + geom_tile(fill="blue", col="white") + geom_text(aes(label=day)) 

enter image description here

+4
source

Source: https://habr.com/ru/post/1501651/


All Articles