How to plot mixed-frequency series with NAs in ggplot?

Viewed 115

I have the following dataframe x:

x1 <- data.frame(Date = seq(as.Date("2010-01-01"), 
                           as.Date("2012-12-01"), 
                           by = "month"), 
                TS1 = rnorm(36,0,1), 
                TS2 = rnorm(36,0,1), 
                stringsAsFactors = F)

x2 <- data.frame(Date = seq(as.Date("2010-01-01"), 
                           as.Date("2012-12-01"), 
                           by = "quarter"), 
                TS3 = rnorm(12,0,1), 
                stringsAsFactors = F)

x <- left_join(x1, x2, by = "Date")

x contains two monthly series, while one is quarterly.

I would like to plot all three series at the same time with ggplot. I am aware of dualplot as a way to do it. The issue with it however is that it allows you to plot only 2 mixed frequency series.

Is there anyone who can help me with this?

Thanks!

2 Answers

Note that ggplot requires long format, so we first use tidyr::pivot_longer.

Next, we can plot TS1 and TS2 easily, but TS3 will not plot at all as it contains missing values.

One option is to plot the line with missings with a separate geom_line call:

x2 <- x %>%
  tidyr::pivot_longer(cols = c(TS1, TS2, TS3), names_to = "TS") %>%
  mutate(TS = as.factor(TS))

ggplot(x2, aes(x = Date, y = value, group = TS, color = TS)) + 
  geom_line() + 
  geom_line(data = subset(x2, TS == "TS3" & !is.na(value)))

enter image description here

In this instance, ggplot does not have to have the data transformed into long format (although it is a nice solution, if you are familiar with transforming data, and recommended especially if there were lots of columns or separate lines to be plotted).

For simplicity, especially when learning ggplot can I propose an alternative solution.

TS1 and TS2 can easily be plotted against date, as neither have NA values. Here, we call geom_line() twice, once for each line:

x %>%  
  ggplot()+
  geom_line(aes(Date, TS1), colour = 'red')+
  geom_line(aes(Date, TS2), colour = 'blue')

enter image description here

If you try and include a third geom_line() with TS3, only the original two lines are plotted due to TS3's missing values (NA). A solution is to fill in the NA values in the data before plotting, using zoo::na.approx(). As the name suggests, zoo::na.approx() is able to approximate values when you have NAs, by linear interpolation. In this instance, I assume linear interpolation between known values is appropriate for plotting (as geom_line is doing anyway). Check out ?zoo::na.approx for more details, including non-linear interpolation.

zoo::na.approx(TS3, Date, na.rm = FALSE) may be read aloud like: "We want to approximate the values of TS3 when they are missing (NA), based on the values of Date, and if there are still NAs in the interpolated data keep the non-NA values we can approximate."

x %>%
  mutate(
    TS3 = zoo::na.approx(TS3, Date, na.rm = FALSE)
  ) %>% 
  ggplot()+
  geom_line(aes(Date, TS1), colour = 'red')+
  geom_line(aes(Date, TS2), colour = 'blue')+
  geom_line(aes(Date, TS3), colour = 'green')

enter image description here

Note that the green line finishes just short (2 data points) of the other two lines. This is because by default, zoo::na.approx() doesn't interpolate when NA is not between two known data points. This is why we specified na.rm = FALSE when doing the interpolation. Look at the help page ?zoo::na.approx for alternatives (such as repeating the last known observation).

Related