Interactive R Shiny platform for bacterial growth and lysis curve phenotyping
Author: Michael Baffour Awuah — Ramsey Lab
Source file:Lysis Curve Ap 26.03.13.R
Blog post / overview: mbaffour.github.io/lysis-curve-app (seeblogpost.html)
The Lysis Curve OD Visualization App is a self-contained R Shiny application that turns raw plate-reader OD (optical density) CSV exports into publication-quality figures and quantitative phenotypic profiles — with no programming required beyond launching the app.
Experimental microbiologists, phage biologists, and any researcher who uses a microplate reader to track bacterial cultures. No R experience needed. Supported experiment types:
# Required
install.packages(c(
"shiny", "tidyverse", "ggpubr", "scales", "ggrepel",
"ggprism", "svglite", "jsonlite", "zoo", "DT"
))
# Optional — Excel-paste grid in Data Entry tab
install.packages("rhandsontable")
# Optional — PowerPoint export
install.packages(c("officer", "rvg"))
# Optional — animated GIF export
install.packages("gifski")
| Package | Role |
|---|---|
shiny |
Web application framework |
tidyverse |
Data manipulation (dplyr, tidyr) and plotting (ggplot2) |
ggpubr |
Statistical annotation, publication themes |
scales |
Axis formatting (log scales, labels) |
ggrepel |
Non-overlapping end-of-curve labels |
ggprism |
Publication-style ggplot2 theme |
svglite |
SVG vector graphics device |
jsonlite |
JSON for Save/Load Settings |
zoo |
Rolling window functions for metric calculation |
DT |
Interactive data tables |
rhandsontable |
Excel-paste spreadsheet grid in Data Entry (optional) |
officer |
PowerPoint generation (optional) |
rvg |
Vector graphics in PowerPoint (optional) |
gifski |
Animated GIF encoding (optional) |
Option 1 — RStudio:
File > Open File → select Lysis Curve Ap 26.03.13.ROption 2 — R console:
shiny::runApp("path/to/Lysis Curve Ap 26.03.13.R")
The app opens in your default browser. Keep the R console open while using it.
Most plate readers export wide format — one column per sample, one row per timepoint.
time,SampleA,SampleB,Control
0,0.05,0.06,0.04
10,0.08,0.09,0.07
20,0.14,0.15,0.12
Replicates in wide format: Stack replicate blocks vertically. The app detects where the time counter resets and assigns replicate IDs automatically.
time,SampleA,Control
0,0.05,0.04
10,0.08,0.07
20,0.14,0.12
0,0.06,0.05 ← replicate 2 starts here
10,0.09,0.08
20,0.15,0.13
A grouping column named variable, condition, treatment, sample, or group triggers long-format detection.
time,condition,OD
0,phage_treated,0.05
0,untreated,0.06
10,phage_treated,0.08
10,untreated,0.09
A column named replicate, rep, or well is used for replicate-aware statistics.
Seven modes for showing data spread, selected from the Variability / Error Display panel:
| Mode | What is shown |
|---|---|
| None | Mean line only |
| Error Bars | ±SD, SEM, or 95 % CI as T-bars or line bars |
| Shadow / Ribbon | Filled band ±SD, SEM, or 95 % CI |
| Spaghetti (Replicates) | Every individual replicate as a semi-transparent trace |
| Quantile Bands | Nested shaded bands: IQR (25–75 %) inner + 2.5–97.5 % outer |
| Jitter Points | Raw replicate observations scattered at each timepoint |
| Combo (Traces + CI Band) | Replicate spaghetti traces + a light CI ribbon, mean line on top |
All modes use the actual replicate structure of your data (wide block detection or explicit replicate column).
The plotting area (panel) is locked to constant pixel dimensions regardless of:
Long labels are automatically word-wrapped at a configurable character limit (default 20 chars, adjustable in the Legend panel). The figure container expands rightward to fit whatever the legend needs — the graph itself never shrinks.
A dedicated Experiment Notes tab captures a full experimental record:
Notes can be:
After uploading data and computing metrics, the Analysis tab provides:
rhandsontable) — resize, paste with Ctrl+V, click Applynls)A collapsible sidebar panel lets you draw a labeled horizontal OD reference line on the main plot:
Click Save Settings to download a JSON file that captures:
Load the JSON on your next session to restore everything exactly. Sliders, checkboxes, dropdowns, and multi-select fields all round-trip correctly.
| Output | Formats |
|---|---|
| Main plot | PDF, PNG, SVG, TIFF, JPEG |
| Animated GIF | Frame-by-frame reveal of samples |
| PowerPoint | Vector plot + optional notes slide |
| Analysis plots | PDF, PNG, SVG per plot type |
| Curve fit plot | PDF, PNG, SVG, TIFF |
| Compare plot | PDF, PNG, SVG, TIFF |
| Metrics table | CSV |
| Statistics | CSV |
| Curve fit parameters | CSV |
| Notes | TXT, CSV, PDF, HTML, JSON, PNG |
| Settings | JSON (save/restore full session) |
| Batch ZIP | All of the above in one archive |
| # | Metric | Description |
|---|---|---|
| 1 | μmax | Maximum specific growth rate (log-linear slope) |
| 2 | Lag phase | Time before exponential growth begins |
| 3 | Max OD | Peak optical density reached |
| 4 | Time to max OD | Time at which peak OD occurs |
| 5 | AUC | Area under the OD curve (trapezoidal) |
| 6 | Final OD | OD at the last recorded timepoint |
| 7 | Doubling time | ln(2) / μmax |
| 8 | Time to half-max OD | Time to reach 50% of peak OD |
| 9 | Lysis onset time | First timepoint where OD begins sustained decline |
| 10 | Lysis rate | Slope of OD decline during lysis |
| 11 | Min OD post-lysis | Lowest OD reached after lysis onset |
| 12 | Time to min OD | Time at which minimum post-lysis OD occurs |
| 13 | OD drop | Magnitude of OD decline from peak to minimum |
| 14 | Lysis efficiency | OD drop as a fraction of peak OD |
| 15 | Infection strength | Ratio of AUC (infected) to AUC (uninfected reference) |
| 16 | Growth suppression | 1 − (peak OD infected / peak OD uninfected) |
| 17 | Lysis speed | Inverse of time from infection to lysis onset |
| 18 | Burst proxy | Post-lysis recovery slope |
| 19 | Recovery ratio | Final OD / peak OD |
Statistics are computed in the Analysis tab after selecting a reference sample:
New tabs:
nls fitting, overlay plot, parameters table (A, k, t₀, R²)New Analysis sub-tab:
Sidebar addition:
Optional new dependency:
rhandsontable — Excel-paste grid in Data Entry (app works without it)| Problem | Likely cause | Fix |
|---|---|---|
| App does not launch | Missing packages | Re-run install.packages(...) from the Installation section |
| No samples appear after upload | File not parsed | Check that the file is CSV and the first column is numeric time |
| Error bars missing | Only one replicate | Replicate blocks must be present for SD/SEM to be computed |
| Metrics tab empty | Metrics not calculated | Click Calculate Metrics in the Analysis tab |
| Plot panel shrinks with long names | Fixed-panel feature | Increase Wrap labels at slider in the Legend panel to wrap long names |
| Settings file does not load | Wrong JSON structure | Only load files saved by this app |
| Data Entry grid not visible | rhandsontable not installed |
Run install.packages("rhandsontable") and restart the app |
| Curve fit did not converge | Too few points or no growth phase | Try toggling Fit growth phase only or use a dataset with a clearer growth curve |
| Batch ZIP is empty | No data or metrics loaded | Load data, calculate metrics, then export |
Feature requests and bug reports are welcome via GitHub Issues:
github.com/mbaffour/lysis-curve-app/issues
Please include:
R.version.string) and OSIf you use this app in published work, please cite it as:
Baffour Awuah, M. (2026). Lysis Curve OD Visualization App [R Shiny application]. Ramsey Lab. https://github.com/mbaffour/lysis-curve-app
Contact: Open a GitHub Issue, or reach out via LinkedIn.
Lab: Ramsey Lab — PI: Dr. Jolene Ramsey