Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot of 2 ts-objects (time series) with 2 y axes (secondary y-axis)

I want to plot 2 ts-objects as bars and lines, respectively, using 2 y-axes. How can I do this in ggplot?

I have 2 ts-objects: one is the value of a variable, the other is the annual change. The data are monthly. I would like to plot both ts-objects into one graph, the value as line, the growth rate as bars. For this, I need a secondary y-axis, because the scales of the two variables are very different.

I usually plot ts-objects using ts.plot, which easily accommodates a secondary y-axis, but there I can't plot bars, only lines.

With ggplot, I struggle on how to use a ts-object... Using autoplot, I can produce a plot and a secondary axis, but the latter really seems independent of my data. How can I have the line and the bars overlap in the following example?

# REPRODUCIBLE EXAMPLE
library(ggplot2)
library(ggfortify)  # to use autoplot
library(seasonal)  # to get the example ts data AirPassengers
library(dplyr)  # to use the pipe-operator

# Genereate year-on-year change
YearOverYear <- function (x,periodsPerYear){
if(NROW(x)<=periodsPerYear){
stop("too few rows")
 }
 else{
 indexes<-1:(NROW(x) - periodsPerYear)
return(c(rep(NA,periodsPerYear), (x[indexes+periodsPerYear]- x[indexes]) / x[indexes]))
  }
}

AirPassengers.gr <- YearOverYear(AirPassengers, 12) %>%
              ts(., start = start(AirPassengers), frequency = 12)

p <- autoplot(AirPassengers, ts.geom = 'line', ts.colour = 'dodgerblue') 
autoplot(AirPassengers.gr*100, ts.geom = 'bar', ts.colour = 'red', p=p) +
  scale_y_continuous(sec.axis = sec_axis(~./1))
like image 408
Isabel Avatar asked Oct 19 '25 01:10

Isabel


1 Answers

Nice to meet you, Isabel

I just changed ts.object to data.table and then using basic ggplot method. Additionally, you can apply any tricky skills.

Library Load

library(ggplot2)
library(ggfortify)  # to use autoplot
library(seasonal)  # to get the example ts data AirPassengers
library(dplyr)  # to use the pipe-operator
library(zoo);library(data.table)

Data handling

YearOverYear <- function (x,periodsPerYear){
  if(NROW(x)<=periodsPerYear){
    stop("too few rows")
  }
  else{
    indexes<-1:(NROW(x) - periodsPerYear)
    return(c(rep(NA,periodsPerYear), (x[indexes+periodsPerYear]- x[indexes]) / x[indexes]))
  }
}

AirPassengers.gr <- YearOverYear(AirPassengers, 12) %>%
  ts(., start = start(AirPassengers), frequency = 12)
lubridate::as_date(time(AirPassengers))

DF = data.frame(Passengers = as.matrix(AirPassengers),
                date = zoo::as.Date(time(AirPassengers)))
DF.gr = data.frame(value = as.matrix(AirPassengers.gr),
                date = zoo::as.Date(time(AirPassengers.gr)))
DF = merge(DF,DF.gr, by = 'date')
setDT(DF)

Plotting Code

scale_value = max(DF$Passengers, na.rm = TRUE)/ max(DF$value, na.rm = TRUE)

ggplot(DF) + 
  geom_line(aes(x= date, y= Passengers), color = 'dodgerblue') +
  geom_bar(aes(x= date, y = value*scale_value), stat = 'identity') + 
  scale_y_continuous(sec.axis = sec_axis(~./scale_value, name = 'NEW'))

enter image description here

If you have any question feel free to ask.

like image 147
Steve Lee Avatar answered Oct 20 '25 16:10

Steve Lee



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!