Source
94 chart lines · 1 file · 2.7 kBBenchmark harness excluded · shared/mount.ts
1983 ASA automobile data406 records · CSV · 17.4 kB
@charts-poc/demo-data/carsSelection: Complete published snapshot
- name
- string
- economy (mpg)
- number | null
- cylinders
- number
- displacement (cc)
- number
- power (hp)
- number | null
- weight (lb)
- number
- 0-60 mph (s)
- number
- year
- number
1983 ASA Data Exposition@observablehq/sample-datasets@1.0.1 · revision 732c0148de74 · cars.csv · ISC distribution; upstream source credited · SHA-256 eaad8395d37ePinned snapshot
cases/31-linear-regression/tanstack.ts94 lines · entry
cases/31-linear-regression/tanstack.ts
import { cars } from '@charts-poc/demo-data/cars'
import { defineChart, dot, lineY } from '@tanstack/charts'
import { extent, mean } from 'd3-array'
import { scaleLinear } from 'd3-scale'
import { tanstackMount } from '../../shared/mount'
import type { CarsRow } from '@charts-poc/demo-data/cars'
import type { ConformanceInput } from '../../types'
interface RegressionPoint {
id: string
'power (hp)': number
'economy (mpg)': number
}
type CompleteCar = CarsRow & {
'power (hp)': number
'economy (mpg)': number
}
const completeCars = cars.filter(
(row): row is CompleteCar =>
row['power (hp)'] !== null && row['economy (mpg)'] !== null,
)
const definition = (input: ConformanceInput) => {
const rows = completeCars.slice(input.revision * 8, input.revision * 8 + 320)
const meanX = mean(rows, (row) => row['power (hp)']) ?? 0
const meanY = mean(rows, (row) => row['economy (mpg)']) ?? 0
let covariance = 0
let variance = 0
for (const row of rows) {
covariance += (row['power (hp)'] - meanX) * (row['economy (mpg)'] - meanY)
variance += (row['power (hp)'] - meanX) ** 2
}
const slope = variance === 0 ? 0 : covariance / variance
const intercept = meanY - slope * meanX
const [minimumPower = 0, maximumPower = 0] = extent(
rows,
(row) => row['power (hp)'],
)
const trend: readonly RegressionPoint[] = [
{
id: 'start',
'power (hp)': minimumPower,
'economy (mpg)': intercept + slope * minimumPower,
},
{
id: 'end',
'power (hp)': maximumPower,
'economy (mpg)': intercept + slope * maximumPower,
},
]
return defineChart({
marks: [
dot(rows, {
x: 'power (hp)',
y: 'economy (mpg)',
fill: '#93c5fd',
stroke: '#2563eb',
r: 3,
}),
lineY(trend, {
x: 'power (hp)',
y: 'economy (mpg)',
stroke: '#dc2626',
strokeWidth: 2,
}),
],
x: { scale: scaleLinear, grid: true, axis: { label: 'Power (hp)' } },
y: {
scale: scaleLinear,
grid: true,
axis: { label: 'Fuel economy (mpg)' },
},
})
}
export const mount = tanstackMount(
definition,
'Scatterplot with linear regression',
{
format: ({ datum }) =>
'name' in datum
? `${datum.name} · ${datum['power (hp)'].toLocaleString(
'en-US',
)} hp · ${datum['economy (mpg)'].toLocaleString('en-US')} mpg`
: `Regression · ${datum['power (hp)'].toLocaleString(
'en-US',
)} hp · predicted ${datum['economy (mpg)'].toLocaleString('en-US', {
maximumFractionDigits: 1,
})} mpg`,
},
)