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

'subset-vs-population': () => {
  const rand = seeded(20261001);
  const REGIONS = ['EU', 'US', 'APAC'];
  const PLANS = ['Starter', 'Growth', 'Enterprise'];
  const rows = Array.from({ length: 600 }, (unused, i) => {
    const plan = i % 12 === 0 ? 'Enterprise' : PLANS[Math.floor(rand() * 2)];
    const enterprise = plan === 'Enterprise';
    const region = enterprise
      ? (rand() < 0.7 ? 'EU' : REGIONS[Math.floor(rand() * 3)])
      : REGIONS[Math.floor(rand() * 3)];
    const mrr = Math.round((enterprise ? 4200 + rand() * 3800 : 90 + rand() * 900) * 100) / 100;
    const seats = enterprise ? 40 + Math.floor(rand() * 260) : 1 + Math.floor(rand() * 18);
    const nps = Math.max(-100, Math.min(100, Math.round((enterprise ? 25 : 15) + (rand() - 0.5) * 90)));
    const churnRisk = Math.round(rand() * 100) / 100;
    return {
      id: `A-${String(i + 1).padStart(4, '0')}`,
      account: `Account ${i + 1}`,
      region,
      plan,
      mrr,
      seats,
      nps,
      churnRisk,
    };
  });
  return {
    rows,
    config: {
      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 } },
      ],
      state: { filters: { col: 'plan', op: 'eq', value: 'Enterprise' } },
    },
    onGrid: (grid) => {
      const shell = grid.element?.closest('.demo-shell') ?? grid.element?.parentElement;
      const panel = document.createElement('div');
      panel.style.cssText = 'margin-top:14px;border:1px solid var(--rule);border-radius:11px;padding:14px 16px;background:var(--paper)';
      shell?.append(panel);
      const titleOf = (colId: string) => {
        const col = grid.columns.all().find((c: any) => c.id === colId);
        return col?.title ?? col?.name ?? colId;
      };
      const bar = (frac: number, positive: boolean) =>
        `<div style="flex:1;height:8px;border-radius:4px;background:var(--rule);overflow:hidden">` +
        `<div style="height:100%;width:${Math.round(Math.max(0, Math.min(1, frac)) * 100)}%;` +
        `background:${positive ? '#2f9e44' : '#e8590c'}"></div></div>`;
      const render = () => {
        const r = grid.statistics?.subsetVsPopulation?.();
        if (!r) { panel.textContent = 'subsetVsPopulation unavailable'; return; }
        if (!r.filtered) {
          panel.innerHTML = '<p style="margin:0;font:13px system-ui;color:var(--ink-2)">Filter the grid to a segment — with no filter the subset is the whole population, and nothing differs.</p>';
          return;
        }
        const rows2 = r.ranked.map((c: any) => {
          const label = titleOf(c.column);
          const pct = (c.distance * 100).toFixed(0);
          const dirWord = c.measure === 'categoricalTotalVariation'
            ? 'mix differs'
            : c.direction > 0 ? 'higher' : c.direction < 0 ? 'lower' : 'unchanged';
          const measureName = c.measure === 'categoricalTotalVariation' ? 'category mix' : "Glass's delta";
          const flag = c.reliable === false ? ' <span style="color:#e8590c">· thin sample</span>' : '';
          return `<div style="display:flex;align-items:center;gap:10px;padding:6px 0;border-top:1px solid var(--rule)">` +
            `<div style="width:120px;font:600 13px system-ui">${label}</div>` +
            bar(c.distance, c.direction >= 0) +
            `<div style="width:230px;font:12px system-ui;color:var(--ink-2);text-align:right">${pct}% of scale · ${dirWord} · ${measureName}${flag}</div>` +
            `</div>`;
        }).join('');
        panel.innerHTML =
          `<p style="margin:0 0 4px;font:13px system-ui"><strong>${count(r.subsetN)}</strong> of <strong>${count(r.populationN)}</strong> accounts in this segment</p>` +
          `<p style="margin:0 0 8px;font:12px system-ui;color:var(--ink-3)">ranked by effect size (a bounded 0–1 distance), not a p-value — the order does not reshuffle as the sample grows</p>` +
          rows2;
      };
      const off = grid.on?.('filter:changed', render);
      render();
      return () => { off?.(); panel.remove(); };
    },
    foot: ['lands filtered to Enterprise: the ranked list is the demonstration', 'grid.statistics.subsetVsPopulation() ranks every column by effect size', 'no p-value crosses the boundary, on purpose: doubling the segment would not reorder it'],
  };
},

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.