A Streamlit web app for processing and exploring droplet digital PCR (ddPCR) data from Bio-Rad QX600 or QX200 instruments.
- Two analysis modes — Full Analysis (multi-plate, with metadata) and Quick Screen (single-file, no metadata)
- Multi-plate processing — Upload multiple ddPCR files and map them to sample plates
- Flexible metadata — Configurable reaction volume, template volume, elution volume, and dilution factor with per-sample overrides
- Detection QC — Automatic detection thresholds (>= 10,000 accepted droplets AND >= 3 positives)
- Extraction efficiency — Optional gyrA-based internal control calculation
- Publication-ready visualizations — Detection heatmaps, concentration distributions, and box plots
- Results explorer — Standalone tool for post-hoc grouping, multi-target comparisons, and target-vs-target scatter plots
- CSV export — Download processed results for downstream analysis
git clone https://github.com/SymbioSeas/Droplette.git
cd Droplettepython -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windowspip install -r requirements.txt# Main processing app
streamlit run droplette.py
# Results explorer (standalone)
streamlit run explore.pyThe app will open in your browser at http://localhost:8501.
Add the following lines to your ~/.zshrc (macOS/Linux with zsh) or ~/.bashrc (bash):
alias droplette='streamlit run /path/to/droplette/droplette.py'
alias droplette-explore='streamlit run /path/to/droplette/explore.py'Replace /path/to/droplette with the absolute path to your cloned repository. Then reload your shell config:
source ~/.zshrc # or source ~/.bashrcAfter that you can launch Droplette from any working directory:
droplette # opens the main processing app
droplette-explore # opens the results explorerDroplette offers two modes selectable at the top of the app.
Multi-plate workflow that links ddPCR data to a sample metadata CSV. Use this when you have sample weight/volume information and want quantified copies per unit (copies/mL or copies/g).
Steps:
- Upload files — One or more ddPCR CSV exports from a Bio-Rad QX600 and a sample metadata CSV
- Map plates — Assign each ddPCR file to a plate identifier defined in your metadata
- Select targets — Choose which targets to quantify
- Configure sample types — Map each
Sample_Typeto the metadata column containing sample weight or volume - Set assay parameters — Reaction volume, template volume, elution volume, and dilution factor
- Optional overrides — Map metadata columns to override any parameter per sample
- Optional extraction efficiency — Enable gyrA-based efficiency calculation
- Run — Click "Run Processing"; results appear as a table with a CSV download
Metadata-free workflow for a single ddPCR plate. All wells share the same parameters. Sample names come from the Sample description 1 column in the Bio-Rad export (falls back to well position if blank).
Steps:
- Upload — A single ddPCR CSV from a Bio-Rad QX600
- Replicate handling — If duplicate sample labels are detected, choose to treat wells separately or average replicates
- Select targets
- Set parameters — Reaction volume, template volume, elution volume, dilution factor, sample amount, sample unit (mL or g), and nucleic acid type
- Run — Click "Run Quick Screen"
Standard Bio-Rad QX600 CSV export. Required columns:
| Column | Description |
|---|---|
Well |
Well position (e.g., A01, B12) |
Target |
Target/assay name |
Conc(copies/µL) |
Concentration in copies per µL |
Accepted Droplets |
Number of accepted droplets |
Positives |
Number of positive droplets |
Optional columns recognized by Droplette:
| Column | Description |
|---|---|
Sample description 1 |
Sample label used by Quick Screen as Sample_Name |
Notes:
- Comma-formatted numbers (e.g.,
1,731.37) are handled automatically - BOM (
utf-8-sig) encoding is handled automatically - Target names are lowercased and stripped of whitespace internally for consistent matching
- Well names are normalized (zero-padding removed:
A04→A4) to ensure consistent joining across files
A CSV linking wells to sample information. Required columns:
| Column | Description |
|---|---|
Sample_Name |
Unique sample identifier |
Well |
Well position matching the ddPCR file |
Plate |
Plate identifier matching the plate-to-file mapping |
Recommended columns:
| Column | Description |
|---|---|
Sample_Type |
Sample type (e.g., water, tissue) — determines unit label (copies/mL vs copies/g) |
Material |
Per-sample nucleic acid type (RNA or DNA); overrides the run-level setting when present |
| numeric columns | Sample weight/volume columns selectable as the "sample amount" denominator |
Per-sample parameter override columns (optional):
| Column | Description |
|---|---|
| any numeric column | Can be mapped to override reaction_vol, template_vol, elution_vol, dilution_factor, or sample_amount for individual samples |
A target is reported as one of three states:
| Status | Condition |
|---|---|
| Detected (numeric value) | Accepted droplets >= 10,000 AND positives >= 3 |
| ND (not detected) | Accepted droplets >= 10,000 but positives < 3 (or concentration is NaN) |
| CNC (could not calculate) | Accepted droplets < 10,000 — insufficient droplets for reliable quantification |
A missing sample amount (zero or blank) also produces ND regardless of droplet counts.
copies/unit = (Conc × reaction_vol × elution_vol) / (template_vol × dilution_factor × sample_amount)
| Variable | Description |
|---|---|
Conc |
ddPCR concentration in copies/µL (from the instrument) |
reaction_vol |
Total reaction volume in µL (default: 22 µL) |
elution_vol |
Volume of the extraction eluate in µL (default: 200 µL) |
template_vol |
Volume of eluate added to each reaction in µL (default: 5 µL) |
dilution_factor |
Pre-PCR dilution factor (default: 1.0, i.e., undiluted) |
sample_amount |
Weight (g) or volume (mL) of the original sample used for extraction |
unit |
mL for samples whose Sample_Type contains "water"; g for all other types |
Example: A water sample with Conc = 2.5 copies/µL, reaction_vol = 22 µL, elution_vol = 200 µL, template_vol = 5 µL, dilution_factor = 1.0, and sample_amount = 1.0 mL:
copies/mL = (2.5 × 22 × 200) / (5 × 1.0 × 1.0) = 2,200 copies/mL
Requires a gyrA internal control spiked into samples before extraction.
measured_total = gyra_conc × reaction_vol × elution_vol / (template_vol × dilution_factor)
expected_input = halo_conc × halo_vol
efficiency (%) = (measured_total / expected_input) × 100
| Variable | Description |
|---|---|
gyra_conc |
Measured gyrA concentration in copies/µL |
halo_conc |
Known concentration of the Halo gyrA spike stock in copies/µL |
halo_vol |
Volume of Halo spike added to the sample before extraction in µL |
Efficiency is only calculated when the gyrA target itself passes the detection threshold (>= 10,000 droplets AND >= 3 positives). Otherwise Extraction_Efficiency_Pct is NaN.
The results CSV contains all metadata columns plus:
| Column | Description |
|---|---|
<Target> |
Copies per unit (numeric) for detected samples; ND or CNC otherwise |
Unit |
Unit label for the target columns (copies/mL or copies/g) |
Nucleic_Acid_Type |
DNA or RNA, from the Material metadata column or the run-level setting |
Extraction_Efficiency_Pct |
Extraction efficiency in percent (Full Analysis, if enabled) |
In Quick Screen mode the output also includes a Well column showing the well position (or comma-separated list of wells when replicates are averaged).
When multiple wells share the same Sample description 1 label, Droplette offers two options:
| Mode | Behavior |
|---|---|
| Separate | Each well produces its own row; duplicate labels get the well position appended, e.g., Isolate_X (A1) |
| Average | Detection is assessed per well; copies/unit values are averaged across wells that are individually detected. If all replicates are ND the result is ND. If all are CNC the result is CNC. Mixed CNC/ND with no detections produces ND. |
When the same sample appears across multiple plates (e.g., a sample run for different targets on separate plates), Droplette merges the rows into one:
- Rows are matched by
Sample_Name(andMaterialif that column is present, so RNA and DNA plates for the same sample stay separate) - Real numeric values take precedence over
ND— if a target was detected on one plate, that value is kept
A standalone Streamlit app for exploring the processed results CSV.
Launch:
streamlit run explore.pyWorkflow:
- Upload the results CSV produced by Droplette
- Configure columns — the app auto-detects target columns (those containing
ND), discrete grouping columns (categorical or low-cardinality), and continuous columns - Select a target and grouping variables to filter and stratify the data
Visualizations:
| Panel | Description |
|---|---|
| Summary Table | N, detected count, ND count, detection %, mean/median/min/max of detected values per group |
| Detection Rate Bar Chart | Stacked bar showing detected vs ND counts per group |
| Concentration Distribution | Strip plot (log scale) of detected values; ND samples shown as open triangles below the axis |
| Multi-Target Detection Heatmap | Detection rate (%) across all targets × groups when multiple targets are loaded |
| Target vs Target Scatter | Log–log scatter comparing two targets; rug marks on axes show partial detections (one target ND) |
droplette/
├── droplette.py # Main processing UI (Full Analysis + Quick Screen)
├── explore.py # Results explorer UI
├── processing.py # Core processing logic (no Streamlit dependency)
├── tests/
│ └── test_processing_simple.py # Unit tests for process_simple()
├── requirements.txt # Python dependencies
└── README.md
- Python 3.9+
streamlit,pandas,numpy,matplotlib,seaborn,pytest
MIT