Chris Parmer — home

Unemployment rate with NBER recession shading

Macroeconomics

Example from the compendium of canonical charts

Macroeconomics — Unemployment rate with NBER recession shading

Python Code

"""Macroeconomics — Unemployment rate with NBER recession shading."""


import pandas as pd
import plotly.graph_objects as go

UNRATE_URL = "https://fred.stlouisfed.org/graph/fredgraph.csv?id=UNRATE"
USREC_URL  = "https://fred.stlouisfed.org/graph/fredgraph.csv?id=USREC"


def generate():
    print("fetching UNRATE and USREC from FRED …")
    unrate = fetch_csv(UNRATE_URL)
    usrec  = fetch_csv(USREC_URL)

    unrate.columns = ["date", "unrate"]
    usrec.columns  = ["date", "rec"]
    unrate["date"] = pd.to_datetime(unrate["date"], errors="coerce")
    usrec["date"]  = pd.to_datetime(usrec["date"],  errors="coerce")

    # Align on common date range
    df = pd.merge(unrate, usrec, on="date", how="inner").sort_values("date")
    df = df.dropna()

    # Find contiguous recession blocks
    in_rec = False
    rec_start = None
    rec_blocks = []
    for _, row in df.iterrows():
        if row["rec"] == 1 and not in_rec:
            in_rec = True
            rec_start = row["date"]
        elif row["rec"] == 0 and in_rec:
            in_rec = False
            rec_blocks.append((rec_start, row["date"]))
    if in_rec:
        rec_blocks.append((rec_start, df["date"].iloc[-1]))

    fig = go.Figure()

    # Recession vrects (add first so they sit behind the line)
    for start, end in rec_blocks:
        fig.add_vrect(
            x0=start, x1=end,
            fillcolor="gray", opacity=0.18,
            line_width=0,
        )

    # UNRATE line
    fig.add_trace(go.Scatter(
        x=df["date"],
        y=df["unrate"],
        mode="lines",
        line=dict(color=VIOLET, width=1.8),
        name="Unemployment Rate",
        hovertemplate="%{x|%b %Y}: %{y:.1f}%<extra></extra>",
    ))

    fig.update_layout(
        xaxis=dict(title=""),
        yaxis=dict(title="Unemployment Rate (%)", ticksuffix="%"),
        legend=dict(orientation="h", y=-0.14),
        margin=dict(t=50, b=70, l=70, r=40),
        annotations=[dict(
            x=0.01, y=0.97,
            xref="paper", yref="paper",
            text="Gray bands = NBER recessions",
            showarrow=False,
            font=dict(size=11, color="#60646c"),
            align="left",
        )],
    )
    return fig


if __name__ == "__main__":
    generate()

Made with Plotly