Climate Warming Stripes — plotnine

Climate warming stripes (also known as "warming stripes") display temperature anomaly data as a sequence of vertical colored bars, one per year, using a blue-to-red diverging colormap. Created by climate scientist Ed Hawkins, this minimalist visualization strips away axes, labels, and gridlines to communicate long-term warming trends through pure color encoding. The progression from cool blues to warm reds makes temperature change immediately visible at a glance.

Climate Warming Stripes rendered with plotnine

Python source (plotnine)

""" anyplot.ai
heatmap-stripes-climate: Climate Warming Stripes
Library: plotnine 0.15.4 | Python 3.13.13
Quality: 87/100 | Updated: 2026-06-02
"""

import os

import numpy as np
import pandas as pd
from plotnine import (
    aes,
    after_stat,
    element_rect,
    element_text,
    geom_tile,
    ggplot,
    guides,
    labs,
    scale_fill_gradient2,
    scale_x_continuous,
    scale_y_continuous,
    theme,
    theme_void,
)


# Theme tokens (see prompts/default-style-guide.md "Theme-adaptive Chrome")
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"

# Data
np.random.seed(42)
years = np.arange(1850, 2025)
n_years = len(years)

base_trend = np.linspace(-0.3, 0.2, n_years)
years_since_1980 = np.maximum(years - 1980, 0).astype(float)
acceleration = years_since_1980**1.6 * 0.0008
noise = np.random.normal(0, 0.08, n_years)
anomaly = base_trend + acceleration + noise
anomaly -= np.mean(anomaly[(years >= 1961) & (years <= 1990)])

df = pd.DataFrame({"year": years, "anomaly": anomaly})

# Plot
vmax = max(abs(anomaly.min()), abs(anomaly.max()))

title = "heatmap-stripes-climate · python · plotnine · anyplot.ai"
n = len(title)
title_size = round(12 * (67 / n)) if n > 67 else 12

plot = (
    ggplot(df, aes(x="year", y=after_stat("1"), fill="anomaly"))
    + geom_tile(aes(width=1, height=1))
    + scale_fill_gradient2(low="#4467A3", mid=PAGE_BG, high="#AE3030", midpoint=0, limits=(-vmax, vmax))
    + scale_x_continuous(expand=(0, 0))
    + scale_y_continuous(expand=(0, 0))
    + guides(fill=False)
    + labs(title=title)
    + theme_void()
    + theme(
        figure_size=(8, 4.5),
        plot_title=element_text(size=title_size, ha="center", weight="bold", color=INK, margin={"b": 10}),
        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
        panel_background=element_rect(fill=PAGE_BG),
        plot_margin=0.01,
    )
)

# Save
plot.save(f"plot-{THEME}.png", dpi=400, width=8, height=4.5, units="in", verbose=False)

Part of Climate Warming Stripes on anyplot.ai.

Other implementations