Arthur Coimbra
Arthur Coimbra

Reputation: 477

How to plot simple vertical line with abline() in R?

I'm unable to add a vertical, or horizontal line to my graph. I feel I'm missing something very simple, but I can't seem to find it. I've copied some examples from the internet but it won't work. What am I doing wrong?

This is what I'm trying:

library(quantmod)
getSymbols("^FTSE", src="yahoo", from=as.Date('2004-01-01'), 
           to=as.Date('2013-01-01'), periodicity="weekly")

plot(FTSE$FTSE.Close)
abline(v='2008-01-01', col="red")

I've also tried:

abline(h = 5000, col="red") and abline(h = mean(FTSE$FTSE.Close), col="red")

But they also won't work. No lines are shown.

I just want a vertical line. I'm using RStudio.

Upvotes: 2

Views: 6208

Answers (4)

jay.sf
jay.sf

Reputation: 72683

This probably should be issued at CRAN. (This was already issued at github, solution is posted in the other answer.)

Here's a workaround.

Following this answer, we could plot a vertical constant rather with lines than with abline. plot.xts, which is used when we plot a "xtx" object, seems to be somewhat buggy or messy written as it also a comment signalizes in the linked answer, and which suggests to use zoo::plot.zoo instead.

From another answer we learn, that we may use .index() to extract the indices that are below the data, similar to factors where the values lie below the labels.

However, plot.zoo prunes the dates according to an unknown smoothing algorithm (which probably can be figured out by looking deeply into zoo::plot.zoo), and our date we're plotting could hit precisely such a "black hole". One possible solution is to give plot.zoo a sapply broadside of x-coordinates. I've written a function genXcords

genXcords <- function(data, date, tadj=0, ladj=0) {
  idx <- as.Date(as.POSIXct(.index(data), origin="1970-01-01"))
  se <- seq(as.Date(date) - 5 - tadj, by="day", length.out=21 + ladj)
  y.crds <- .index(data)[which(min(se) < idx & idx < max(se))]
  return(y.crds)
}

that first pulls out the dates from the numerical indices. Next, it creates a sequence of dates containing the date to be plotted somewhere within. Note the adjustment parameters tadj and ladj, because will will need some fine-tuning afterwards. (Probably the function itself has to be further refined!) Eventually, the function throws a battery of x-coordinates which we can try to plot.

Now let's test genXcords method on an example.

# load package
library(xts)

# get data
data(sample_matrix)
sample.xts <- as.xts(sample_matrix)

# create line data
y.cords <- genXcords(sample.xts, "2007-05-16", -6, -18)  # note the adjustment!

# plot 
zoo::plot.zoo(sample.xts[,"Close"])
invisible(sapply(y.cords, function(x) lines(x=rep(x, 100), 
                                  y=seq(0, max(sample.xts$Close) + 10, length.out=100), 
                                  col="red", lty=2, lwd=2)))

I manually adjusted the tadj and ladj parameters until just one single vertical line appeared at the right place. This resulted in the plot below.

enter image description here

Note: Unfortunately I couldn't get it to work with the FTSE data. But in principle, as one can see it works, and instead of deleting my code I put it here.

Upvotes: 2

jay.sf
jay.sf

Reputation: 72683

Alternatively, we will have to use xts::addEventLines.

There was actually an issue opened at github on Feb, 2015 that abline simply won't work with the new plot.xts and we should use the alternative.

library(quantmod)
getSymbols("^FTSE", src="yahoo", from=as.Date('2004-01-01'), 
           to=as.Date('2013-01-01'), periodicity="weekly")

plot(FTSE$FTSE.Close)
# abline(v='2008-01-01', col="red")  # won't work

# alternative
events <- xts("", as.Date("2008-01-01"))
addEventLines(events, col="red", lwd=2)

Result

enter image description here

Note: It's also possible to define multiple event lines, e.g. events <- xts(letters[1:3], as.Date(c("2008-01-01", "2009-01-01", "2010-01-01"))) .

Upvotes: 2

Brigadeiro
Brigadeiro

Reputation: 2945

You want to use the v argument (for vertical) not the h argument (for horizontal). Here's a reproducible example:

d <- data.frame("y" = 1:5, 
                "dates" = paste0("2012-01-0", 1:5))

plot(d$y ~ d$dates)

abline(v = which(d$dates == "2012-01-01"), col = "red")

Upvotes: 0

AndS.
AndS.

Reputation: 8110

This is an interesting issue. Here is my workaround. I took the row index and made them into a column, then I translated the plot into ggplot so that I could have a little more control on the plot. Let me know if anything in the code is ambiguous.

library(tidyverse)
library(quantmod)

getSymbols("^FTSE", src="yahoo", from=as.Date('2004-01-01'), 
           to=as.Date('2013-01-01'), periodicity="weekly")

FTSE %>%
  as.data.frame() %>%
  rownames_to_column("date") %>%
  mutate(date = lubridate::ymd(date)) %>%
  ggplot(aes(date,FTSE.Close ))+
  geom_line()+
  geom_vline(xintercept = as.Date('2008-01-01'), col="red")+
  scale_y_continuous(breaks = scales::pretty_breaks(6), 
                     sec.axis = sec_axis(trans = ~., breaks = scales::pretty_breaks(6)))+
  scale_x_date(date_labels = "%b %d %Y", date_breaks = "2 years")+
  ggtitle("FTSE.Close",subtitle = "2014-01-01/2012-12-27")+
  theme(axis.title = element_blank(),
        axis.line.x = element_line(colour = "black"),
        axis.ticks.x = element_line(colour = "black"),
        axis.line.y = element_blank(),
        axis.ticks.y = element_blank(),
        panel.background = element_blank(),
        panel.grid.major = element_line(colour = "gray"))

Upvotes: 2

Related Questions