Lattice Grid Buy a licence

demo D230

An SPC study: control, range, capability in React

A drifting process with limits fixed on the first thirty readings, so the drift breaks a rule rather than being absorbed

chart type: control · movingRange · capability

This grid runs an SPC study, control, moving range and capability, with limits fixed on the first thirty readings so a later drift breaks a rule rather than being absorbed. It shows a process going out of control being caught, not smoothed over.

Building…
Loading a live grid…

This is the React version. The grid mounts through the createLatticeGrid adapter, which takes its configuration as ordinary props and hands back the live grid through a ref. The grid below is the same one every other tab runs.

The configuration

<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.107.0/lattice-grid.min.css">

<div id="app"></div>

<script type="module">
  import React from 'https://esm.sh/react@18';
  import { createRoot } from 'https://esm.sh/react-dom@18/client';
  import { createGrid, createStat } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/lattice-grid.esm.min.js';
  import { createLatticeReact } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/modules/react.esm.min.js';
  import { createChart } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/modules/charts.esm.min.js';

  const { LatticeGrid, LatticeChart } = createLatticeReact({ React, createGrid, createChart });

  const columns = [
    { field: 'n', title: '#', type: 'number', layout: { width: 80 } },
    // The spec declares the tolerance; capability and the control limits read it.
    { field: 'bore', title: 'Bore', type: 'millimetres', spec: { lower: 9.95, upper: 10.05, target: 10 } },
  ];

  const rows = [/* one process over time, drifting up after the thirtieth reading */];

  function App() {
    const [grid, setGrid] = React.useState(null);
    const tilesRef = React.useRef(null);

    // Three figures read from the live grid: Cpk against the tolerance, the
    // mean bore, and the count. createStat has no v2 component to wrap it
    // with, so it stays imperative, same as every other stat tile in this
    // sweep. baseline fixes the control limits on the first thirty readings,
    // so the later drift breaks a rule.
    React.useEffect(() => {
      if (!grid || !tilesRef.current) return undefined;
      const stats = [
        createStat({ grid, container: tilesRef.current.querySelector('#cpk'), title: 'Cpk',
          value: (g) => g.statistics.capability('bore', { rules: 'nelson', baseline: 30 })?.cpk,
          goodWhen: 'up', baseline: 1.33, decimals: 2, footer: '1.33 is the usual floor' }),
        createStat({ grid, container: tilesRef.current.querySelector('#mean'), title: 'Mean bore', of: 'bore', fn: 'avg' }),
        createStat({ grid, container: tilesRef.current.querySelector('#count'), title: 'Readings', fn: 'count', footer: 'the first 30 set the limits' }),
      ];
      return () => { for (const s of stats) s.destroy(); };
    }, [grid]);

    return (
      <>
        <div ref={tilesRef} style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '12px' }}>
          <div id="cpk" />
          <div id="mean" />
          <div id="count" />
        </div>
        {/* Control, moving range and capability, all from the one declared tolerance. */}
        {grid && <LatticeChart grid={grid} type="control" y="bore" baseline={30} rules="nelson" title="Control chart, limits fixed on the first 30 readings" style={{ height: '220px', marginTop: '14px' }} />}
        {grid && (
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px', marginTop: '14px' }}>
            <LatticeChart grid={grid} type="movingRange" y="bore" title="Moving range" style={{ height: '200px' }} />
            <LatticeChart grid={grid} type="capability" y="bore" title="Capability against the tolerance" style={{ height: '200px' }} />
          </div>
        )}
        <LatticeGrid
          rowKey="id"
          toolPanel={{ side: 'left', panels: ['columns', 'statistics'] }}
          columns={columns}
          rows={rows}
          onGridReady={setGrid}
          style={{ height: '320px', marginTop: '14px' }}
        />
      </>
    );
  }

  createRoot(document.getElementById('app')).render(<App />);
</script>