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.
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>