Lattice Grid Buy a licence

demo D222

Chaining, three levels deep

sales → revenue per rep → top three and a profile, with tiles reading the middle level; one filter moves all of it

source: { mode: 'derived', from, groupBy, profile } · createStat

Building…
Loading a live grid…

The configuration

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

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

<div id="tiles" style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin-bottom: 16px"></div>
<lattice-grid id="book" row-key="id" style="display: block; height: 320px"></lattice-grid>
<div style="display: flex; gap: 16px; margin-top: 16px">
  <lattice-grid id="byRep" style="flex: 1"></lattice-grid>
  <lattice-grid id="top3" style="flex: 1"></lattice-grid>
  <lattice-grid id="profile" style="flex: 1"></lattice-grid>
</div>

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

  const USD = { style: 'currency', currency: 'USD', maximumFractionDigits: 0 };

  // Level 0, the book: a plain grid, filterable, over the sales rows.
  const bookEl = document.getElementById('book');
  bookEl.config = {
    toolPanel: { side: 'left', panels: ['filters', 'columns'] },
    columns: [
      { field: 'rep', title: 'Rep' },
      { field: 'region', title: 'Region', filter: { type: 'set' } },
      { field: 'amount', title: 'Deal', type: 'number', format: USD, total: 'sum' },
    ],
  };
  bookEl.rows = rows;  // e.g. [{ id: 'S0', rep: 'Ana Bright', region: 'EMEA', amount: 2140 }, ...]

  // Level 1, revenue per rep, derived from the book and following its filter.
  // No rows: the group value is the identity. refresh: 'live' re-derives on the
  // next frame when the book is filtered. bookEl.grid is the live grid inside it.
  const byRepEl = document.getElementById('byRep');
  byRepEl.config = {
    autoHeight: true,
    source: { mode: 'derived', from: bookEl.grid, follow: 'filtered', refresh: 'live', groupBy: 'rep',
      select: { revenue: { of: 'amount', fn: 'sum' }, deals: { fn: 'count' } },
      sort: [{ col: 'revenue', dir: 'desc' }] },
    columns: [
      { field: 'rep', title: 'Rep' },
      { field: 'revenue', title: 'Revenue', type: 'number', format: USD },
      { field: 'deals', title: 'Deals', type: 'number' },
    ],
  };

  // Level 2, derived from byRep, not from the book: the chain composes.
  document.getElementById('top3').config = {
    autoHeight: true,
    source: { mode: 'derived', from: byRepEl.grid, refresh: 'live', sort: [{ col: 'revenue', dir: 'desc' }], limit: 3 },
    columns: [
      { field: 'rep', title: 'Rep' },
      { field: 'revenue', title: 'Revenue', type: 'number', format: USD },
    ],
  };

  // Level 2, the profile transpose: one row of stats over byRep's revenues.
  document.getElementById('profile').config = {
    autoHeight: true,
    source: { mode: 'derived', from: byRepEl.grid, profile: ['revenue'], refresh: 'live' },
    columns: [
      { field: 'column', title: 'Measure' },
      { field: 'mean', title: 'Mean', type: 'number', format: { maximumFractionDigits: 0 } },
      { field: 'stddev', title: 'σ', type: 'number', format: { maximumFractionDigits: 0 } },
      { field: 'min', title: 'Weakest', type: 'number', format: { maximumFractionDigits: 0 } },
      { field: 'max', title: 'Strongest', type: 'number', format: { maximumFractionDigits: 0 } },
    ],
  };

  // A tile is one reduced figure over a grid. These read byRep. createStat comes
  // from the element's own module, so it shares one engine with byRepEl.grid.
  // The concentration is a Gini ratio; show: 'rep' turns max into an argmax.
  const tile = () => document.getElementById('tiles').appendChild(document.createElement('div'));
  createStat({ grid: byRepEl.grid, container: tile(), title: 'Revenue concentration', of: 'revenue', fn: 'gini', goodWhen: 'down', footer: '0 = even, 1 = one rep has it all' });
  createStat({ grid: byRepEl.grid, container: tile(), title: 'Best rep', of: 'revenue', fn: 'max', show: 'rep' });
  createStat({ grid: byRepEl.grid, container: tile(), title: 'Weakest rep', of: 'revenue', fn: 'min', show: 'rep' });
  createStat({ grid: byRepEl.grid, container: tile(), title: 'Spread across reps', of: 'revenue', fn: 'stddev' });
  createStat({ grid: byRepEl.grid, container: tile(), title: 'Reps selling', fn: 'count' });
</script>