Skip to content

CO2 timeseries

Shows the yearly CO2 measurements from the Mauna Loa Observatory in Hawaii.

The data is sourced from the datasets/co2-ppm-daily.

Highlights:

  • Uses wrap_matplotlib to automatically handle saving and closing the figure.
  • Uses a custom renderer function to create each frame of the animation.
  • Uses Paused to pause the animation at notable dates.
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator
from streamjoy import stream, wrap_matplotlib, Paused

URL = "https://raw.githubusercontent.com/datasets/co2-ppm-daily/master/data/co2-ppm-daily.csv"
NOTABLE_YEARS = {
    1958: "Mauna Loa measurements begin",
    1979: "1st World Climate Conference",
    1997: "Kyoto Protocol",
    2005: "exceeded 380 ppm",
    2010: "exceeded 390 ppm",
    2013: "exceeded 400 ppm",
    2015: "Paris Agreement",
}


@wrap_matplotlib()
def renderer(df):
    plt.style.use("dark_background")

    fig, ax = plt.subplots(figsize=(7, 5))
    fig.patch.set_facecolor("#1b1e23")
    ax.set_facecolor("#1b1e23")
    ax.set_frame_on(False)
    ax.axis("off")
    ax.set_title(
        "CO2 Yearly Max",
        fontsize=20,
        loc="left",
        fontname="Courier New",
        color="lightgrey",
    )

    # draw line
    df.plot(
        y="value",
        color="lightgrey",  # Line color
        legend=False,
        ax=ax,
    )

    # max date
    max_date = df["value"].idxmax()
    max_co2 = df["value"].max()
    ax.text(
        0.0,
        0.92,
        f"{max_co2:.0f} ppm",
        va="bottom",
        ha="left",
        transform=ax.transAxes,
        fontsize=25,
        color="lightgrey",
    )
    ax.text(
        0.0,
        0.91,
        f"Peaked in {max_date.year}",
        va="top",
        ha="left",
        transform=ax.transAxes,
        fontsize=12,
        color="lightgrey",
        fontname="Courier New",
    )

    # draw end point
    date = df.index[-1]
    co2 = df["value"].values[-1]
    diff = df["diff"].fillna(0).values[-1]
    diff = f"+{diff:.0f}" if diff >= 0 else f"{diff:.0f}"
    ax.scatter(date, co2, color="red", zorder=999)
    ax.annotate(
        f"{diff} ppm",
        (date, co2),
        textcoords="offset points",
        xytext=(-10, 5),
        fontsize=12,
        ha="right",
        va="bottom",
        color="lightgrey",
    )

    # draw source label
    ax.text(
        0.0,
        0.03,
        f"Source: {URL}",
        va="bottom",
        ha="left",
        transform=ax.transAxes,
        fontsize=8,
        color="lightgrey",
    )

    # properly tighten layout
    plt.subplots_adjust(bottom=0, top=0.9, right=0.9, left=0.05)

    # pause at notable years
    year = date.year
    if year in NOTABLE_YEARS:
        ax.annotate(
            f"{NOTABLE_YEARS[year]} - {year}",
            (date, co2),
            textcoords="offset points",
            xytext=(-10, 3),
            fontsize=10.5,
            ha="right",
            va="top",
            color="lightgrey",
            fontname="Courier New",
        )
        return Paused(ax, 2.8)
    else:
        ax.annotate(
            year,
            (date, co2),
            textcoords="offset points",
            xytext=(-10, 3),
            fontsize=10.5,
            ha="right",
            va="top",
            color="lightgrey",
            fontname="Courier New",
        )
        return ax


if __name__ == "__main__":
    df = (
        pd.read_csv(URL, parse_dates=True, index_col="date")
        .resample("1YE")
        .max()
        .interpolate()
        .assign(
            diff=lambda df: df["value"].diff(),
        )
    )
    stream(df, renderer=renderer, max_frames=-1, threads_per_worker=1).write("co2_emissions.mp4")