diff --git a/src/charts/RateDensityRidgeline.jsx b/src/charts/RateDensityRidgeline.jsx index 54325d3..a6abe7b 100644 --- a/src/charts/RateDensityRidgeline.jsx +++ b/src/charts/RateDensityRidgeline.jsx @@ -2,23 +2,25 @@ import { useState } from 'react' import { MODEL_QUADRANTS } from '../hooks/useApi.js' import { raceColor, OBSERVED_MARK_COLOR, RACE_LABELS, SHORT_RACE_LABEL } from '../utils/colors.js' import { fitSkewedInterval, densityCurve } from '../utils/distributionApprox.js' +import { kdeCurve } from '../utils/kde.js' import { niceTicks } from '../utils/niceTicks.js' +import { useDrawDistribution } from '../hooks/useDrawDistribution.js' import ChartLegend from '../components/ChartLegend.jsx' import ApproxNote from '../components/ApproxNote.jsx' /** * Modeled posterior density per race×sex group, for one selected model * (dropdown, default three-year + referral rate), split into Female/Male - * columns — matches whitepaper-fig-clark-density-1.png's ridge style. Plain - * SVG — each ridge is 60 analytic points from fitSkewedInterval/densityCurve, - * already smooth without a binning/curveBasis smoothing pass. + * columns. Each ridge is drawn from that group's 500 real posterior draws + * (Gaussian KDE) when available, falling back per-group to the analytic + * fitSkewedInterval/densityCurve approximation otherwise. */ const RACE_ORDER = ['WH', 'BL', 'HI', 'AM'] const SEX_COLUMNS = [{ sex: 'F', label: 'Female' }, { sex: 'M', label: 'Male' }] const DEFAULT_MODEL = 'unified_m4_mod' // Three-year + referral rate -function buildGroupRow(row) { +function buildGroupRow(row, draws) { const enroll = row.stu_enroll || 0 const observedRate = enroll > 0 ? ((row.observed_arrests || 0) / enroll) * 1000 : 0 const rateMedian = (row.rate_median || 0) * 1000 @@ -28,13 +30,16 @@ function buildGroupRow(row) { race: row.race, sex: row.sex, observedRate, + draws, fit: fitSkewedInterval({ median: rateMedian, lower: rateLower, upper: rateUpper }), } } -export default function RateDensityRidgeline({ quadData }) { +export default function RateDensityRidgeline({ quadData, leaid, state }) { const [selectedModel, setSelectedModel] = useState(DEFAULT_MODEL) const rows = (quadData && quadData[selectedModel]) || [] + const groups = rows.map((r) => ({ race: r.race, sex: r.sex, stuEnroll: r.stu_enroll || 0 })) + const { status, drawsByGroup } = useDrawDistribution({ leaid, state, model: selectedModel, year: '21-22', groups }) const modelSelect = (