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.27.0/lattice-grid.min.css">

<script type="module">
  import { defineLatticeGrid } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.27.0/modules/webcomponent.esm.js';
  defineLatticeGrid();
</script>

<lattice-grid row-key="id" style="display: block; height: 540px"></lattice-grid>

<script type="module">
  const grid = document.querySelector('lattice-grid');
  grid.config = {
    formatting: {
      // A scale states its own bounds, so filtering the column does not rescale
      // the colours. The two ink rules run after the scale and carry
      // stopIfTrue: false, so the scale underneath 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' },
    ],
  };
  grid.rows = 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.