Customer segmentation in a data grid, 1.106
Segmenting customers or devices usually means a notebook. Someone exports the rows, runs a clustering script, pastes the segment numbers back into a spreadsheet and sends it round. A week later the data has changed and the segments are stale, because nobody wants to do it again.
This release moves the segmenting into the grid. The example above is 120 customers with their orders a month and their spend. The Segment column is a cluster column over those two numbers, and the chart draws one colour per segment. Pick a region and watch the segments found again over the rows that are left.
Customer segmentation without leaving the grid
A cluster shadow column assigns every visible row a segment id, by k-means or by density, over the numeric columns you choose. It is an ordinary column after that. You can group by it, filter it, colour a cell from it, sort it, export it and hand it to a chart as the series.
- Centres and sizes on demand.
grid.statistics.clustersreturns the centre of each segment in your columns’ own units, and how many rows each one holds. - The grid can choose k.
grid.statistics.autoKscores the options by the elbow or silhouette criterion and reports the choice. Press “Let the grid choose” above and the example rebuilds with the number it picked. - Recomputed as the rows change. Filter, edit or stream in new rows and the segments follow, because they are computed over the rows the grid is showing.
const grid = createGrid(el, {
rowKey: 'id',
rows,
columns: [
{ field: 'orders', type: 'number' },
{ field: 'spend', type: 'number' },
{ id: 'segment', title: 'Segment',
shadow: { kind: 'cluster', columns: ['orders', 'spend'], method: 'kmeans', k: 3 } },
],
});
const { k, centres, sizes } = grid.statistics.clusters('segment');
Density clustering is there for data that does not form round groups: rows that belong to no dense region read as noise rather than being forced into a segment. The statistics reference lists every option.
Drawers and dialogs from the app shell
Every app ends up writing its own drawer and its own dialog: the overlay, the focus handling, the Escape key, the stack when a dialog opens from a drawer, and a way to get the answer back to the code that asked. It is plumbing, and it is rewritten per project.
In 1.106 the app shell provides it. createDrawer slides in from the left, right, top or bottom. createDialog opens centred, with action buttons below. The body of either is a shell cell, so it can hold a grid, a form or plain markup. Overlays stack, trap focus while open, close on Escape or a backdrop click, and take a size in pixels, a percentage or 'content'.
The part that saves the most code is the result. Each overlay returns a closed promise, and it resolves with the value of the button the user chose.
Open the drawer below, press the cancel button inside it, and choose from the dialog. Escape closes the top overlay, and the result line shows what the promise returned.
const dialog = createDialog({
title: 'Cancel order 4471?',
content: '<p>The customer is emailed.</p>',
actions: [{ label: 'Keep it', value: 'keep' }, { label: 'Cancel order', value: 'cancel' }],
});
dialog.open();
const choice = await dialog.closed; // 'keep' or 'cancel'
An htmx page that loads the grid once
A page that uses htmx and also loads a view module, such as the calendar, kanban or Gantt chart, used to pay for the grid core twice. The htmx build carried its own copy, and the view module needed the core from the page. That is about 700 KB where about 52 KB would do.
modules/htmx.shared takes the core from the page instead. Load the core, then the shared build, and the page downloads the core once:
<script src="https://cdn.latticegrid.dev/lattice-grid@1.106.0/lattice-grid.min.js"></script>
<script src="https://cdn.latticegrid.dev/lattice-grid@1.106.0/modules/htmx.shared.min.js"></script>
The self-contained modules/htmx is still the right choice for a page that loads only the grid. The htmx pages show it working with server-rendered tables.
Upgrading from 1.105
There is nothing to change. Clustering, drawers and dialogs are new surface and opt in by use. To use the shared htmx build, load modules/htmx.shared.min.js after the core instead of modules/htmx.
The changelog has the full list, and the grid engine page covers the core that all three build on. Try the segments above on your own numbers.