Lattice Grid Buy a licence

demo D47

Colour scales

A heat map across a numeric column, between bounds you declare

formatting scale rules

Building…
Loading a live grid…

The configuration

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.js"></script>

<div id="grid" style="height: 540px"></div>

<script>
  const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
    rowKey: 'id',
    formatting: {
      // A scale states its own bounds. They are not derived from the rows, so
      // filtering the column does not rescale the colours. The two ink rules
      // run after the scale and carry stopIfTrue: false so the scale's
      // neighbour is still reached: this is the layering the ordered list is for.
      monthlyCost: [
        { id: 'cost-scale', scale: { min: 0, max: 42000, colours: ['#f5f7fa', '#1a6bc7'] } },
        { id: 'cost-ink-high', when: { op: 'gte', value: 21000 }, style: { color: '#ffffff' }, stopIfTrue: false },
        { id: 'cost-ink-low', when: { op: 'lt', value: 21000 }, style: { color: '#16202b' }, stopIfTrue: false },
      ],
      // Three stops rather than two: the middle colour is reached at the middle
      // of the range, which is what makes a latency column read as good,
      // borderline, bad.
      p99Ms: [
        { id: 'p99-scale', scale: { min: 90, max: 4100, colours: ['#e8f5ee', '#fdf3e0', '#fbeceb'] } },
        { id: 'p99-ink', when: { op: 'notBlank' }, style: { color: '#16202b' }, stopIfTrue: false },
      ],
    },
    columns: [
      { field: 'service', title: 'Service', layout: { pin: 'start', width: 140 } },
      { field: 'team', title: 'Team', filter: { type: 'set' } },
      { field: 'region', title: 'Region', filter: { type: 'set' } },
      { field: 'p99Ms', title: 'p99 ms', type: 'number', filter: { type: 'number' } },
      { field: 'monthlyCost', title: 'Monthly cost', type: 'number', filter: { type: 'number' }, format: { style: 'currency', currency: 'USD' }, total: 'sum' },
    ],
    rows,  // service records
  });
</script>

Heat-mapping a numeric column with colour scales

A colour scale shades each cell in a numeric column by where its value sits between a declared minimum and maximum, so a column of margins or temperatures reads as a heat map rather than a list of digits. A developer reaches for it when the pattern across a column matters more than any single figure: spotting the worst-performing row in a sales sheet, or the outlier reading in a sensor log, without scanning every number by eye. Lattice Grid configures this through formatting scale rules, a column option taking the bounds and a colour range and interpolating the background for every cell, so the shading updates as values change rather than needing a fixed lookup table. The interpolation runs once per cell against the declared bounds, so a scale over several thousand rows costs the same per cell as a plain formatter, and the JavaScript data grid does not recompute the range on every scroll or resize. Colour alone never carries the only signal: the underlying value stays visible in the cell text, so a viewer relying on a screen reader or unable to distinguish the colour range still gets the figure the shading describes. Bounds can be fixed values or derived from the data, tracking a known target range or the spread present in the current rows.

How do I add a colour scale or heat map to a data grid column?

Apply a formatting scale rule to the column, giving it a minimum, a maximum and the colours to interpolate between. Lattice Grid shades each cell’s background by where its value falls in that range, recalculating per cell without a separate lookup pass. Bounds can be fixed numbers or derived from the visible data, and the cell text stays legible so the colour is a supplement to the value, not a replacement for it.