Skip to main content

Contribution heatmap

The GitHub profile grid, rebuilt from its own raw material — and the subject is this repository. Every cell is one UTC day of pond's default branch; colour carries the non-merge commit count. A heat map is the right shape whenever the question is "when was the activity?" asked across two time scales at once: weeks along the x axis, the shape of a week down the y.

The chart​

Point at a cell for its day and count. Sundays are the top row, Saturdays the bottom — GitHub's reading — and the columns run from the repo's first week (12 April 2026) to the current, deliberately partial one. The brightest cell is Wednesday 13 May: 35 commits; the heaviest column is the week of 2 August: 129.

The data​

Real measured data — this repo's own. The GitHub REST API's commit_activity statistics for pond-ts/pond: the numbers behind the repository's own activity graph, retrieved the day this card was built. 1,001 commits across 126 days — 18 Sunday-start UTC weeks, from first commit to the moment of retrieval.

ColumnMeaning
sun … satNon-merge commits that weekday, one row per UTC week

Three binning rules matter, and the generator refuses to emit if any stops holding. Merge commits are excluded — the API total matches git rev-list --count --no-merges origin/main exactly, which is how the claim was pinned. Days are UTC, so a late CEST evening's commits land in the next row. And the API serves a fixed 52-week window; the 34 leading all-zero weeks (the repo is four months old) are trimmed, while the current week keeps its honest trailing zeros — days that haven't happened yet.

What the grid shows about how pond is built: 26 of the 126 days are quiet; the other hundred average 10 commits a day, with a 26-day unbroken streak in there. And the usual profile-heatmap tell is missing — there is no weekend stripe. Sundays (142 commits) outwork Thursdays (113), because much of this history is multi-agent experiment sessions, and agents don't know it's Saturday.

Build it​

1. Shape the data wide — and key the weeks as spans. <HeatMap> wants its y dimension as columns: one column per row of the grid, one sample per x bin — the same wide shape the Niño 3.4 grid uses for its 45 year-rows. The x bins here are range-keyed (timeRange, each week carrying its own start/end), because a week is a span: a point-keyed series would leave the layer to infer each cell's bin from the midpoints to its neighbours, and every cell would straddle its week's start by ±3.5 days. Same rule as bars on auction hours in negative prices.

const series = commitActivity(); // one row per week: sun, mon, … sat

<ChartContainer range={commitActivityRange()} width={width}>
<LineCursor />
<ChartRow height={210}>
<YAxis id="dow" ticks={COMMIT_ROW_TICKS} label="" width={44} />
<Layers>
<HeatMap series={series} columns={COMMIT_ROWS} colors={ramp} axis="dow" />
</Layers>
</ChartRow>
</ChartContainer>;

2. Order the rows for the reading you want. <HeatMap> draws the first column at the bottom, and the GitHub convention puts Sunday on top — so the row list runs sat → sun. The y ticks label only Mon / Wed / Fri (GitHub's three), each at its row's centre:

export const COMMIT_ROWS = ['sat', 'fri', 'thu', 'wed', 'tue', 'mon', 'sun'];
export const COMMIT_ROW_TICKS = [
{ at: 1.5, label: 'Fri' },
{ at: 3.5, label: 'Wed' },
{ at: 5.5, label: 'Mon' },
];

3. Read cells with a real 2-D hit. The hover readout is fed by <Selector onHover>, which resolves the cell under the pointer on both axes. The 1-D tracker can't do this — it samples every row at the cursor's x and knows nothing about y:

<Selector onHover={setHit}>
<ChartRow height={210}>…</ChartRow>
</Selector>

The hit's label is the row (the weekday column's name), its key is the week's start — together they name one day, which is what the readout prints.

Options to try​

OptionWhat it doesReach for it when
colorsThe ramp the counts map intoThis card uses the site's sequential ramp; a fixed-hue ramp survives theme changes
domainPins the colour scale's extentComparing two heat maps, or keeping colours stable as data updates — see Niño 3.4
Re-bin x with pondaggregate(Sequence.calendar('month'))Months instead of weeks — climate-stripes-style summaries of the same columns
Fewer / more ticksWhich rows get namedSeven rows read fine with three labels; forty-five need explicit picks
timeFormatThe x axis's date renderingWeekly bins often want month names, not day-precision dates

See also​

  • Measles and the vaccine — the same layer at 50 rows × 81 years, with a log-scaled colour domain
  • Niño 3.4 — the wide-series shape this grid borrows, and the re-binning story
  • Storybook — the systematic knob walk