StatLens

License: MIT Live

A free, browser-only statistics tool for the whole analysis loop — from raw data to a publication-quality figure.

Try it: ronnyallen.github.io/StatLens

StatLens runs a real Python scientific stack — NumPy, SciPy, statsmodels, pingouin, lifelines — inside your browser via Pyodide and WebAssembly. ~45 statistical tests, eight typed data table types, and 12 chart types with automatic significance brackets.

Nothing to install. No server. Your workbooks are saved to your own Google Drive.

Statistical correctness is the top priority; UX polish is second. 44 analyses are pinned to golden reference values from SciPy, statsmodels, pingouin, and R — and re-verified in CI on every push.


Table of contents


Why

Statistics software tends to be expensive, desktop-bound, or both. StatLens does the everyday work — put data in a typed table, run the right test, get a clean graph with significance brackets — in a browser tab, for free.


Features

An in-app About page carries the same guide, kept verified against the engine.


What goes in which table

The table type you pick determines which analyses are offered.

Table Use when Example Tests Post hoc
Column Comparing groups on one measurement Control / Drug A / Drug B tumour volumes One-sample t, Unpaired t (Student’s), Welch’s t, Paired t, Mann-Whitney, Wilcoxon, Sign test, Kolmogorov-Smirnov, One-way ANOVA, Welch’s ANOVA, Brown-Forsythe, Repeated-Measures ANOVA, Kruskal-Wallis, Friedman Tukey, Dunnett (vs control), Dunnett’s T3, Games-Howell, Dunn, Bonferroni, Šídák, Holm-Šídák
XY One variable measured against another Dose vs response; time vs signal Pearson, Spearman, Simple linear regression, Nonlinear curve fitting (exponential, Michaelis-Menten, 4PL, Gaussian, polynomial, Boltzmann), Deming regression, Simple logistic regression, Area under curve, LOWESS, Spline, Smooth, Integrate, Differentiate
Grouped Two factors at once Drug × Dose on blood pressure Two-way ANOVA (Type III), Repeated-Measures two-way, Mixed-effects, ART ANOVA (non-parametric) Tukey on marginal means
Contingency Counts in categories Exposed / Unexposed × Case / Control Chi-square (± Yates), Fisher’s exact, McNemar’s, Odds and risk ratios, Diagnostic (sensitivity / specificity)
Survival Time until an event Days to relapse by treatment arm Kaplan-Meier, Log-rank (Mantel-Cox), Gehan-Breslow-Wilcoxon, Hazard ratios, Cox regression Pairwise log-rank (Holm)
Parts of Whole One whole split into parts Cell counts per phenotype Fraction of total, Chi-square goodness of fit, Binomial test
Multiple Variables Many variables per subject Age, BMI, dose, response per patient Correlation matrix, Multiple linear regression, Multiple logistic regression, Poisson regression, PCA, Three-way ANOVA
Nested Subsamples within groups 3 wells per animal, 4 animals per group Nested t-test / nested one-way ANOVA Tukey

Analyses report effect sizes (Cohen’s d, eta², mean differences), confidence intervals, and degrees of freedom, alongside a Markdown results report.


Charts

Bar + error bars · Box & whisker · Violin · Raincloud · Scatter · Strip · Jitter · Beeswarm · Horizontal box · Range / dumbbell · CI forest · Kaplan-Meier step

All support significance brackets and asterisks, computed and laid out automatically. Error bars (SD / SEM / CI) and regression overlays with confidence bands. Light/dark theme, 15 bundled font families.

Export: 600-DPI PNG with correct DPI metadata and embedded fonts, or SVG.


Coming soon


How it works

StatLens is a 100% client-side single-page app. Nothing runs on a server.

┌──────────────────────── Browser tab ─────────────────────────┐
│                                                              │
│  React 19 + TypeScript (Vite 8)                              │
│    ├── ag-grid ............ spreadsheet data tables          │
│    ├── visx / d3 .......... chart rendering (SVG)            │
│    └── Radix + Tailwind ... UI (shadcn/ui)                   │
│                    │                                          │
│                    │  postMessage                             │
│                    ▼                                          │
│  Web Worker ──► Pyodide 0.26.1 (WebAssembly)                 │
│                   ├── numpy, pandas, scipy                    │
│                   ├── statsmodels, scikit-learn               │
│                   └── pingouin, scikit-posthocs, lifelines    │
│                   └── analysis_engine.py  (3.1k lines)        │
│                                                              │
└──────────────┬───────────────────────────────────────────────┘
               │  HTTPS
               ▼
   Google Drive (drive.file scope) ── your workbooks, your account

The parts that matter:

  1. The stats engine is real Python. src/stats/analysis_engine.py (~3,100 lines) is the single source of statistical truth. It executes under Pyodide inside a Web Worker, so heavy analyses never block the UI.
  2. Pyodide loads from a CDN at runtime, but caches locally. The Python runtime and scientific packages are not in the JS bundle. First load pulls tens of MB — the header shows Loading engine…Engine ready. After that, the Service Worker caches everything locally, meaning the app loads instantly on subsequent visits (even offline) and updates silently in the background (StaleWhileRevalidate).
  3. Optional packages install via micropip (pingouin, scikit-posthocs, lifelines) behind defensive imports — if one fails to install, the engine still loads and everything that doesn’t need it still works.
  4. No SharedArrayBuffer, so no COOP/COEP headers are required and the whole app can be served as plain static files.
  5. Storage is Google Drive. Workbooks are JSON files named *.statlens, saved into a StatLens folder in your Drive.

Tech stack

Layer Choice
Build Vite 8 (Rolldown), TypeScript 6
UI React 19, Tailwind CSS 3.4, Radix UI / shadcn/ui, lucide-react
Grid ag-grid-community 35
Charts visx 4, d3-scale / d3-shape / d3-array
Routing react-router-dom 7
Validation zod 4
Stats Pyodide 0.26.1 → NumPy, pandas, SciPy, statsmodels, scikit-learn, pingouin, scikit-posthocs, lifelines
Auth Google Identity Services
Lint oxlint
Tests vitest + a Python-side CI matrix

Correctness

The project’s central rule, from Agents.md:

Statistical correctness is non-negotiable. Every statistic/test has a unit test against known reference values (SciPy/statsmodels/pingouin/lifelines docs, R, or published worked examples) with sensible tolerance. Never change an algorithm without updating tests + comments.

What that looks like in practice:

Statistics CI

.github/workflows/stats-tests.yml runs on every push and PR, against a Python stack pinned to match what the Pyodide worker installs — so CI and the browser can’t silently diverge:

An analysis without a reference test is considered unfinished.


Privacy & data


Code map

StatLens/
├── apps/web/src/
│   ├── App.tsx               # routes, header, engine bootstrap
│   ├── pages/AboutPage.tsx   # in-app about + usage guide
│   ├── stats/
│   │   ├── analysis_engine.py    # ★ all statistics live here (~3.1k lines)
│   │   ├── pyodide.worker2.ts    # Web Worker: boots Pyodide, runs the engine
│   │   ├── engine.ts             # main-thread client for the worker
│   │   └── __tests__/            # golden-value oracle tests
│   ├── charts/
│   │   ├── GraphEngine.tsx       # chart dispatch
│   │   ├── {Column,XY,Survival}Charts.tsx
│   │   ├── SignificanceLayer.tsx # significance bracket layout
│   │   └── geometry/             # pure, testable chart maths
│   ├── components/
│   │   ├── dashboard/            # workbook list
│   │   ├── workspace/            # grid, analyse panel, results, graph settings
│   │   └── ui/                   # shadcn/ui primitives
│   ├── data/                     # auth, Drive API, sheet templates
│   ├── lib/exportGraph.ts        # PNG / SVG export
│   └── types/workbook.ts         # zod schemas for the workbook format
├── apps/web/scratch/         # Python contract + verification scripts (run by CI)
├── docs/
│   ├── PRD.md                    # product requirements
│   ├── AUDIT_MATRIX.md           # every analysis + its runtime/golden status
│   └── *.md                      # statistical references (post hoc, curve fitting…)
├── tests/                        # Python-side oracle tests
└── Agents.md                     # project charter & engineering rules

Acknowledgements

Built on the shoulders of Pyodide, SciPy, statsmodels, pingouin, scikit-posthocs, lifelines, visx, and AG Grid.

Built with Claude and Antigravity.

License

MIT — free to use, modify, and distribute; just keep the copyright notice.