Skip to content

PlHeatmapChart

A magnitude per cell, coloured rather than measured. Two shapes of one idea: a grid for two categorical axes, a treemap for parts of a whole.

React
tsx
import { PlHeatmapChart } from 'plass-ui';

<PlHeatmapChart series={week} categories={hours} />;
dart
import 'package:plass_ui/plass_ui.dart';

PlHeatmapChart(series: week, categories: hours);

Reach for the grid when both axes are categorical and the question is where, which hour of which day, which cohort in which week. A bar chart of the same data would be forty bars nobody can scan.

Colour here encodes size and not identity, so it comes off a one-hue ramp rather than the categorical palette. A heatmap in eight hues says its cells are eight unrelated things.

Props

PropTypeDefaultDescription
series * readonly PlassChartSeries[]The rows. Each series is a row of the grid or a group of the treemap
categoriesreadonly PlassChartCategory[]The column names
shape'grid' | 'treemap''grid'A grid for two categorical axes and one magnitude; a treemap for tiles packed by share
scale'sequential' | 'diverging''sequential'One hue pale to deep, or two hues either side of a neutral
midpointnumber0Where a diverging scale turns over
minnumberWhere the scale starts. Taken from the data otherwise
maxnumberAnd where it ends
valueLabels'none' | 'all''none'Writes each cell's value on it where it fits. A label that does not fit is dropped
legendboolean | Pick<PlassChartLegend, 'side' | 'align'>Where the scale legend sits. false leaves it off
tooltipPlassChartTooltipThe tooltip
heightnumber | stringHow tall the plot is
formatIntl.NumberFormatOptionsHow a value is written
labelstring'Chart'What the whole drawing is called
emptyReactNodeWhat is drawn when there is nothing to draw
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Type scale and plot height
PropTypeDefaultDescription
series * List<PlassChartSeries>The rows. Each series is a row of the grid or a group of the treemap
categoriesList<PlassChartCategory>?The column names
shapePlHeatmapShapePlHeatmapShape.gridA grid for two categorical axes and one magnitude; a treemap for tiles packed by share
scalePlChartScaleKindPlChartScaleKind.sequentialOne hue pale to deep, or two hues either side of a neutral
midpointdouble0Where a diverging scale turns over
mindouble?Where the scale starts. Taken from the data otherwise
maxdouble?And where it ends
valueLabelsPlHeatmapLabelsPlHeatmapLabels.noneWrites each cell's value on it where it fits. A label that does not fit is dropped
legendPlChartLegendPlChartLegend()The scale legend. Only its side and align are read: there is nothing on a scale to switch off
tooltipPlChartTooltipPlChartTooltip()The tooltip
heightdouble?How tall the plot is
formatString Function(double)?How a value is written
semanticLabelString?'Chart'What the whole drawing is called
emptyWidget?What is drawn when there is nothing to draw
sizesharedPlassSizePlassSize.mdType scale and plot height

Each series is a row of the grid or a group of the treemap, and each datum a cell or a tile. A null leaves the cell as surface rather than drawing it as the bottom of the scale, because "nothing happened" and "the least of anything" are not the same reading.

One ladder covers the whole chart rather than one per row. The colour of a cell has to mean the same number wherever it is, which is the entire promise a heatmap makes.

Examples

shape

React

A treemap is for parts of a whole with more parts than a pie chart can hold, and it is the same component because the data is the same shape: a row of a heatmap and a group of a treemap are both a named series of named magnitudes.

The packing is squarified rather than sliced. A slice-and-dice treemap of twenty values ends in slivers a pixel wide, and a sliver's area is unreadable however exact it is, the reader compares its length instead, which is not the encoded quantity.

A tile's area is its share, so a negative value has no area to be. It stays in the table and off the picture.

A treemap has no axes: its tiles are named on their own faces, which is the trade it makes for filling the box edge to edge.

scale

React

sequential is one hue, pale to deep, and is right whenever more is simply more. diverging is two hues either side of a neutral, for a value with a middle that means something, over and under target, gained and lost. Reached for on a plain magnitude it invents a boundary the data has none of.

A diverging scale is read from its middle rather than from its bottom, and both arms reach as far as the further one, so a set running from −2 to +40 does not paint every negative the deepest blue there is.

valueLabels

Writes each cell's value on it where the cell is big enough for the text with room either side. A label that does not fit is dropped rather than clipped: a missing label sends the reader to the tooltip, and a clipped one sends them nowhere.

On a treemap the name comes first and the value only if there is still room under it, because nothing else on a treemap names its tiles. On a grid both coordinates are already written down the side and along the bottom, so the only thing left to write is the number.

Accessibility

  • The drawing carries the chart's name, and every cell is handed over as text, each row, then its cells as name-and-value pairs.
  • On React the picture is a role="img" and a tab stop; the arrow keys walk the cells and Escape clears the readout, with each cell announced in a live region as it is reached.
  • On React the same numbers are written into a table under the chart, with both sets of names on it: rows down the side, columns across the top.
  • The label written inside a cell is the one place in the library where text does not wear an ink token. Which of the two it wears is decided per ramp step, where the step's lightness is known and the answer flips between the themes.
  • The scale legend names both ends, and the middle too when the scale diverges.

Released under the MIT License