Skip to main content

Heatmap

Basic Configuration

The Heatmap component renders a flat array of values as a grid of colored cells — like the GitHub contributions calendar. It works inside a Single Container and only needs a value accessor. The data can be an array of objects or, as below, a plain array of numbers:

component.tsx
import { VisSingleContainer, VisHeatmap } from '@unovis/react'

function Component(props) {
const data: number[] = props.data
const value = (d: number) => d

return (
<VisSingleContainer data={data}>
<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
/>
</VisSingleContainer>
)
}
Loading...

Grid Dimensions

The array is laid out into a grid whose size you control with numRows and/or numColumns. By default the grid has 7 rows and the data fills column by column (layout: HeatmapLayoutType.Column) — each column completes top-to-bottom before the next begins, just like GitHub weeks. Set layout: HeatmapLayoutType.Row to fill row by row instead.

<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
/>
Loading...

Empty Cells & Offset

When the value accessor returns null or undefined, the cell is rendered empty (using the --vis-heatmap-cell-fill-color variable). Use offset to leave empty cells before the first datum — handy for aligning the first value to a specific weekday:

<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
offset={3}
/>
Loading...

Color

By default cells are colored with a quantized green scale (configurable via the --vis-heatmap-color-* CSS variables). Pass colorRange to use your own bucket colors, colorDomain to fix the [min, max] mapping, or a per-cell color accessor for full control:

component.tsx
function Component(props) {
const data: number[] = props.data
const value = (d: number) => d
const colorRange = [`#e0e7ff`, `#a5b4fc`, `#6366f1`, `#4338ca`]

return (
<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
colorRange={colorRange}
/>
)
}
Loading...
// Quantized bucket colors (value → color)
colorRange={['#e0e7ff', '#a5b4fc', '#6366f1', '#4338ca']}

// Fix the domain so the scale doesn't depend on the data extent
colorDomain={[0, 20]}

// Or take full control per cell
color={d => d > 10 ? '#4338ca' : '#a5b4fc'}

Cell Appearance

Cell Size

By default cells stretch to fill the container. Set cellSize to render fixed-size square cells (the component then reports its own size, which pairs with the container's Sizing.Extend).

<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
/>
Loading...

Cell Padding

cellPadding is the gap between cells in pixels.

<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
/>
Loading...

Corner Radius

cellCornerRadius rounds the cell corners (pass a number, or true for a default radius of 2).

<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
/>
Loading...

Labels

Because the Heatmap isn't an XY component, labels are built in. Provide columnLabel and/or rowLabel accessors — each is called per index and may return undefined to skip a label. Column labels render above the grid, row labels to the left:

<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
rowLabel={rowLabel}
/>
Loading...
// GitHub-style: months across the top, alternating weekdays on the left
columnLabel={column => /* month name on the first column of each month */}
rowLabel={row => ['', 'Mon', '', 'Wed', '', 'Fri', ''][row]}

Handling Overlap

When many labels are packed into a small space their text can collide. By default (labelHideOverlapping: true) the Heatmap hides overlapping labels, resolving each axis independently and keeping the top-most row label and left-most column label of every colliding group. Toggle it off to always render every label:

<VisHeatmap
value={value}
numRows={8}
cellSize={12}
cellPadding={2}
cellCornerRadius={3}
columnLabel={columnLabel}
rowLabel={rowLabel}
labelHideOverlapping={true}
/>
Loading...

Events

The following selectors are available for events:

import { Heatmap } from '@unovis/ts'
...
events = {
[Heatmap.selectors.cell]: { },
}
<VisHeatmap
value={value}
numRows={7}
cellSize={16}
cellPadding={3}
cellCornerRadius={3}
events={events}
/>

CSS Variables

All supported CSS variables and their default values
--vis-heatmap-cell-fill-color: #ebedf0;
--vis-heatmap-cell-stroke-color: transparent;
--vis-heatmap-cell-stroke-width: 0px;
--vis-heatmap-cell-cursor: default;
--vis-heatmap-color-1: #9be9a8;
--vis-heatmap-color-2: #40c463;
--vis-heatmap-color-3: #30a14e;
--vis-heatmap-color-4: #216e39;
--vis-heatmap-label-color: #6e7781;
--vis-heatmap-label-font-size: 12px;
--vis-heatmap-label-font-family: undefined;
--vis-heatmap-label-font-weight: 400;
--vis-dark-heatmap-cell-fill-color: #161b22;
--vis-dark-heatmap-color-1: #0e4429;
--vis-dark-heatmap-color-2: #006d32;
--vis-dark-heatmap-color-3: #26a641;
--vis-dark-heatmap-color-4: #39d353;
--vis-dark-heatmap-label-color: #7d8590;

Component Props

NameTypeDescription
* required property