HeatmapChart
A magnitude per cell, coloured rather than measured. Two shapes of one idea: a grid, for two categorical axes and one number; and a treemap, for parts of a whole with more parts than a pie can hold.
import { HeatmapChart } from 'neba';
<HeatmapChart
label="Sessions by hour and weekday"
categories={['00', '06', '12', '18']}
series={[
{ name: 'Mon', data: [4, 24, 51, 18] },
{ name: 'Tue', data: [3, 27, 55, 20] }
]}
/>;The data
The series shape is the one every chart shares: see LineChart for the full definition. Here a series is a row of the grid or a group of the treemap, y is the magnitude, and x names the column or the tile.
A null is a gap and the cell is left as surface. It is not drawn as the bottom of the scale, because "nothing happened" and "the least of anything" are two different readings and only one of them is in the data.
The scale runs across every cell in the chart rather than per row. A colour has to mean the same number wherever it appears, which is the whole promise a heatmap makes; min and max pin the ends where a comparison needs a fixed frame.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| series * | NebaChartSeries[] | — | A series is a row of the grid or a group of the treemap. y is the magnitude and x names the column or tile; a null is a gap and its cell is not drawn |
| categories | (string | number | Date)[] | — | The column names. Points may carry their own x instead |
| shape | 'grid' | 'treemap' | 'grid' | grid is a cell per row and column; treemap packs a tile per datum, sized by its share |
| scale | 'sequential' | 'diverging' | 'sequential' | sequential is one hue pale to deep; diverging is two hues either side of a neutral grey. Reach for diverging only when there is a real zero to diverge about |
| midpoint | number | 0 | Where a diverging scale turns over |
| min | number | — | Where the scale starts. Taken from the data otherwise, so two charts are not comparable until they are given the same bounds |
| max | number | — | Where the scale ends |
| valueLabels | 'none' | 'all' | 'none' | Writes each value on its cell. A label that does not fit is dropped rather than clipped, and its ink is picked from the step underneath it |
| legend | boolean | { side, align } | true | A scale bar with its ends labelled, not a list of swatches: nothing here has a name and the order is the meaning |
| variantshared | 'solid' | 'outline' | 'text' | 'text' | Weight of the surface. A chart is a drawing rather than a sheet, so this defaults to text and a chart inside a Card draws no second edge. Use outline for one that stands alone |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Axis type, line weight, marker size, and the height, when none is given |
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | The sheet's colour family. A series' colour does not come from here: the palette or series.color decides that |
| densityshared | 'default' | 'compact' | 'default' | Padding only: never the height, never the type scale |
| elevationshared | 0 | 1 | 2 | 3 | 0 | Drop shadow depth. 0 means no shadow at all |
| height | number | string | size | How tall the drawing is. The axis labels are drawn inside it, so a card sized to the chart is a card the chart fits in |
| label | string | locale's word | The chart's accessible name. Read out in place of the drawing, and the caption of the hidden data table under it. Without it the locale's generic word stands in, but what the chart is *of* can only be said here |
| format | Intl.NumberFormatOptions | — | How numbers are written everywhere they appear: the axis, the tooltip, the value labels, the table. Without it, past ten thousand they are compacted (12.4K) |
| locale | string | — | The language of the chart's own words and dates |
| legend | boolean | NebaChartLegend | series ≥ 2 | Shown automatically from two series up and left off below that: a legend with one swatch restates the title |
| tooltip | boolean | NebaChartTooltip | true | What the pointer uncovers. It never carries a value that is not also in the hidden table |
| empty | ReactNode | — | What to draw when there is nothing to draw |
Every native <div> attribute passes through, along with every Box prop. See prop conventions for the shared axes.
Examples
shape
grid is the shape for two categorical axes and one number: hours against weekdays, a cohort against a week. treemap packs a tile per datum, sized by its share, and fills the box.
A treemap is squarified rather than sliced: tiles are laid in rows and each row is closed the moment its aspect ratios stop improving. Sliced, twenty values end as slivers a pixel wide, and a sliver's area is unreadable however exact it is.
A treemap has no axes (every tile is named on its own face), and a negative value has no area to be, so it stays in the table and off the picture.
scale
sequential is one hue from pale to deep, and it is right whenever more is simply more. diverging is two hues either side of a neutral grey, for a value with a middle that means something: over and under target, gained and lost. midpoint says where that middle is.
Reach for diverging only when there is a real zero to diverge about. On a plain magnitude it invents a boundary the data has none of, and the reader spends the chart looking for what changed at the grey.
Neither ramp is the eight-slot categorical palette: colour here encodes size, not identity, and a heatmap in eight hues says its cells are eight unrelated things.
valueLabels · min · max
valueLabels="all" writes each value on its cell, where the cell is big enough for the text with room either side; a label that does not fit is dropped rather than clipped. Inside a filled cell the label picks its ink from the step underneath it, so it stays readable at both ends of the ramp.
min and max pin the scale. Left out, the ends come from the data: which means two charts of different data are not comparable until they are given the same bounds.
legend
The legend is a scale bar with its two ends labelled, not a list of swatches: nothing here has a name, and the order is the meaning. On a diverging scale the midpoint is named under the middle of the bar. legend={false} leaves it off, and legend's own side moves it.
Accessibility
- The data is also rendered as a visually hidden table, captioned with
label, one row per series and one column per category. - The plot is focusable;
←/→walk the cells,Escapeclears the tooltip. - The scale legend gives the two ends of the range as numbers, so the ramp never has to be read by eye alone.