Skip to content

feat(vegalite): add Calendar Heatmap template#64

Open
zl190 wants to merge 2 commits into
microsoft:devfrom
zl190:feat/vegalite-calendar
Open

feat(vegalite): add Calendar Heatmap template#64
zl190 wants to merge 2 commits into
microsoft:devfrom
zl190:feat/vegalite-calendar

Conversation

@zl190

@zl190 zl190 commented Jul 21, 2026

Copy link
Copy Markdown

What

Adds a Calendar Heatmap template to the Vega-Lite backend, bringing it to
parity with the ECharts backend (ecCalendarHeatmapDef).

ECharts has a first-class calendar coordinate system; Vega-Lite has none. The
ECharts calendar.ts header notes that VL "has no first-class calendar; would
fake it with rect + computed week/day fields." It turns out no computed fields
are needed — timeUnit expresses the GitHub-style grid directly from a single
date field:

  • xtimeUnit: 'yearweek' (one ordinal column per calendar week)
  • ytimeUnit: 'day' (Sun–Sat rows, Monday-first to match the ECharts dayLabel.firstDay = 1)
  • coloraggregate: 'sum' collapses rows sharing a calendar day into one cell

so the same date field drives both axes with no core changes.

Encoding

channel role
x (date) the date of each cell
color (quantitative) the cell value; falls back to a per-day count when omitted

Scheme handling

Mirrors the ECharts template's encodingActions: named Vega-Lite schemes
(viridis/blues/greens/reds/oranges/purples) pass through as
scale.scheme; github has no built-in Vega-Lite equivalent, so it resolves to
an explicit scale.range (the same low→high ramp the ECharts template uses).

Changes

  • vegalite/templates/calendar.ts — new vlCalendarHeatmapDef
  • register in vlTemplateDefs (Tables & Maps group, next to Heatmap)
  • tests/calendar-vegalite.test.ts — 8 cases: registry, dual-axis timeUnit
    projection, Monday-first row order, per-day sum, count fallback, github
    range vs named scheme, and cross-backend parity. The assembled spec is also
    verified through vl.compile.
  • regenerate docs/reference-vegalite.md; move Calendar Heatmap from the
    SKILL.md "ECharts adds" list into the shared template table (+ synced bundled
    asset)

Open questions

  • Weekday-first convention: rows are Monday-first to stay consistent with the
    shipped ECharts calendar (dayLabel.firstDay = 1), so the same spec renders the
    same way on both backends. This differs from GitHub's own contribution graph,
    which starts the week on Sunday. I kept parity with the existing backend rather
    than mirroring GitHub. If you'd rather the canonical calendar follow GitHub
    (Sunday-first), that's a cross-backend convention change — ECharts and Vega-Lite
    together — which I'm happy to do as a separate PR so the two backends stay aligned.
  • Multi-year spans: yearweek produces a continuous band that widens with
    range; the ECharts template shrinks its cell size instead. This PR relies on
    labelOverlap + the container width. Happy to add explicit cell sizing if you
    prefer.
  • Recommendation layer: I did not add a Calendar recommendation rule (a
    temporal x + quantitative color heuristic). Let me know if you'd like one.

zl190 and others added 2 commits July 20, 2026 12:40
Port the Calendar Heatmap to the Vega-Lite backend, mirroring the
ECharts implementation (ecCalendarHeatmapDef). ECharts uses a first-class
calendar coordinate system; Vega-Lite has none, but it needs no computed
week/day fields either — timeUnit expresses the GitHub-style grid from a
single date field: yearweek on x (one ordinal column per calendar week),
day on y (Sun–Sat rows, Monday-first to match the ECharts dayLabel), and
sum on color collapses rows sharing a calendar day into one cell.

The upstream ECharts calendar.ts header notes VL "has no first-class
calendar; would fake it with rect + computed week/day fields" — timeUnit
avoids the computed fields, so no core changes are needed.

Scheme handling mirrors the ECharts template's encodingActions: named
Vega-Lite schemes (viridis/blues/greens/reds/oranges/purples) pass
through as scale.scheme; "github" has no built-in Vega-Lite equivalent,
so it resolves to an explicit scale.range (the same low→high ramp the
ECharts template uses).

- register in vlTemplateDefs (Tables & Maps group, next to Heatmap)
- tests: 8 cases (registry, dual-axis timeUnit projection, Monday-first
  row order, per-day sum, count fallback, github range vs named scheme,
  cross-backend parity); assembled spec also verified through vl.compile
- docs: regenerate reference-vegalite.md; move Calendar Heatmap from the
  SKILL.md "ECharts adds" list into the shared template table (+ synced
  bundled asset)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `github` scheme now maps counts through a quantile scale (equal-count
bins → the 5 canonical GitHub buckets) instead of a continuous ramp, so a
Calendar Heatmap with `color.scheme: 'github'` renders the discrete, snapped
levels people recognize from the GitHub contribution graph.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant