Catch plate, row, column, edge, replicate, and missing-control risks in an existing microplate map before the experiment starts.
PlateProof is a small, fully offline CLI. Give it a long-form CSV and declare the categorical factors, replicate identifier, or roles you care about. It returns a terminal decision plus deterministic JSON, Markdown, and a self-contained HTML/SVG plate report. Your layout never leaves the machine.
PlateProof: REVIEW - 8 wells across 2 plates; 6 risk findings.
Reports: plateproof-report
A valid CSV can still encode a risky experiment: every drug well may be on one plate, one cohort may sit in a single row, technical replicates may touch, or a plate may lack the requested positive control. These are easy to miss in a spreadsheet and costly to discover after wet-lab work.
PlateProof is for researchers, screening teams, and data stewards who already have a plate map and want a quick, reviewable preflight. It audits the supplied layout; it does not create or optimize one.
PlateProof requires Python 3.11 or newer and has no runtime dependencies.
python -m pip install "https://github.com/KanadeK/plateproof/releases/download/v0.1.0/plateproof-0.1.0-py3-none-any.whl"
plateproof --versionThe wheel, source distribution, and ready-to-open demo bundle are also on the v0.1.0 release.
Download the demo bundle, unpack it with Python, and audit the intentionally risky layout:
curl -LO https://github.com/KanadeK/plateproof/releases/download/v0.1.0/plateproof-0.1.0-demo.zip
python -m zipfile -e plateproof-0.1.0-demo.zip .
cd plateproof-demo
plateproof audit examples/risky.csv \
--factor treatment \
--factor cohort \
--replicate sample_id \
--role-column role \
--require-role positive_control \
--out plateproof-reportExit 1 is expected here: the audit completed and wrote reports, but found
risks worth review. Open plateproof-report/report.html in any browser. The
example finds all three v0.1.0 rule families:
factor_level_confined: treatment and cohort levels are each tied to one plate;replicate_clustered: the twoS1wells are adjacent;required_role_missing: plateP2has nopositive_control.
The report's plate-association evidence includes:
{
"factor": "treatment",
"dimension": "plate",
"normalized_mutual_information": 1.0,
"factor_levels": 2,
"position_levels": 2
}Normalized mutual information (NMI) is descriptive evidence, not a statistical significance test.
PlateProof expects UTF-8 long-form CSV: one occupied well per row. The identity
columns default to plate and well; each audited value must be non-empty.
plate,well,treatment,cohort,sample_id,role
P1,A1,drug,trial,S1,negative_control
P1,A2,drug,trial,S1,sample
P2,G11,control,reference,C1,negative_controlWell names are case-insensitive and normalized (a01 becomes A1). A
(plate, well) pair must be unique and inside the declared geometry. The
defaults are 8 rows by 12 columns; v0.1.0 supports up to 26 rows and 99 columns,
with at most 100,000 occupied wells.
Use different identity column names when necessary:
plateproof audit layout.csv \
--plate-column plate_id \
--well-column position \
--factor treatment \
--out reportFor every --factor, PlateProof computes counts and NMI against plate, row,
column, and edge membership. A risk finding is emitted when a factor level with
at least two wells is completely confined to one positional value while that
position varies in the input.
--replicate COLUMN reports a group when all of its wells are on one plate and
every member touches another group member orthogonally. --role-column plus
repeatable --require-role checks the declared role on every plate.
The output directory must not already exist. A valid audit writes exactly:
| File | Use |
|---|---|
report.json |
Versioned plateproof.report.v1 automation contract |
report.md |
Portable review summary and actions |
report.html |
Self-contained, escaped HTML with SVG plate maps |
Reports contain the source filename, never its absolute path. HTML has no JavaScript, external font, tracker, or network request.
From a repository checkout or the demo bundle:
# Balanced 96-well-style input: exit 0
plateproof audit examples/balanced.csv \
--factor treatment --factor cohort \
--role-column role \
--require-role negative_control --require-role positive_control \
--out balanced-report
# 384-well geometry and zero-padded well names: exit 0
plateproof audit examples/boundary_384.csv \
--rows 16 --columns 24 \
--factor condition \
--out boundary-report
# Duplicate normalized well: exit 2, no report directory
plateproof audit examples/invalid_duplicate.csv \
--factor treatment \
--out invalid-reportThe invalid example prints:
plateproof: error: row 3 has duplicate well P1/A1; each plate/well pair must be unique
| Code | Meaning | What to do |
|---|---|---|
0 |
Valid audit; no declared risk rule triggered | Review the metrics and continue with domain judgment |
1 |
Valid audit; one or more reports were written | Open the report and review the stated evidence/action |
2 |
Invalid arguments/input or report-write failure | Fix the stderr message and rerun with a new output path |
| Message or behavior | Cause | Fix |
|---|---|---|
missing required column: treatment |
A declared column is absent or spelled differently | Correct the header or change the relevant CLI column option |
duplicate well P1/A1 |
Case and zero padding normalize to the same well | Keep one row or correct the plate/well identity |
outside declared 8x12 geometry |
The map is larger than the defaults or the well is wrong | Correct the well, or pass the actual --rows and --columns |
output path already exists |
PlateProof never overwrites a report directory | Choose a new --out path; remove old output yourself only if intended |
Command exits 1 but reports exist |
This is a review result, not a crash | Read report.html or consume report.json |
cannot read CSV ... |
The file is missing, unreadable, malformed, or not UTF-8 | Check the path/permissions and export UTF-8 CSV |
- PlateProof only evaluates declared categorical columns and plate, row, column, and edge geometry.
- NMI and the explicit rules are descriptive preflight signals. They are not hypothesis tests and do not prove bias, causality, or experimental validity.
- The tool does not know dispensing order, chemistry, incubation, batch history, intentional gradients, or whether a scientific design choice is appropriate.
- It does not generate/randomize layouts, create liquid-handler worklists, or analyze assay readings, images, OD values, or dose response.
- Replicate adjacency is a transparent review heuristic, not proof that the layout is wrong.
These boundaries are deliberate. See the accepted specification and near-neighbor evidence for the product and novelty scope.
git clone https://github.com/KanadeK/plateproof.git
cd plateproof
uv sync --locked --all-extras --dev
uv run python scripts/check.pyThe single gate checks the lock file, formatting, lint, strict types, unit and
integration tests with branch coverage, all four committed examples, local
Markdown links and main README commands, dependency vulnerabilities, wheel and
sdist contents, the demo bundle, clean-environment wheel installation, and a
real run through the installed plateproof entry point. CI calls the same
command on Linux/Python 3.11 and Windows/Python 3.14.
To reproduce the three release assets in a new dist directory:
uv run python scripts/release_assets.py distMIT © 2026 KanadeK.