Data Point Dropper

A 2D scatter where every sample is a focusable toggle. Click (or focus + Enter / Space) any point to "drop" it from the regression; the solid accent line refits over the remaining points and a faint dashed reference keeps the original full-dataset fit visible for direct comparison. Used for leverage and influence analysis — drop a point near the cloud's centre of mass and the remaining line barely budges; drop a point at the cloud's x-extreme and the line rotates dramatically.

Data point dropper. 11 of 11 samples kept. Full fit y = 0.16 x + 0.11. Remaining fit y = 0.16 x + 0.11.
full y = 0.16 x + 0.11drop 0/11remaining y = 0.16 x + 0.11
Customize
Display

Installation

npx shadcn@latest add https://craftbits.dev/r/data-point-dropper.json

Usage

import { DataPointDropper } from "@craft-bits/core";
 
<DataPointDropper
  samples={[
    { id: "a", x: -2, y: -0.6 },
    { id: "b", x: -1, y: 0.1 },
    { id: "c", x: 0, y: 0.6 },
    { id: "d", x: 1, y: 1.0 },
    { id: "e", x: 2, y: 1.7 },
  ]}
/>

Drive the dropped-set from outside (controlled):

const [dropped, setDropped] = useState<readonly string[]>([]);
 
<DataPointDropper
  samples={cloud}
  droppedIds={dropped}
  onDroppedIdsChange={setDropped}
/>

Start with one point pre-dropped (uncontrolled):

<DataPointDropper
  samples={cloud}
  defaultDroppedIds={["leverage"]}
/>

Hide the full-dataset reference for a single-fit picker:

<DataPointDropper
  samples={cloud}
  showFullLine={false}
/>

Understanding the component

  1. Two analytic fits, side by side. Both the full-dataset and remaining-after-drop lines are closed-form least-squares solutions: the slope is the covariance of x and y divided by the variance of x; the intercept is mean(y) − slope · mean(x). No gradient descent, no iteration — one pass over the points yields each line. Degenerate clouds (variance of x near zero, or fewer than two points) return null and the line is hidden.
  2. Stable viewport. The math viewport is derived from the full sample cloud — not the remaining set — so dropping a high-leverage point doesn't pan the chart and the user can see the line snap relative to fixed axes. The viewport is then extended in y to keep both line endpoints inside the visible area.
  3. Leverage made visible. Drop a point near the cloud's centre of mass and the remaining line barely budges. Drop a point at the cloud's x-extreme — a high-leverage observation — and the remaining line rotates dramatically. That's the lesson the component teaches at a glance.
  4. Controlled + uncontrolled. Following Radix's value / defaultValue pattern, pass droppedIds + onDroppedIdsChange for controlled mode or just defaultDroppedIds to let the component manage its own state.
  5. Keyboard-first interaction. Every sample circle is role="checkbox" with tabIndex={0} and aria-checked. Tab between points, press Enter or Space to toggle — no mouse required. :focus-visible gets a stroke ring in the accent colour.
  6. Spring transitions. Line endpoints and per-point opacity follow with SPRINGS.smooth. prefers-reduced-motion: reduce collapses every spring to an instant swap.

Props

PropTypeDefaultDescription
samplesreadonly DataPointDropperSample[]requiredThe full set of samples available to fit. Each must have a stable id.
droppedIdsreadonly string[]Controlled set of dropped (excluded) sample IDs.
defaultDroppedIdsreadonly string[][]Uncontrolled initial set of dropped IDs.
onDroppedIdsChange(next: readonly string[]) => voidFires whenever the dropped-set changes (click toggle, kbd Enter/Space).
showFullLinebooleantrueRender the dashed regression line fit through the full dataset.
showRemainingLinebooleantrueRender the solid regression line fit through the remaining samples.
transitionTransitionSPRINGS.smoothSpring for line endpoint and point-fade transitions.
classNamestringMerged onto the root <div> via cn().

The DataPointDropperSample shape:

interface DataPointDropperSample {
  id: string;   // stable identifier — used for controlled droppedIds + React keys
  x: number;    // x coordinate in math space
  y: number;    // y coordinate in math space
}

Accessibility

  • The root <div> is role="figure" with a visually hidden aria-live="polite" summary of point count, drop count, and both fitted formulas — screen readers hear the new line whenever a point is dropped or restored.
  • Every sample point is a focusable role="checkbox" with aria-checked reflecting drop state and an aria-label reporting the sample's coordinates.
  • Keyboard control: Tab moves between points; Enter or Space toggles drop state.
  • :focus-visible stroke ring in text-cb-accent so keyboard users always see where they are.
  • Motion respects prefers-reduced-motion: reduce — every spring collapses to an instant swap.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/viz/DataPointDropper.tsx). The source paired a click-to-place scatter sandbox with a click-anywhere-on-the-plane add interaction and a single best-fit line. The library extract reframes that as a drop-an-existing-point primitive for leverage / influence analysis — a fixed cloud in, the dropped subset out, two regression lines (full + remaining) drawn on top.