Source
75 chart lines · 2 files · 2.2 kBBenchmark harness excluded · shared/mount.ts
Likert survey responses500 records · CSV · 8.2 kB
@charts-poc/demo-data/surveySelection: Complete published snapshot
- Question
- string
- ID
- number
- Response
- string
Eitan Leesobservablehq/plot@356f579b1d94 · revision 356f579b1d94 · test/data/survey.csv · Observable Plot repository MIT; upstream source credited · SHA-256 de6879d71248Pinned snapshot
cases/78-gauge/tanstack.ts45 lines · entry
cases/78-gauge/tanstack.ts
import { survey } from '@charts-poc/demo-data/survey'
import { defineChart } from '@tanstack/charts'
import { polar, radialArc } from '@tanstack/charts/polar'
import { pie } from 'd3-shape'
import { agreementPercent, gaugeSegments } from './transform'
import { tanstackMount } from '../../shared/mount'
import type { GaugeDatum } from './transform'
import type { ConformanceInput } from '../../types'
const startAngle = (-Math.PI * 3) / 4
const endAngle = (Math.PI * 3) / 4
const pieLayout = pie<GaugeDatum>()
.sort(null)
.value(({ value }) => value)
.startAngle(startAngle)
.endAngle(endAngle)
const ids: readonly GaugeDatum['id'][] = ['value', 'remainder']
const colors = ['#ef4444', '#e2e8f0']
const definition = (input: ConformanceInput) => {
const question = `Q${(input.revision % 2) + 1}`
const arcs = pieLayout([...gaugeSegments(agreementPercent(survey, question))])
return defineChart({
marks: [
polar({
inset: 0,
radiusRatio: 0.8,
marks: [
radialArc(arcs, {
startAngle: 'startAngle',
endAngle: 'endAngle',
padAngle: 'padAngle',
innerRadius: ({ radius }: { radius: number }) => radius * 0.72,
color: ({ data }) => data.id,
}),
],
}),
],
color: { domain: ids, range: colors },
margin: 0,
})
}
export const mount = tanstackMount(definition, 'Survey agreement share gauge')cases/78-gauge/transform.ts30 lines · support
cases/78-gauge/transform.ts
export interface GaugeDatum {
id: 'value' | 'remainder'
label: string
value: number
}
export function gaugeSegments(value: number): readonly GaugeDatum[] {
return [
{ id: 'value', label: 'Agree', value },
{
id: 'remainder',
label: 'Other responses',
value: 100 - value,
},
]
}
export function agreementPercent(
rows: readonly SurveyRow[],
question: string,
): number {
const responses = rows.filter((row) => row.Question === question)
const agreements = responses.filter(
(row) => row.Response === 'Agree' || row.Response === 'Strongly Agree',
)
return responses.length === 0
? 0
: Math.round((agreements.length / responses.length) * 100)
}
import type { SurveyRow } from '@charts-poc/demo-data/survey'