![]() |
From MarginTale |
How do you attack the problem? Looking at the example output above:
- We facet_grid by "months" and "years"
- The data itself is plotted by "week of month" and "day of week" and coloured according to the value of interest
So, given a time series we just have to fiddle with time indexes to create a data.frame containing the time series as well as per observation the corresponding "month", "year", "week of month", "day of week". The rest is then a one-liner of code with Hadley's wonderful ggplot2 system.
The following code contains step by step comments:
The following code contains step by step comments:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require(quantmod) | |
require(ggplot2) | |
require(reshape2) | |
require(plyr) | |
require(scales) | |
# Download some Data, e.g. the CBOE VIX | |
getSymbols("^VIX",src="yahoo") | |
# Make a dataframe | |
dat<-data.frame(date=index(VIX),VIX) | |
# We will facet by year ~ month, and each subgraph will | |
# show week-of-month versus weekday | |
# the year is simple | |
dat$year<-as.numeric(as.POSIXlt(dat$date)$year+1900) | |
# the month too | |
dat$month<-as.numeric(as.POSIXlt(dat$date)$mon+1) | |
# but turn months into ordered facors to control the appearance/ordering in the presentation | |
dat$monthf<-factor(dat$month,levels=as.character(1:12),labels=c("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"),ordered=TRUE) | |
# the day of week is again easily found | |
dat$weekday = as.POSIXlt(dat$date)$wday | |
# again turn into factors to control appearance/abbreviation and ordering | |
# I use the reverse function rev here to order the week top down in the graph | |
# you can cut it out to reverse week order | |
dat$weekdayf<-factor(dat$weekday,levels=rev(1:7),labels=rev(c("Mon","Tue","Wed","Thu","Fri","Sat","Sun")),ordered=TRUE) | |
# the monthweek part is a bit trickier | |
# first a factor which cuts the data into month chunks | |
dat$yearmonth<-as.yearmon(dat$date) | |
dat$yearmonthf<-factor(dat$yearmonth) | |
# then find the "week of year" for each day | |
dat$week <- as.numeric(format(dat$date,"%W")) | |
# and now for each monthblock we normalize the week to start at 1 | |
dat<-ddply(dat,.(yearmonthf),transform,monthweek=1+week-min(week)) | |
# Now for the plot | |
P<- ggplot(dat, aes(monthweek, weekdayf, fill = VIX.Close)) + | |
geom_tile(colour = "white") + facet_grid(year~monthf) + scale_fill_gradient(low="red", high="yellow") + | |
opts(title = "Time-Series Calendar Heatmap") + xlab("Week of Month") + ylab("") | |
P |
It should be easy to wrap into a function and I hope its useful.
Hello,
ReplyDeletethanks for this very interesting post!
I'm fairly new to R so I was hopping you could help with this: I'm trying to create the same chart but using daily percentage changes instead of close prices. I tried several ways but I couldn't do it. I was wondering if you could help me with this.
Thanks a lot in advance!
Dan.
thx,
Deletequick and dirty, add:
VIX<-dailyReturn(Cl(VIX))
colnames(VIX)<-"VIX.Close"
after the line containing getSymbols
enjoy
Hi,
ReplyDeleteIt is a good post. Just want to simplify few statements using lubridate package, especially where creating month, year and weekday are involved
library(lubridate)
dat$year = year(dat$date)
# using month() in lubridate and set label option to true to get Jan..
dat$month = month(dat$date, label = TRUE, abbr = TRUE)
dat$weekday = wday(dat$date, label = TRUE, abbr = TRUE)
#approximate for week num in month
dat$monthday = mday(dat$date)
dat$monthweek = ceiling(dat$monthday / 7)
Cheers
Krishna
This is very useful. Thanks for posting.
ReplyDeleteWhen I run this on the stock example, as well as data I have available, I'm getting scientific notation in the label on the right (ie. VIX.Close = 2.0e+01 as opposed to 20). Any thoughts on how this could be fixed?
what happens if you add
Deletebreaks=seq(10,80,10)
as a parameter into scale_fill_gradient(...) above?
I'm having the same problem. The Week of the Month axis labels are also in scientific notation. How can I change this?
DeleteNote: using breaks=seq(10,80,10) didn't change it.