Chris Parmer — home

GitHub-style commit activity heatmap

Engineering — week × day of week

Example from the compendium of canonical charts

Engineering — GitHub-style commit activity heatmap (week × day of week)

Python Code

"""Engineering — GitHub-style commit activity heatmap (week × day of week)."""


import numpy as np
import pandas as pd
import plotly.graph_objects as go
import requests, warnings


REPO = "plotly/plotly.js"
COMMITS_URL = f"https://api.github.com/repos/{REPO}/stats/commit_activity"

DOW_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]


def fetch_commit_activity():
    warnings.filterwarnings("ignore")
    requests.packages.urllib3.disable_warnings()
    headers = {"Accept": "application/vnd.github+json",
               "X-GitHub-Api-Version": "2022-11-28"}
    r = requests.get(COMMITS_URL, headers=headers, verify=False, timeout=30)
    if r.status_code != 200:
        raise ValueError(f"status {r.status_code}")
    data = r.json()
    if not isinstance(data, list) or len(data) == 0:
        raise ValueError("empty response")
    return data


def generate():
    print(f"fetching commit activity for {REPO} …")

    weeks_data = None
    try:
        weeks_data = fetch_commit_activity()
        print(f"  got {len(weeks_data)} weeks")
    except Exception as e:
        print(f"  fetch failed ({e}), using synthetic data")

    if weeks_data is not None:
        # Each item: {"days": [sun,mon,...,sat], "total": N, "week": unix_ts}
        n_weeks = len(weeks_data)
        commits = np.zeros((n_weeks, 7), dtype=float)
        week_starts = []
        for i, w in enumerate(weeks_data):
            commits[i] = w.get("days", [0] * 7)
            week_starts.append(pd.Timestamp(w["week"], unit="s"))
        week_labels = [f"W{i+1}" if i % 4 != 0 else ts.strftime("%b '%y")
                       for i, ts in enumerate(week_starts)]
    else:
        rng = np.random.default_rng(134)
        n_weeks = 52
        # Simulate: more commits mid-week, seasonal variation
        base = rng.poisson(2, (n_weeks, 7)).astype(float)
        base[:, 0] *= 0.2   # less on Sunday
        base[:, 6] *= 0.3   # less on Saturday
        base[:, 1:5] *= 1.5  # more Mon-Thu
        # Seasonal dip in Aug
        base[28:32] *= 0.4
        commits = base
        week_labels = [f"W{i+1}" for i in range(n_weeks)]

    # Layout: x=week, y=day of week (Mon at top)
    # Reorder days: Mon to Sun (0=Mon ... 6=Sun)
    DOW_ORDER = [1, 2, 3, 4, 5, 6, 0]  # Mon...Sat, Sun
    DOW_DISPLAY = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
    z = commits[:, DOW_ORDER].T   # shape (7, n_weeks)

    fig = go.Figure()

    fig.add_trace(go.Heatmap(
        x=list(range(len(week_labels))),
        y=DOW_DISPLAY,
        z=z,
        colorscale=[
            [0.0,  "#ebedf0"],   # empty / GitHub light grey
            [0.001,"#9be9a8"],
            [0.25, "#40c463"],
            [0.6,  "#30a14e"],
            [1.0,  "#216e39"],   # GitHub dark green
        ],
        zmin=0,
        colorbar=dict(title="Commits", thickness=12, len=0.6),
        xgap=2, ygap=2,
        hovertemplate="Week %{x}<br>%{y}: %{z:.0f} commits<extra></extra>",
    ))

    # Month separator annotations
    tick_vals, tick_texts = [], []
    for i, lbl in enumerate(week_labels):
        if "'" in lbl:   # month label
            tick_vals.append(i)
            tick_texts.append(lbl)

    fig.update_layout(
        xaxis=dict(
            tickvals=tick_vals,
            ticktext=tick_texts,
            tickangle=0,
            showgrid=False,
        ),
        yaxis=dict(showgrid=False, autorange="reversed"),
        margin=dict(t=30, b=50, l=60, r=80),
        height=220,
    )

    return fig


if __name__ == "__main__":
    generate()

Made with Plotly