Open data, followed all the way down to one person inside it.
Every piece here starts with a public dataset and ends with a story. The numbers can be checked: any figure set in mono opens its own evidence in a column to the right, so you never have to leave the sentence you are reading to find out whether it is true.
open to work
02pieces
02public datasets
271occupations
4,810teenagers
work
files
build.py — 02-screen-time
The interactive parts of piece 02 are shaped by the same rule as everything else here: the web layer computes nothing. This is the loop that precomputes every position both sliders can take.
# the grid: every headline this dataset can honestly produce
cells = []
for k in THRESHOLDS:
heavy = [r for r in rows if r["screen_time_index"] >= k]
light = [r for r in rows if r["screen_time_index"] < k]
row = []
for cut in CUTOFFS:
ph = sum(1 for r in heavy if r["bdi_total"] >= cut) / len(heavy)
pl = sum(1 for r in light if r["bdi_total"] >= cut) / len(light)
row.append({
"rr": round(ph / pl, 3) if pl > 0 else None,
"ph": round(100 * ph, 2),
"pl": round(100 * pl, 2),
"nh_flagged": sum(1 for r in heavy if r["bdi_total"] >= cut),
"nl_flagged": sum(1 for r in light if r["bdi_total"] >= cut),
})
cells.append({"threshold": k, "n_heavy": len(heavy),
"n_light": len(light), "row": row})
analysis/pipelines/02_screen_time/build.py
5 thresholds × 26 cutoffs = 130 cells, each carrying its ratio, both percentages, and both flagged counts. stdlib Python, with no dependency besides kagglehub.