adding more standard deviations to a plot

61 Views Asked by At

I'm trying to add more standard deviation to my current plot. I need to add 1std and 3std, I've already addeed the 2std to my plot.

This is my code:

tidyverse_downloads_rollmean <- treasury %>%
  tq_mutate(
    # tq_mutate args
    select     = yield,
    mutate_fun = rollapply, 
    # rollapply args
    width      = 360,
    align      = "right",
    FUN        = mean,
    # mean args
    na.rm      = TRUE,
    # tq_mutate args
    col_rename = "mean_360"
  ) 

This is for the 2std but I need to add 1std and 3std in the same plot:

custom_stat_fun_2 <- function(x, na.rm = TRUE) {
 
  m  <- mean(x, na.rm = na.rm)
  s  <- sd(x, na.rm = na.rm)
  hi <- m + 2*s
  lo <- m - 2*s
  
  ret <- c(mean = m, stdev = s, hi.95 = hi, lo.95 = lo) 
  return(ret)
}

I added to my data:

rollstats<- treasury %>%
    tq_mutate(
      select     = yield,
      mutate_fun = rollapply, 
      # rollapply args
      width      = 360,
      align      = "right",
      by.column  = FALSE,
      FUN        = custom_stat_fun_2,
      # FUN args
      na.rm      = TRUE
    )

This is my plot:

rollstats %>%
       ggplot(aes(x = date)) +
       # Data
       geom_line(aes(y = yield), color = "grey40", alpha = 0.5, size =1) +
       geom_ribbon(aes(ymin = lo.95, ymax = hi.95), alpha = 0.4) +
       geom_point(aes(y = mean), linetype = 2, size = 0.5, alpha = 0.5) +
       # Aesthetics
       labs(title = "tidyverse packages: Volatility and Trend", x = "",
            subtitle = "360-Day Moving Average with 95% Confidence Interval Bands (+/-2 Standard Deviations)") +
       scale_color_tq(theme = "light") +
       theme_tq() +
       theme(legend.position="none")

This is my output:

enter image description here

But I want something like this:

enter image description here

So how can I add the 1std and 2std? Is there another way to plot 1std, 2std and 3std in the same plot? Thanks in advance!

1

There are 1 best solutions below

0
On

You haven't provided a reprex so hard to help you. Tidyquant has functions to plot the standard deviation bands for you (geom_bbands). But, here's an idea with only ggplot2 using different data. Calculate the 1st, 2nd, and 3rd standard deviations:

library(tidyquant)

custom_stat_fun_2 <- function(x, na.rm = TRUE) {
  
  m  <- mean(x, na.rm = na.rm)
  s  <- sd(x, na.rm = na.rm)
  hi1 <- m + s
  lo1 <- m - s
  hi2 <- m + 2*s
  lo2 <- m - 2*s
  hi3 <- m + 3*s
  lo3 <- m - 3*s
  
  ret <- c(mean = m, stdev = s,hi1 = hi1, lo1 = lo1, hi2=hi2, lo2=lo2, hi3=hi3, lo3=lo3) 
  return(ret)
}

treasury <- treasuryTR::get_yields("DGS10", format_out = "tibble")

rollstats<- treasury |>
    tq_mutate(
      select     = DGS10,
      mutate_fun = rollapply, 
      # rollapply args
      width      = 360,
      align      = "right",
      by.column  = FALSE,
      FUN        = custom_stat_fun_2
    ) |>
    na.omit()

Melt the data frame to have one column for hi and one for lo and then set factor levels so they plot in reverse order:

rollsds <- tidyr::pivot_longer(rollstats,cols = starts_with(c("hi", "lo")),
 names_to = c(".value", "sd"), names_pattern = "(.*)(\\d)")
rollsds$sd <- factor(as.character(rollsds$sd), levels=c(3,2,1))

Plot

library(ggplot2)

rollstats |>
  ggplot(aes(x = date)) +
  # Data
  geom_ribbon(data=rollsds, aes(ymax = hi, ymin=lo, fill=sd, color=sd), alpha=0.3) +
  geom_line(aes(y = mean), linetype = 2, size = 0.5, alpha = 0.5) +
  geom_line(aes(y = DGS10), color = "midnightblue", alpha = 0.7, size =1) +
  # Aesthetics
  theme_tq() 

enter image description here