Lattice Grid Buy a licence

demo D233

What makes this segment different

Filter to a segment and rank every column by how far it has moved from the whole

grid.statistics.subsetVsPopulation()

Building…
Loading a live grid…

The configuration

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

<div id="grid" style="height: 520px"></div>
<pre id="out" style="margin-top: 12px"></pre>

<script type="module">
  import { createGrid } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.25.0/lattice-grid.esm.min.js';

  const grid = createGrid(document.getElementById('grid'), {
    rowKey: 'id',
    columnDefaults: { filter: true },
    toolPanel: { side: 'left', panels: ['filters', 'columns'], exportName: 'accounts' },
    columns: [
      { field: 'account', title: 'Account', layout: { pin: 'start', width: 150 } },
      { field: 'region', title: 'Region', filter: { type: 'set' }, layout: { width: 110 } },
      { field: 'plan', title: 'Plan', filter: { type: 'set' }, layout: { width: 130 } },
      { field: 'mrr', title: 'MRR', type: 'number', format: { style: 'currency', currency: 'USD', decimals: 0 }, total: 'sum', layout: { width: 130 } },
      { field: 'seats', title: 'Seats', type: 'number', total: 'sum', layout: { width: 100 } },
      { field: 'nps', title: 'NPS', type: 'number', total: 'avg', layout: { width: 90 } },
      { field: 'churnRisk', title: 'Churn risk', type: 'number', format: { style: 'percent', decimals: 0 }, total: 'avg', layout: { width: 120 } },
    ],
    // Land filtered to one segment, so the ranking has something to say at once.
    state: { filters: { col: 'plan', op: 'eq', value: 'Enterprise' } },
    rows,  // e.g. [{ id: 'A-0001', account: 'Account 1', region: 'EU', plan: 'Enterprise', mrr: 5200, seats: 120, nps: 40, churnRisk: 0.2 }, …]
  });

  // subsetVsPopulation ranks every column by how far the filtered segment has
  // moved from the whole book, on one bounded 0 to 1 scale and by effect size
  // rather than a p-value, so the order holds as the segment grows or shrinks.
  // Recompute it whenever the filters change.
  const out = document.getElementById('out');
  const report = () => {
    out.textContent = JSON.stringify(grid.statistics.subsetVsPopulation(), null, 2);
  };
  grid.on('filter:changed', report);
  report();
</script>

Finding out what actually makes a segment different

Filtering to a segment is easy; saying what makes that segment different from everyone else usually means exporting to a spreadsheet and eyeballing averages column by column. grid.statistics.subsetVsPopulation() does that comparison for you, over every column at once, the moment a filter narrows the grid. It reads the filtered rows as the subset and the full dataset as the population, scores every column on how far the subset has moved, and ranks them so the column that actually explains the segment is first rather than buried between eleven others. A numeric column and a categorical one are scored on the same bounded scale, so “MRR is up” and “region is now entirely EU” can be ranked against each other honestly instead of comparing a currency figure to a percentage by eye. The ranking is by effect size, not a significance test: filter to a single large account and the ranking still reflects how different that account is, not how many rows are behind the answer, and doubling the size of a segment does not reshuffle which column explains it. A reliable: false flag on a result says plainly when a segment is too small to stand behind, rather than reporting a confident-looking number regardless of sample size.

How do I find out what distinguishes a filtered segment from the rest of my data?

Call grid.statistics.subsetVsPopulation() after applying a filter. It returns a ranked array, one entry per column, ordered by how far that column’s filtered values have moved from the whole dataset, plus subsetN and populationN so you can see how much data the answer stands on. Numeric columns are scored with a standardised mean difference (Glass’s delta); categorical columns are scored by how much their value mix has shifted. Both land on the same 0-to-1 distance, so the ranking holds across column types.

Why rank by effect size instead of statistical significance?

A p-value shrinks as a sample grows even when nothing about the underlying difference has changed, so the same real-world gap looks “more significant” in a bigger segment and can reorder a ranking for no reason connected to the data. Effect size does not move when the sample is scaled up: the same shift on ten rows or ten thousand reports the same magnitude. subsetVsPopulation reports no p-value at all, by design, and instead names a reliable: false result when a segment is too thin to trust, which is the honest version of the same concern.