2 min read

Generate a Chart of Median House Prices With Mortgage Rates And Recessions in Python

A Python tutorial using free economic data
Generate a Chart of Median House Prices With Mortgage Rates And Recessions in Python
Photo by Tierra Mallorca / Unsplash

In case you want to generate a beautiful chart in Python of median house prices with mortgage rates and recessions overlaid, here's the code. It's all self-explanatory but if you need help, comment below.

import pandas as pd

import matplotlib.pyplot as plt

from pandas_datareader.data import DataReader

from datetime import datetime

save_path = "./results/median-house-price-with-mortgage-rates.png"

# Fetch median sales price data from FRED

def fetch_median_sales_price():

    """

    Fetches Median Sales Price of Houses in the US from FRED.

    Returns:

        DataFrame with date index and median sales price.

    """

    start_date = "1988-01-01"

    end_date = datetime.now()

    median_sales_price = DataReader("MSPNHSUS", "fred", start_date, end_date)

    median_sales_price.rename(columns={"MSPNHSUS": "Median Sales Price"}, inplace=True)

    return median_sales_price

# Fetch mortgage rates from FRED

def fetch_mortgage_rates():

    """

    Fetches 30-Year Fixed Mortgage Rates in the US from FRED.

    Returns:

        DataFrame with date index and mortgage rates.

    """

    start_date = "1988-01-01"

    end_date = datetime.now()

    mortgage_rates = DataReader("MORTGAGE30US", "fred", start_date, end_date)

    mortgage_rates.rename(columns={"MORTGAGE30US": "Mortgage Rates"}, inplace=True)

    return mortgage_rates

# Fetch recession data from FRED

def fetch_recession_data():

    """

    Fetches US recession data from FRED.

    Returns:

        DataFrame with date index and recession indicators.

    """

    start_date = "1988-01-01"

    end_date = datetime.now()

    recession_data = DataReader("USREC", "fred", start_date, end_date)

    return recession_data

def get_recession_periods(recessions):

    """

    Extracts periods of recessions.

    Args:

        recessions: DataFrame containing recession indicators (1 for recession, 0 otherwise).

    Returns:

        List of tuples representing start and end dates of recessions.

    """

    recession_periods = []

    in_recession = False

    start_date = None

    for date, value in recessions["USREC"].items():

        if value == 1 and not in_recession:

            in_recession = True

            start_date = date

        elif value == 0 and in_recession:

            in_recession = False

            end_date = date

            recession_periods.append((start_date, end_date))

    return recession_periods

def plot_median_sales_price_and_mortgage_rates(median_sales_price, mortgage_rates, recession_periods):

    """

    Plots the Median Sales Price of Houses and Mortgage Rates with recession periods.

    Args:

        median_sales_price: DataFrame with median sales price data.

        mortgage_rates: DataFrame with mortgage rate data.

        recession_periods: List of recession periods (start and end dates).

    """

    fig, ax1 = plt.subplots(figsize=(14, 8))

    # Plot median sales price

    ax1.plot(median_sales_price.index, median_sales_price["Median Sales Price"], color="blue", linewidth=1.5, label="Median Sales Price")

    ax1.set_xlabel("Year", fontsize=14, labelpad=10)

    ax1.set_ylabel("Median Sales Price (USD)", fontsize=14, labelpad=10, color="blue")

    ax1.tick_params(axis="y", labelcolor="blue")

    ax1.grid(visible=True, which="major", linestyle="--", linewidth=0.5, alpha=0.7)

    # Add recession periods

    for start_date, end_date in recession_periods:

        ax1.axvspan(start_date, end_date, color="gray", alpha=0.3, label="Recession" if start_date == recession_periods[0][0] else "")

    # Plot mortgage rates

    ax2 = ax1.twinx()

    ax2.plot(mortgage_rates.index, mortgage_rates["Mortgage Rates"], color="green", linewidth=1.5, linestyle="--", label="Mortgage Rates")

    ax2.set_ylabel("Mortgage Rates (%)", fontsize=14, labelpad=10, color="green")

    ax2.tick_params(axis="y", labelcolor="green")

    # Combine legends

    lines, labels = ax1.get_legend_handles_labels()

    lines2, labels2 = ax2.get_legend_handles_labels()

    ax1.legend(lines + lines2, labels + labels2, fontsize=12, loc="upper left")

    # Title and layout

    plt.title("Median Sales Price of Houses and Mortgage Rates with Recession Periods", fontsize=18, fontweight="bold", pad=20)

    plt.tight_layout()

    plt.savefig(save_path, dpi=300, bbox_inches="tight")

    plt.show()

if __name__ == "__main__":

    try:

        median_sales_price = fetch_median_sales_price()

        mortgage_rates = fetch_mortgage_rates()

        recession_data = fetch_recession_data()

        recession_periods = get_recession_periods(recession_data)

        plot_median_sales_price_and_mortgage_rates(median_sales_price, mortgage_rates, recession_periods)

    except Exception as e:

        print(f"An error occurred: {e}")