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

import * as ng from '@angular/core';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import createLatticeGrid from '@toclocoinc/lattice-grid/modules/angular';

const { LatticeGridComponent } = createLatticeGrid({ ng, createGrid });

const 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 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 },
  ],
};

const 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' },
];

const rows = [/* service records */];



@Component({
  selector: 'app-root',
  standalone: true,
  imports: [LatticeGridComponent],
  template: '<lattice-grid [config]="grid" style="display:block;height:540px"></lattice-grid>',
})
export class AppComponent {
  grid = {
    rowKey: 'id',
    formatting: formatting,
    columns: columns,
    rows: rows,
  };
}

bootstrapApplication(AppComponent);

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.