# `Ascii.Pieces.Heatmap`
[🔗](https://github.com/houllette/ascii_art/blob/main/lib/ascii/pieces/heatmap.ex#L1)

Contribution calendar, a day at a time, weeks scrolling left.

A contribution calendar, weeks across and weekdays down, shaded by how busy
each day was. As upstream draws it, days fill in one at a time and a full
week moves it left; give it `counts` and it shows your activity instead,
standing still.

## Options

Give them to `Ascii.new/2` as `options:`, and new ones while it plays
with `Ascii.put_options/2` (or a Phoenix player's `options`): the
calendar is drawn anew from them, a day's new count as soon as it comes.

  * `counts` - each day's count, oldest first, the last being `date`, up
    to a billion either way. Days are shaded in four steps of the busiest
    day's count, as GitHub does; days before the first are blank. Default
    `[]`: upstream's made-up activity, filling in a day at a time.
  * `date` - the last count's day, as `"2026-10-07"`. Default `""`: today,
    from the clock (or `now:`, see `Ascii.frame/3`).
  * `weeks` - how many weeks show, 12 to 97; the frame is two columns a
    week and six more wide, and always 12 rows tall. Default 30.
  * `unit` - what is counted, after the total under the calendar. Default
    `"contributions"`.
  * `months`, `weekdays` - the names to use, twelve from January and
    seven from Sunday, of which the scale shows the first three letters
    (months along the top, Monday, Wednesday and Friday down the side).
    English by default; a list of another length is ignored.
  * `seed` - the seed of upstream's made-up activity. Default 7.

## Colours

In one ink, or a gradient, with `:ink` and `:gradient` (see
`Ascii.Ink`); part by part with `:parts` (see `Ascii.Parts`),
`parts: true` taking the colours suggested here, GitHub's greens:

  * `scale` - the months and weekdays, grey.
  * `level.0` - an empty day, grey.
  * `level.1`, `level.2`, `level.3`, `level.4` - the days by their shade,
    quietest to busiest: dark green, green, bright green and brightest
    green.
  * `value`, `unit` - the total under the calendar, and its unit.
  * `legend` - the key's words, grey; its shades are in their levels.

## Keys and clicks

It takes none: it shows activity, and `Ascii.handle_event/2` ignores
every event. A Phoenix player given `interactive` and `notify` still tells
your LiveView where it was clicked, and on which part
(`Ascii.part_at/4`): a day's `level.3`, say.

## Screen readers

`Ascii.describe/1` reads the counts given, their total, unit and span,
and the busiest day's count: "heatmap: 19 commits in the last 12 weeks,
busiest day 9". With a `date`, the total is the frame's own; without one
it takes the last `weeks` of counts. Without counts, it gives the
piece's name and note.

## Example

```elixir
options = %{counts: [0, 1, 2, 4, 9, 3], date: "2026-10-07", unit: "commits", weeks: 12}
map = Ascii.new!("heatmap", options: options, parts: true)

{frame, _map} = Ascii.frame(map, 0.0)
{frame.cols, frame.rows}
#=> {30, 12}

Ascii.describe(map)
#=> "heatmap: 19 commits in the last 12 weeks, busiest day 9"
```

```heex
<Ascii.Phoenix.live_player id="commits" piece="heatmap" options={%{counts: @counts, unit: "commits"}} parts />
```

Ported from `src/pieces/heatmap.ts` in bas3line/ascii (MIT).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
