Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plot time series using different colours based on factor

Tags:

r

xts

quantmod

I'd like to plot a single line which is multi-coloured, and the colours are based on the corresponding value in a factor. For instance, a time series of daily stock close price, where the days it has gone up by more than a certain amount are in blue, and the days it has gone done by a lot are in red, and the other days it is in boring black.

My data is in an xts object (with the factor put in there with as.numeric(myfactor)), and I'd like to be using the quantmod chartSeries or chart_Series functions. But if that is impossible then something using plot would be enough.

Some sample data:

library(xts)
x = xts( data.frame( v=(rnorm(50)+10)*10, type=floor(runif(50)*4) ),
  order.by=as.Date("2001-01-01")+1:50)

And I can plot it like this:

library(quantmod)
chartSeries(x$v)
addTA(x$type, type='p')

Which looks like this: plot using chartSeries

I.e. I felt it'd be easier to match the information in the bottom chart with the top one if coloured line segments were being used.

like image 635
Darren Cook Avatar asked Oct 20 '22 03:10

Darren Cook


1 Answers

So here's a ggplot solution. It's a bit more involved, but offers more sophisticated formatting options.

library(quantmod)
sp500 <- getSymbols("^GSPC", from="2015-01-01", auto.assign=FALSE)
sp500 <- Cl(sp500)                         # extract close
sp500 <- merge(sp500, dailyReturn(sp500))  # add daily returns
sp500 <- merge(lag(Cl(sp500),1), sp500)    # merge with close lagged by 1 day

names(sp500) <- c("ymin", "ymax", "return")
library(ggplot2)
library(scales)
df <- with(sp500,
           data.frame(xmin=c(lag(index(sp500),1)),
                      xmax=index(sp500), 
                      ymin, ymax, return))
df$status <- with(df,ifelse(return>0.01,"up",ifelse(return< -0.01,"down","neutral")))
ggplot(df) + 
  geom_segment(aes(x=xmin, xend=xmax, y=ymin, yend=ymax, color=status)) +
  scale_color_manual(values=c(up="green", down="red", neutral="grey50"), 
                     breaks=c("up","down"),
                     labels=c("Gain > 1%", "Loss > 1%")) +
  scale_x_date(breaks=date_breaks("months"), labels=date_format("%b"))+
  labs(x=NULL, y="Closing Price", title="S&P 500") +
  theme(panel.background =element_rect(fill="black"),
        panel.grid = element_blank())

As with the other answer the basic idea is to draw segments color coded based on the magnitude of the gain/loss. So we start by extracting closing prices, add a column of returns, and then add another column of closing prices lagged by 1 day. Then we create a data.frame from this with two columns of dates, also lagged by 1 day. Then we add a column (status) to indicate if the gain/loss was > 1%. Then we use this to drive geom_segment(...), color coding by status. In the scale_color_manual(...) call, we set the colors to red and green, and exclude the neutral color from the legend. The rest is all formatting.

like image 132
jlhoward Avatar answered Oct 21 '22 18:10

jlhoward