8

I am working with some time series data and would like to highlight chart area whenever certain conditions become true. For example:

require(ggplot2)
require(quantmod)
initDate <- "1993-01-31"
endDate <- "2012-08-10"
symbols <- c("SPY")
getSymbols(symbols, from=initDate, to=endDate, index.class=c("POSIXt","POSIXct"))
spy<-SPY$SPY.Adjusted
spy$sma<-SMA(spy$SPY.Adjusted,200)
spy<-spy[-(1:199),] 
spy<-as.data.frame(spy)
ggplot(spy,aes(x=index(spy),y=spy$SPY.Adjusted))+geom_line()+geom_line(aes(x=index(spy),y=spy$sma))

The above code plots the the data, but how can I highlight the section when ever close is above sma? This question is similar to How to highlight time ranges on a plot?, but then it is manual. Is there a function in ggplot2 for conditional plotting?

Community
  • 1
  • 1
user1234440
  • 22,521
  • 18
  • 61
  • 103
  • 3
    The question you link to _is_ the way to do this. **ggplot2** does not yet have the functionality to understand something like `geom_shade_the_region_that_I_have_in_mind_you_know_that_one()`. You have to actually tell it what region you want shaded. – joran Aug 26 '12 at 21:04
  • 1
    You would increase your chances of getting non-quants to experiment with your code if you put in proper library calls to indicate which packages are needed to run that code. – IRTFM Aug 26 '12 at 21:08
  • @joran thanks so much for the insightful answer~ will work hard to come up with something useful. – user1234440 Aug 26 '12 at 21:11
  • I should add, though, that it's certainly possible to use the technique in the linked question to write a function that returns the desired `geom_rect` object. But you still have to write that function yourself, 'by hand'. – joran Aug 26 '12 at 21:20

1 Answers1

13

Based on code in the TA.R file of the quantmod package, here is code that uses rle to find the starts and ends of the rectangles.

runs <- rle(as.logical(spy[, 1] > spy[, 2]))
l <- list(start=cumsum(runs$length)[which(runs$values)] - runs$length[which(runs$values)] + 1,
          end=cumsum(runs$lengths)[which(runs$values)])
rect <- data.frame(xmin=l$start, xmax=l$end, ymin=-Inf, ymax=Inf)

Combine that with some ggplot2 code from the accepted answer to the question you linked to:

ggplot(spy,aes(x=index(spy),y=spy$SPY.Adjusted))+geom_line()+geom_line(aes(x=index(spy),y=spy$sma))+geom_rect(data=rect, aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax), color="grey20", alpha=0.5, inherit.aes = FALSE)

And you get:

enter image description here

If you reverse the order of plotting and use alpha=1 in geom_rect it may (or may not) look more like you desire:

ggplot(spy,aes(x=index(spy),y=spy$SPY.Adjusted))+geom_rect(data=rect, aes(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax), border=NA, color="grey20", alpha=1, inherit.aes = FALSE)+geom_line()+geom_line(aes(x=index(spy),y=spy$sma))

enter image description here


Since you have an xts object. You may not even want to convert to a data.frame. Here is how you could plot it using the brand new plot.xts method in the xtsExtra package created by Michael Weylandt as part of a Google Summer of Code project.

spy <- as.xts(spy)
require(xtsExtra)
plot(spy, screens=1,
     blocks=list(start.time=paste(index(spy)[l$start]),
                 end.time=paste(index(spy)[l$end]), col='lightblue'),                    
     legend.loc='bottomright', auto.legend=TRUE)

enter image description here

Community
  • 1
  • 1
GSee
  • 48,880
  • 13
  • 125
  • 145