Lattice Grid Buy a licence

demo D244

Regression diagnostics in React

A fitted line with its confidence band, residual and QQ charts read straight from the fit shadow columns, and the coefficients in a panel that refits as you filter

grid.statistics.regressionModel · regressionPlots

This grid fits a regression over the filtered rows and shows the fitted line with its confidence band, plus residual and Q-Q charts read from the fit, with the coefficients in a panel that refits as you filter. It treats a regression as finished only once the residuals have been looked at.

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.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.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 } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/lattice-grid.esm.min.js';
  import { createLatticeReact } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/react.esm.min.js';
  import { createChart, regressionPlots } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/charts.esm.min.js';

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

  const model = { predictors: ['x'], response: 'y' };

  const columns = [
    { field: 'x', title: 'x', type: 'number', format: { decimals: 2 }, filter: { type: 'number' } },
    { field: 'y', title: 'y', type: 'number', format: { decimals: 2 }, filter: { type: 'number' } },
    // The fit lives in the data as shadow columns, so each diagnostic is a
    // plain chart over ordinary cells that refits as the grid is filtered.
    { id: 'yhat', title: 'Fitted', type: 'number', format: { decimals: 2 }, shadow: { kind: 'fitPredicted', model } },
    { id: 'resid', title: 'Residual', type: 'number', format: { decimals: 2 }, shadow: { kind: 'fitResidual', model } },
    { id: 'sresid', title: 'Std residual', type: 'number', format: { decimals: 2 }, shadow: { kind: 'fitStdResidual', model } },
    { id: 'lev', title: 'Leverage', type: 'number', format: { decimals: 3 }, shadow: { kind: 'fitLeverage', model } },
    { id: 'cook', title: "Cook's D", type: 'number', format: { decimals: 3 }, shadow: { kind: 'fitCooksD', model } },
  ];

  const rows = [/* one point a row: x, y */];

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

    const onGridReady = (g) => {
      setGrid(g);
      // regressionPlots turns the fit into ready chart specs over those shadow
      // columns: the fit with its confidence band, residuals against fitted,
      // and a normal QQ of the residuals.
      const { plots } = regressionPlots(g, {
        spec: model, fitted: 'yhat', residual: 'resid', stdResidual: 'sresid', leverage: 'lev', cooksD: 'cook',
      });
      setFitSpec(plots.fit.spec);
    };

    return (
      <>
        {grid && fitSpec && (
          <LatticeChart grid={grid} {...fitSpec} title="Fit with 95% confidence band" style={{ height: '240px' }} />
        )}
        <LatticeGrid
          rowKey="id"
          toolPanel={{ side: 'left', panels: ['columns', { name: 'regression', props: { predictors: ['x'], response: 'y' } }], openPanel: 'regression' }}
          columns={columns}
          rows={rows}
          onGridReady={onGridReady}
          style={{ height: '360px', marginTop: '14px' }}
        />
      </>
    );
  }

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

Fitting a line and reading its residuals

A regression is not finished when it has coefficients; it is finished when the residuals have been looked at. Lattice Grid fits the model over the filtered rows and reports the coefficient table, R squared and the collinearity flag in a panel beside the grid. Filter the grid and the model refits over what is left, so the numbers always describe the data you are actually looking at. This gives an analyst working in a JavaScript data grid the diagnostics they would otherwise leave for a separate notebook, in the same place as the data.

The fitted model also lives in the data as shadow columns: the fitted value, the residual, the standardised residual, the leverage and Cook’s distance. They are ordinary numeric cells that sort, filter, group and export like any other, and they read the fit by row key. That turns each diagnostic picture into a plain chart over columns: the fit with its confidence band, the residuals against the fitted value, and a normal QQ plot of the residuals. Two high-leverage points in the sample keep leverage and Cook’s distance meaningful rather than flat.

How do you check a regression fit in a data grid?

Read the coefficient table, R squared and the collinearity flag from the regression panel, which recomputes over the filtered rows. Add the fit as shadow columns to bring the fitted value, residual, standardised residual, leverage and Cook’s distance into the data itself, then chart the fit with its confidence band, the residuals against the fitted value, and a QQ plot of the residuals to see where the model holds and where it does not.