Search code examples
rggplot2geom-vline

ggplot geom_vline on x-axis of class date


I am trying to add a geom_vline in a function where the x-axis consists of dates. The plot shows NOK vs EUR, and the vertical lines are supposed to show up on dates with policy rate changes. The following code shows no vertical lines:

nok_eur_plot <- function(nok_eur_data, regression_method) {
  g <- ggplot(
      nok_eur_data, 
      aes(x = Date, y = NOK_EUR)
      ) + 
    geom_smooth(method = regression_method) +
    geom_point() + 
    labs(
      x = "Date", 
      y = paste("NOK per EUR for the last", length(nok_eur_data$NOK_EUR), "working-days", sep = " "),
      title = "NOK per EUR",
      subtitle = paste("From", min(nok_eur_data$Date), "to", max(nok_eur_data$Date), sep = " ")
      ) + 
    theme(
      axis.title.y = element_text(color = "blue")
      )

  rate_changes <- nok_key_policy_rate_change(length(nok_eur_data$NOK_EUR))

  for(row in 1:nrow(rate_changes)) {
    g + geom_vline(xintercept = rate_changes$Date[row], color = "red", size = 1, linetype = 4)
  }

  plot(g)
}

The result is this: enter image description here

I have tried changing the

xintercept = rate_changes$Date[row]

to

xintercept = as.numeric(rate_changes$Date[row])

and

xintercept = as.POSIXct(rate_changes$Date[row])

as suggested here, but to no avail. I have checked that there are rate changes present for the date range shown in the plot, and there are 3 of them.

The whole Rmd-script looks like this:

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library("xml2")
library("dplyr")
library("ggplot2")
library("scales")
```

## NOK vs EUR Regression

```{r, results='asis'}
analysis_periods <- c(10,100,200)

nok_eur <- function(days) {

  url_to_read <- paste(
    "https://data.norges-bank.no/api/data/EXR/",
    "B.EUR.NOK.SP?lastNObservations=",
    days,
    sep = ""
  )

  nok_eur_obs <- read_xml(url_to_read) %>%
    xml_find_all("//Obs")

  dates_closed <- nok_eur_obs %>% 
    xml_attr("TIME_PERIOD") %>% 
    as.Date("%Y-%m-%d")

  nok_eur_daily <- nok_eur_obs %>% 
    xml_attr("OBS_VALUE") %>% 
    as.numeric()

  nok_eur_data <- data.frame(x = dates_closed, y = nok_eur_daily)
  colnames(nok_eur_data) <- c("Date", "NOK_EUR")
  return(nok_eur_data)
}

nok_key_policy_rate_change <- function(days) {

  url_key_policy_rates <- "https://data.norges-bank.no/api/data/IR/B.KPRA.RR.R"

  key_policy_rates_obs <- read_xml(url_key_policy_rates) %>%
    xml_find_all("//Obs")

  key_policy_rates_subset <- key_policy_rates_obs[
    (length(key_policy_rates_obs) - days + 1):length(key_policy_rates_obs)
    ]

  dates_closed_rates <- key_policy_rates_subset %>%
    xml_attr("TIME_PERIOD") %>%
    as.Date("%Y-%m-%d")

  rates_daily <- key_policy_rates_subset %>%
    xml_attr("OBS_VALUE") %>%
    as.numeric()

  nok_key_policy_rate_data <- data.frame(x = dates_closed_rates, y = rates_daily)
  colnames(nok_key_policy_rate_data) <- c("Date", "Key_policy_rate")
  for(row in 1:nrow(nok_key_policy_rate_data)) {
    if(row == 1) {
      rate_change <- c(0)
    } else {
      change_from_previous <- nok_key_policy_rate_data$Key_policy_rate[row] - nok_key_policy_rate_data$Key_policy_rate[row - 1]
      rate_change <- c(rate_change, change_from_previous)
    }
  }
  nok_key_policy_rate_data["Change"] <- rate_change

  nok_key_policy_rate_change_data <- filter(nok_key_policy_rate_data, Change != 0)
  return(nok_key_policy_rate_change_data)

} 

nok_eur_plot <- function(nok_eur_data, regression_method) {
  g <- ggplot(
      nok_eur_data, 
      aes(x = Date, y = NOK_EUR)
      ) + 
    geom_smooth(method = regression_method) +
    geom_point() + 
    labs(
      x = "Date", 
      y = paste("NOK per EUR for the last", length(nok_eur_data$NOK_EUR), "working-days", sep = " "),
      title = "NOK per EUR",
      subtitle = paste("From", min(nok_eur_data$Date), "to", max(nok_eur_data$Date), sep = " ")
      ) + 
    theme(
      axis.title.y = element_text(color = "blue")
      )

  rate_changes <- nok_key_policy_rate_change(length(nok_eur_data$NOK_EUR))

  for(row in 1:nrow(rate_changes)) {
    g + geom_vline(xintercept = rate_changes$Date[row], colour = "red", size = 1, linetype = 4)
  }

  plot(g)
}

for(no_days in analysis_periods) {

  nok_eur_plot(nok_eur(no_days), "auto")
  nok_eur_plot(nok_eur(no_days), "lm")

}

The nok_eur_data dataframe (example with 5 days):

    Date <date> NOK_EUR <dbl>
1   2019-09-25  9.9310      
2   2019-09-26  9.9235      
3   2019-09-27  9.9155      
4   2019-09-30  9.8953      
5   2019-10-01  9.9463      
6   2019-10-02  9.9930  
...

The nok_key_policy_rate_change_data dataframe (example with 100 days):

    Date <date> Key_policy_rate <dbl> Change <dbl>
1   2019-06-21  0.25                  0.25  
2   2019-09-20  0.50                  0.25  

Any suggestions much appreciated.


Solution

  • The following loop in your code actually doesn't modify the graph:

    for(row in 1:nrow(rate_changes)) {
        g + geom_vline(xintercept = rate_changes$Date[row], color = "red", size = 1, linetype = 4)
    }
    

    You should assign the result (i.e. g <- g + ...) in order to obtain an effect.

    More efficient: remove the for loop and add all vertical lines in one go

    g <- g + geom_vline(xintercept = rate_changes$Date, color = "red", size = 1, linetype = 4)
    print(g)