The Coronavirus Recession

Economic outlook, counting recession lengths, chart remix

Coronavirus Recession

Over on LinkedIn I posted a summary of recent economic talks I have been giving: The Coronavirus Recession. Read the whole things for analysis and lots of charts, but I leave off with three key questions:

  • Recession was here, but is it already gone?
  • Housing market indicators have rebounded, but will the recovery be sustained?
  • After effects of shutdown and possible second wave to the pandemic remain as risks to the outlook, how big are these risks?

1,2,3,4 or is that 0,1,2,3?

Over on Twitter, Fintwit relives this epic debate on a bodybuilding forum about how many days are in a week. The Fintwit question, did the recession start in February or March 2020? I stand with Francis Diebold on this one!

Though itโ€™s easy to get turned around on this one and Iโ€™m sure Iโ€™ve been inconsistent in the past. Hopefully I can make it through this post.

Also on Twitter, I see another cool package. This one mdthemes from Thomas Neitmann which allows you to easily incorporate markdown into your ggplots with R.

Chart Remix

Speaking of recession lengths and mdthemes, letโ€™s remix the chart from my LinkedIn Post on Expanding Expansions, Contracting Recessions. Weโ€™ll also be sure to count precisely.

library(sqldf)
library(ggrepel)
library(tidyverse)
library(mdthemes)
library(lubridate)

Data prep code

#####################################################################################
## Make Recession Data Frame ##
# based on NBER dates: https://www.nber.org/cycles.html
#####################################################################################



recessions.df = read.table(textConnection(
  "Peak, Trough
  1857-06-01, 1858-12-01
  1860-10-01, 1861-06-01
  1865-04-01, 1867-12-01
  1869-06-01, 1870-12-01
  1873-10-01, 1879-03-01
  1882-03-01, 1885-05-01
  1887-03-01, 1888-04-01
  1890-07-01, 1891-05-01
  1893-01-01, 1894-06-01
  1895-12-01, 1897-06-01
  1899-06-01, 1900-12-01
  1902-09-01, 1904-08-01
  1907-05-01, 1908-06-01
  1910-01-01, 1912-01-01
  1913-01-01, 1914-12-01
  1918-08-01, 1919-03-01
  1920-01-01, 1921-07-01
  1923-05-01, 1924-07-01
  1926-10-01, 1927-11-01
  1929-08-01, 1933-03-01
  1937-05-01, 1938-06-01
  1945-02-01, 1945-10-01
  1948-11-01, 1949-10-01
  1953-07-01, 1954-05-01
  1957-08-01, 1958-04-01
  1960-04-01, 1961-02-01
  1969-12-01, 1970-11-01
  1973-11-01, 1975-03-01
  1980-01-01, 1980-07-01
  1981-07-01, 1982-11-01
  1990-07-01, 1991-03-01
  2001-03-01, 2001-11-01
  2007-12-01, 2009-06-01
  2020-02-01, 9999-01-01"), sep=',',
  colClasses=c('Date', 'Date'), header=TRUE)


df<- data.frame(date=seq.Date(as.Date("1857-01-01"), 
                              as.Date("2020-06-01"), by="1 month"))

rdf <- recessions.df %>% 
  mutate(TroughLag  = lag(Trough),  # find last trough
         PeakLag    = lag(Peak)      # find last peak
  )

# Merge with sqldf
output <- sqldf("select * from df left join rdf
                 on  (df.date>=rdf.Peak and df.date <= rdf.Trough or
                     (df.date > rdf.TroughLag and df.date <= rdf.Peak)) ")



outdf <- 
  mutate(filter(output,!is.na(TroughLag)),
         expand=ifelse(date>=Peak, "Recession","Expansion"),
         d1=ifelse(expand=="Recession",Peak %m+% months(1), TroughLag %m+% months(1)),
         d2=ifelse(expand=="Recession",Trough, Peak %m-% months(0))) %>%
  mutate(d1=as.Date(d1, origin = lubridate::origin),
         d2=as.Date(d2, origin = lubridate::origin)) %>%
  mutate(name=paste0(expand, " ",
                     as.character(d1, format="%b %Y"), " : ",
                     as.character(d2, format="%b %Y")
  )) %>%
  mutate(contraction = interval(Peak, Trough) %/% months(1),       # Peak to Trough
         expansion   = interval(TroughLag, Peak) %/% months(1),    # Previous Trough to this Peak
         cycle1      = interval(TroughLag, Trough) %/% months(1),  # Trough from previous Trough
         cycle2      = interval(PeakLag, Peak) %/% months(1))      # Peak from previous Peak


outdf2 <- 
  outdf %>% group_by(name, expand)  %>%
  summarize(start.date=min(date),
            end.date=max(date),
            contraction_peak_to_trough=mean(contraction),
            expansion_previous_trough_to_this_peak=mean(expansion),
            cycle_trough_from_previous_trough=mean(cycle1),
            cycle_peak_from_previous_peak=mean(cycle2)) %>% 
  ungroup() %>% arrange(start.date) %>%
  mutate(duration =ifelse(expand=="Recession",
                          contraction_peak_to_trough, 
                          expansion_previous_trough_to_this_peak)) %>%
  arrange(start.date) %>% filter(!is.na(expand) ) %>%
  rename(type=expand)

First letโ€™s recreate the plot we made before, without using mdthemes.

#####################################################################################
## Make Plot No mdthemes ##
#####################################################################################
ggplot(data = outdf2 %>% filter(!is.na(type)),
       aes(x=start.date, xend=end.date,
           y=duration, yend=duration, label=name,color=type))+
  scale_fill_manual(name="Expansion or Recession", values= c("#4575b4", "#d73027"))+
  scale_color_manual(name="Expansion or Recession", values= c("#4575b4", "#d73027"))+
  theme_minimal(base_size=9)+
  theme(legend.position="bottom",
        plot.caption=element_text(hjust=0,size=rel(0.8))  )+
  geom_segment(size=1.1)+
  scale_y_continuous(breaks=seq(0,130,10),limits=c(0,130),expand=c(0,0),sec.axis=dup_axis())+
  
  # even with ggrepel, labeling all points gets crowded
  geom_text_repel(data= outdf2 %>% 
                    filter(duration>40 |  (year(start.date)> 1969 | year(start.date) < 1860) 
                    ), size=3)+
  stat_smooth(method="lm", fill=NA, linetype=2, alpha=0.35)+
  #geom_rug(data=outdf,sides="b", inherit.aes=FALSE,aes(x=date,color=expand))+
  labs(x="Date",y="Duration of U.S. Expansion/Recession in Months",
       title="Expansions Expand, Recessions Contract",
       subtitle="Duration of U.S. expansions/recessions over time\n",
       caption="@lenkiefer Source: NBER recession dates as of June 16, 2020 http://www.nber.org/cycle.html\n\nSegments extend from expansion/recession start to end date on x axis, y axis equals length of expansion/recession.\nDotted lines regression fit to expansion/recession: duration ~ start.date")

Now letโ€™s use mdthemes to enhance the plot. Weโ€™ll use the markdown syntax to make the title colors correspond to recessions (red) and expansions (blue).

We will use the mdthemes::as_md_theme function to wrap theme_minimal and automagically allow us to use text styling within our title, subtitle, and caption calls to ggplot2.

#####################################################################################
## Make Plot with mdthemese##
#####################################################################################
ggplot(data = outdf2,# %>% filter(!is.na(type)),
       aes(x=start.date, xend=end.date,
           y=duration, yend=duration, label=name,color=type))+
  scale_fill_manual(name="Expansion or Recession", values= c("#4575b4", "#d73027"))+
  scale_color_manual(name="Expansion or Recession", values= c("#4575b4", "#d73027"))+
  as_md_theme(theme_minimal(base_size=9)+
                theme(legend.position="bottom",
                     plot.caption=element_text(hjust=0,size=rel(0.8))  ))+
  geom_segment(size=1.1)+
  scale_y_continuous(breaks=seq(0,130,10),limits=c(0,130),expand=c(0,0),sec.axis=dup_axis())+
  # even with ggrepel, labeling all points gets crowded
  geom_text_repel(data= outdf2 %>% 
                    filter(duration>40 |  (year(start.date)> 1969 | year(start.date) < 1860) 
                    ), size=3,show.legend = FALSE)+
  stat_smooth(method="lm", fill=NA, linetype=2, alpha=0.35)+
  #geom_rug(data=outdf,sides="b", inherit.aes=FALSE,aes(x=date,color=expand))+
  labs(x="Date",y="Duration of U.S. Expansion/Recession in Months",
       title=paste0("<span style = 'color:#4575b4'>Expansions Expand</span>,",
                    "<span style = 'color:#d73027'> Recessions Contract</span>"),
       subtitle="Duration of U.S. expansions/recessions over time\n",
       caption="<span style= 'color:#fe5305'>**@lenkiefer**</span> Source: NBER recession dates as of June 16, 2020<br>Segments extend from expansion/recession start to end date on x axis, y axis equals length of expansion/recession.<br>Dotted lines regression fit to expansion/recession: duration ~ start.date")