Source

92 chart lines · 2 files · 2.2 kBBenchmark harness excluded · shared/mount.ts

U.S. driving and gasoline prices55 records · CSV · 1.5 kB
@charts-poc/demo-data/driving

Selection: Complete published snapshot

side
string
year
number
miles
number
gas
number

The New York Timesobservablehq/plot@356f579b1d94 · revision 356f579b1d94 · test/data/driving.csv · Observable Plot repository MIT; upstream source credited · SHA-256 3aced2fa41f2Pinned snapshot

cases/56-connected-scatter/tanstack.ts59 lines · entry
cases/56-connected-scatter/tanstack.ts
import { arrow, d3Curve, defineChart, dot, lineY, text } from '@tanstack/charts'
import { scaleLinear } from 'd3-scale'
import { curveCatmullRom } from 'd3-shape'
import { driving } from '@charts-poc/demo-data/driving'
import { directionSegments } from './transform'
import { tanstackMount } from '../../shared/mount'

const arrows = directionSegments(driving)
const labels = driving.filter((row) => row.year % 5 === 0)

const definition = () =>
  defineChart({
    marks: [
      lineY(driving, {
        x: 'miles',
        y: 'gas',
        stroke: '#64748b',
        strokeWidth: 2.25,
        curve: d3Curve(curveCatmullRom.alpha(0.5)),
      }),
      dot(driving, {
        x: 'miles',
        y: 'gas',
        fill: '#0f766e',
        r: 3.25,
      }),
      arrow(arrows, {
        x1: 'miles1',
        y1: 'gas1',
        x2: 'miles2',
        y2: 'gas2',
        stroke: '#0f766e',
        strokeWidth: 1.5,
        headLength: 7,
      }),
      text(labels, {
        x: 'miles',
        y: 'gas',
        text: (row) => `${row.year}`,
        fill: '#0f172a',
        dy: -9,
      }),
    ],
    x: {
      scale: scaleLinear,
      grid: true,
      axis: { label: 'Miles driven per person' },
    },
    y: {
      scale: scaleLinear,
      grid: true,
      axis: { label: 'Cost of gasoline ($ per gallon)' },
    },
  })

export const mount = tanstackMount(
  definition,
  'Directed connected scatterplot over time',
)
cases/56-connected-scatter/transform.ts33 lines · support
cases/56-connected-scatter/transform.ts
import type { DrivingRow } from '@charts-poc/demo-data/driving'

export interface DirectionSegment {
  fromYear: number
  toYear: number
  miles1: number
  gas1: number
  miles2: number
  gas2: number
}

export function directionSegments(
  rows: readonly DrivingRow[],
): readonly DirectionSegment[] {
  const targetIndexes = [14, 28, 42]
  const segments: DirectionSegment[] = []

  for (const targetIndex of targetIndexes) {
    const source = rows[targetIndex - 1]
    const target = rows[targetIndex]
    if (source === undefined || target === undefined) continue
    segments.push({
      fromYear: source.year,
      toYear: target.year,
      miles1: source.miles,
      gas1: source.gas,
      miles2: target.miles,
      gas2: target.gas,
    })
  }

  return segments
}