@tanstack/charts
Version:
A chart grammar for TypeScript and JavaScript. Marks consume your data directly, channels describe visual encodings, and the engine compiles them into a renderer-neutral keyed scene. TanStack's compact scales cover common numeric and categorical mappings.
137 lines (107 loc) • 5.51 kB
Markdown
title: Scatterplots and Relationships
description: Choose scatterplot, regression, connected-path, lag, and nearest-point patterns for quantitative relationships.
Scatterplots answer how two quantitative measures vary together. Position
carries the primary evidence. Color, radius, a fitted line, or chronological
connections should add one clearly stated dimension rather than compete with
that relationship.
## Choose the comparison
| Reader question | Start with |
| --------------------------------------------------------------- | ------------------------------------------- |
| Do two quantitative measures move together? | A scatterplot |
| What linear tendency summarizes that relationship? | Scatterplot plus `linearRegressionY` |
| How does the relationship evolve in a known order? | A connected scatterplot |
| Does a series depend on its previous observation? | A lag plot |
| Which dense point is closest to the pointer or keyboard cursor? | A scatterplot with a spatial focus strategy |
Do not infer causation from proximity or a fitted trend. Show the model and
preparation only when they answer the stated question.
## Start with two quantitative measures
A plain scatterplot should establish the relationship before adding a fitted
model, chronology, or spatial partition.
```ts group=basic-scatter env=charts file=/src/chart.ts entry
import { defineChart, dot } from '@tanstack/charts'
import { scaleLinear } from '@tanstack/charts/scales/linear'
const rows = [
{ temperature: 12, sales: 18 },
{ temperature: 16, sales: 25 },
{ temperature: 20, sales: 31 },
{ temperature: 24, sales: 46 },
{ temperature: 29, sales: 52 },
{ temperature: 32, sales: 61 },
]
const chart = defineChart({
marks: [
dot(rows, {
x: 'temperature',
y: 'sales',
r: 5,
fill: '#2563eb',
}),
],
x: {
scale: scaleLinear,
grid: true,
axis: { label: 'Temperature (°C)' },
},
y: {
scale: scaleLinear,
grid: true,
axis: { label: 'Daily sales' },
},
})
export default chart
```
## Add a linear regression
Pass the observations directly to `linearRegressionY`. The mark owns the
least-squares fit, semantic-domain samples, optional confidence band, and
aggregate source lineage. Keep the dot layer separate so each observation
remains independently focusable.
<!-- ::chart-example id=31-linear-regression height=480 -->
Set `ci: 0` when only the fitted line is needed. The default `0.95` band uses a
Student-t interval for the fitted mean. See the
[linear regression mark](../reference/marks/regression.md) for grouping,
sampling, and degenerate-fit behavior.
The dot layer still preserves every observation while the regression mark owns
only its derived model geometry.
## Connect observations only when order matters
A connected scatterplot turns sequence into a path through two-dimensional
measure space. Chronological labels and direction arrows make that additional
ordering visible.
<!-- ::chart-example id=56-connected-scatter height=480 -->
Without an explicit order, connecting points invents a relationship. Keep the
path, arrow, selected labels, and points as separate layers so each can use the
same scales without sharing renderer-specific state.
## Compare each observation with its predecessor
A lag plot moves time out of the axis and into data preparation. Each point
pairs a current value with the previous value; an identity rule shows where
those values would be equal.
<!-- ::chart-example id=60-lag-autocorrelation height=480 -->
Make the lag length explicit and decide how the first observation is handled.
The chart should receive the resulting pairs rather than conceal the shift
inside a mark.
## Separate visible cells from nearest-point focus
Voronoi cells make each point's nearest region visible. The optional `voronoi`
mark paints those cells but deliberately adds no focus candidates. A layered
`dot` mark remains the semantic source for pointer focus, keyboard navigation,
and tooltips.
<!-- ::chart-example id=65-voronoi-nearest-tooltip height=480 -->
See the [`voronoi` mark](../reference/marks/voronoi.md) for final-screen cell
geometry and stable identity. [Tooltips and Focus](../guides/tooltips-and-focus.md)
defines the focus and formatting model. Use a `ChartSpatialIndexFactory` when
lookup performance matters but the cells should not be painted.
## Production checks
- Use quantitative scales with intentional domains on both axes. Use a
logarithmic scale only when multiplicative distance is the intended reading;
see [Scales](../concepts/scales-and-d3.md).
- Map magnitude through an area-preserving radial scale when point size carries
a third quantitative value.
- Control opacity or aggregate spatially before thousands of overlapping dots
obscure the distribution. See [Large Data](../guides/large-data.md).
- Keep lag pairs in data preparation. Keep lookup-only spatial indexes in
interaction capabilities; use `voronoi` only when cells are part of the
visible encoding.
- Provide keyboard-equivalent focus and a textual value path, as described in
[Accessibility](../guides/accessibility.md).
The channel and styling contracts for points are in
[Dot and Hexagon Marks](../reference/marks/dot-and-hexagon.md).