A web application for global kinetic analysis of Single-Cycle Kinetics (SCK) biosensor experiments (SPR / BLI).
SCKAnalyzer fits multi-injection, single-cycle sensorgrams to a 1:1 Langmuir binding model — with optional per-injection bulk (refractive-index) offset correction — and reports association/dissociation rate constants, equilibrium affinity, fit-quality diagnostics, and bootstrap confidence intervals. It is released as open-source software to accompany the associated publication (see Citation).
Live instance: https://sck.iecb.u-bordeaux.fr
Single-cycle kinetics is an experimental design (used in Surface Plasmon Resonance and Bio-Layer Interferometry instruments, e.g. Biacore/BLItz/Octet) in which a single analyte is injected onto a sensor surface at a series of increasing concentrations without a regeneration step between injections, producing one continuous, multi-step sensorgram per replicate.
SCKAnalyzer fits this trace directly using a global, non-linear least-squares approach:
- Binding model: 1:1 Langmuir (
ka,kd,R_max), solved analytically per injection segment. - Global fitting across replicates:
ka/kdare always shared across replicates in global mode; sharingR_maxand sharing per-injection bulk offsets are each an independent, optional toggle. - Nuisance parameters: optional per-injection bulk (refractive-index) offsets, shareable across replicates in global mode.
- Robust loss functions: soft-L1 (default), linear, or Huber loss (via
scipy.optimize.least_squares) to reduce sensitivity to outliers/artifacts. - Uncertainty quantification: asymptotic standard errors from the Jacobian-based covariance estimate, and optional residual-resampling bootstrap (95% CI).
- Fit diagnostics: RMSE, MAE, R², AIC, BIC, and reduced chi-square are computed by the backend; the web UI's results table currently displays RMSE, R², reduced chi-square, and N points.
- Upload generic CSV sensorgrams or Octet .frd files directly, with support for multiple files/replicates and merging datasets together.
- Define injection steps either by clicking start/end markers directly on the sensorgram, or by specifying a serial dilution scheme (start time, injection/gap durations, number of injections, final concentration, dilution factor) that auto-builds the full step table.
- Two independently-configurable, chainable trace corrections per replicate: reference-channel subtraction and double-reference (blank-run) subtraction, each selecting another uploaded replicate.
- A visual "Baseline → 0" normalization for the Prepare-dataset/Define-steps previews (display-only — it does not affect the fitted values), plus a separate baseline correction applied by the fit itself.
- Interactive step editor, exclusion windows (bubbles/spikes), and per-parameter bounds/fixed values.
- Overlaid association/dissociation QA plots with per-injection RMSE and ΔRU normalization.
- Per-plot and per-table CSV/PNG export, plus a single "download all" ZIP bundle (plots, tables, and a manifest).
- Per-replicate and global (multi-replicate, shared-parameter) fitting modes.
SCKAnalyzer/
├── backend/ FastAPI service: parsing (CSV/FRD) and kinetic fitting (NumPy/SciPy)
│ ├── app/
│ │ ├── main.py API endpoints
│ │ ├── fit.py 1:1 Langmuir model, global fitting, bootstrap
│ │ ├── csv_parser.py Generic CSV / BLI DAT parsing
│ │ └── frd_parser.py Octet BLI .frd (XML) parsing
├── frontend/ React + Vite + Plotly single-page application
├── deploy/ Reference nginx/systemd provisioning script + config template
└── Dockerfile Backend container image
- Python ≥ 3.11
- Node.js ≥ 18
- Production (Option B below) additionally requires an apt-based Linux distribution (e.g. Ubuntu/Debian) with sudo access
Runs the backend with auto-reload and the frontend with Vite's dev server. Intended for local development, not for serving real users.
1) Backend (FastAPI)
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000Health check: http://localhost:8000/api/health
2) Frontend (React)
cd frontend
npm install
npm run devOpen http://localhost:5173 — the Vite dev server proxies /api/* to http://localhost:8000.
The backend's CORS policy (
backend/app/main.py) is intentionally permissive (allow_origins=["*"]) for local development. Tighten it before exposing the API beyond a trusted network (see Production, below).
Two supported paths, depending on whether you want just the API in a container or a full turnkey host.
Option A — Backend API only, via Docker
Builds a container image for the FastAPI backend only (no pre-built image is published on a registry, and the frontend is not included):
docker build -t sckanalyzer-backend .
docker run -p 8000:8000 sckanalyzer-backendYou are responsible for building the frontend (npm run build in frontend/, producing frontend/dist/) and serving those static files yourself (nginx, any static host, etc.), configured to send /api/* to this backend container. You should also restrict the backend's CORS allow_origins (backend/app/main.py) to your actual frontend origin(s).
Option B — Full host (frontend + backend + nginx + systemd)
deploy/setup_server.sh provisions an apt-based Linux host (e.g. Ubuntu/Debian; it relies on apt-get and is not portable to non-apt distributions) end-to-end: builds both the frontend and backend, installs a systemd unit for the backend, and configures nginx to serve the frontend and reverse-proxy /api/ to it. As shipped, this serves plain HTTP on port 80 with no TLS and assumes IP-only access on a trusted network (see the script's header comments for the exact security assumptions — add TLS/a domain yourself if the host will be reachable more broadly).
Deployment-specific values (app user, install path, virtualenv path, service/site names, backend port) are kept out of the script and out of version control:
cp deploy/config.example.sh deploy/config.sh
$EDITOR deploy/config.sh # adjust for your server
sudo ./deploy/setup_server.shdeploy/config.sh is gitignored, so your server's paths and usernames are never committed.
- Upload a sensorgram file (generic CSV, or an Octet
.frdfile) via the web UI. - Select the time and response columns for each replicate, and optionally configure reference-channel subtraction and/or double-reference (blank-run) subtraction by choosing another uploaded replicate.
- Define injection steps by clicking start/end markers on the sensorgram, or by specifying a serial dilution scheme that auto-builds the step table; optionally mark exclusion windows to remove from the fit.
- Choose per-replicate or global fitting mode, configure bulk-offset fitting and its sharing, robust loss, baseline handling, and per-parameter bounds/fixed values, then run the fit.
- Inspect fitted parameters, quality metrics, and residual/overlap plots; export results as CSV/PNG per plot or as a single ZIP bundle.
Generic CSV input requires at minimum a time column and a response column (e.g. time, ru) per replicate; injection concentrations are entered in the step table rather than read from a column, and a reference/blank trace is selected from among the other uploaded replicates rather than from a column in the same file. Octet BLI .frd files are parsed directly (baseline/association/dissociation segments are stitched automatically; regeneration/neutralization steps are excluded).
There is no automated test suite (no CI, no pytest). To smoke-test manually: start the app (see Installation) and upload a sensorgram file via the UI to verify parsing, step definition, and fitting end to end.
The backend exposes a small JSON/multipart API (see backend/app/main.py):
| Endpoint | Description |
|---|---|
GET /api/health |
Liveness check |
POST /api/parse |
Parse an uploaded CSV/FRD file, return columns |
POST /api/fit |
Fit a single sensorgram — either file+time_col+ru_col, or pre-processed t_json+y_json arrays |
POST /api/fit_global |
Global fit across multiple replicates — either file+replicates_json, or pre-processed series_json (array of {t, y}) |
If you use SCKAnalyzer in your research, please cite:
Malard, F., Blanc, J.-M., Roubin, E., Schäfer, T. & Di Primo, C. SCKAnalyzer: An Online Tool for Single Cycle Kinetics Data Processing. In preparation, 2026.
A CITATION.cff / archived software DOI (e.g. via Zenodo) will be added at the time of publication.
SCKAnalyzer is released under the GNU General Public License v3.0 (GPL-3.0-or-later).
- Florian Malard — florian.malard@gmail.com
- Carmelo Di Primo — carmelo.di-primo@inserm.fr
