CaTune Workflow¶
CaTune is the interactive parameter tuning approach to calcium trace deconvolution. You choose the deconvolution parameters – rise time constant, decay time constant, and sparsity penalty – and CaTune helps you see how they perform on your real data. Under the hood it uses FISTA deconvolution with a double-exponential calcium kernel, following established approaches from the literature.
The workflow¶
A typical CaTune workflow has four steps:
Load your data – from CaImAn, Minian, or raw NumPy arrays (see Loading Data)
Tune parameters interactively – use
calab.tune()to open CaTune in the browser, adjust parameters, and see the deconvolved result in real timeExport parameters – export your chosen parameters from the browser as a JSON file (or receive them directly as a Python dict via the bridge)
Batch deconvolve – apply those parameters to all your traces with
calab.run_deconvolution()orcalab.deconvolve_from_export()
You can also skip the browser entirely and call run_deconvolution() directly with parameters from the literature.
Interactive tuning with tune()¶
tune() opens CaTune in your browser so you can explore deconvolution parameters interactively. It starts a local HTTP server on 127.0.0.1, opens the web app with a ?bridge= URL parameter pointing to that server, and the browser fetches your traces from the server. When you export parameters from the web app, the browser POSTs them back and tune() returns them as a Python dict.
import calab
import numpy as np
traces = np.load("my_traces.npy") # (n_cells, n_timepoints)
# Opens CaTune in your default browser and blocks until you export params
params = calab.tune(traces, fs=30.0)
if params is not None:
print(params)
# {'tau_rise': 0.02, 'tau_decay': 0.4, 'lambda_': 0.5, 'fs': 30.0, 'filter_enabled': False}
Full signature¶
calab.tune(
traces: np.ndarray,
fs: float = 30.0,
timeout: float | None = None,
port: int | None = None,
app_url: str | None = None,
open_browser: bool = True,
) -> dict | None
Parameter |
Description |
|---|---|
|
Calcium traces. Shape |
|
Sampling rate in Hz. Default: |
|
Seconds to wait. |
|
Port to bind the bridge server to. |
|
Override the CaTune URL (useful for local dev). Default: GitHub Pages deployment. |
|
Whether to auto-open the browser. Default: |
Return value¶
Returns a dict with the parameters you selected, or None if the session was cancelled or timed out. Dict keys:
Key |
Type |
Description |
|---|---|---|
|
|
Rise time constant (seconds) |
|
|
Decay time constant (seconds) |
|
|
Sparsity regularization weight |
|
|
Sampling rate (Hz) |
|
|
Whether high-pass filtering was enabled |
Under the hood, tune() starts a local HTTP server on 127.0.0.1, opens the web app with a ?bridge= URL parameter, and the browser fetches traces from (and posts results back to) that server. The server binds to localhost only and is not network-reachable.
Batch deconvolution with run_deconvolution()¶
Once you have parameters – from tune(), from a CaTune export JSON, or from published values in the literature – apply them to all your traces with run_deconvolution().
Quick activity extraction¶
import numpy as np
import calab
traces = np.load("my_traces.npy") # (n_cells, n_timepoints)
# Using params from tune()
activity = calab.run_deconvolution(
traces, fs=30.0, tau_r=0.02, tau_d=0.4, lam=0.5
)
# activity.shape == traces.shape
You can also use parameters directly from the literature without opening the browser at all:
# GCaMP6f typical values (no browser needed)
activity = calab.run_deconvolution(
traces, fs=30.0, tau_r=0.02, tau_d=0.4, lam=0.5
)
Full signature¶
calab.run_deconvolution(
traces: np.ndarray,
fs: float,
tau_r: float,
tau_d: float,
lam: float,
max_iters: int = 2000,
conv_mode: str = "fft",
constraint: str = "nonneg",
) -> np.ndarray
Parameter |
Description |
|---|---|
|
Calcium traces. Shape |
|
Sampling rate in Hz. |
|
Rise time constant in seconds. |
|
Decay time constant in seconds. |
|
L1 sparsity penalty (regularization strength). |
|
Maximum FISTA iterations. Default: |
|
Convolution mode: |
|
Constraint type: |
Returns a np.ndarray of non-negative activity estimates, same shape as the input traces.
Full results with diagnostics¶
run_deconvolution_full has the same signature but returns a DeconvolutionResult namedtuple with additional diagnostics:
result = calab.run_deconvolution_full(
traces, fs=30.0, tau_r=0.02, tau_d=0.4, lam=0.5
)
result.activity # np.ndarray -- deconvolved activity
result.baseline # float | np.ndarray -- estimated baseline(s)
result.reconvolution # np.ndarray -- model fit (K*activity + baseline)
result.iterations # int | np.ndarray -- FISTA iterations used
result.converged # bool | np.ndarray -- convergence flag(s)
For multi-trace input, baseline, iterations, and converged are arrays (one value per cell).
See the API Reference for the full DeconvolutionResult definition.
From a CaTune export¶
After tuning parameters in the browser, CaTune can export them as a JSON file. Two convenience functions let you load and apply those exact parameters without manually extracting values.
Loading export parameters¶
params = calab.load_export_params("catune_export.json")
# Returns dict with keys: tau_rise, tau_decay, lambda_, fs, filter_enabled
calab.load_export_params(
path: str | Path,
) -> dict
Parameter |
Description |
|---|---|
|
Path to the CaTune export JSON file. |
Returns a dict with keys: tau_rise, tau_decay, lambda_, fs, filter_enabled.
Deconvolving from an export¶
deconvolve_from_export loads the export JSON, applies the bandpass filter if it was enabled during tuning, and runs FISTA deconvolution – all in one call.
# Just the activity array
activity = calab.deconvolve_from_export(traces, "catune_export.json")
# Full diagnostics
result = calab.deconvolve_from_export(
traces, "catune_export.json", return_full=True
)
calab.deconvolve_from_export(
traces: np.ndarray,
params_path: str | Path,
return_full: bool = False,
) -> np.ndarray | DeconvolutionResult
Parameter |
Description |
|---|---|
|
Calcium traces. Shape |
|
Path to the CaTune export JSON file. |
|
If |
Saving and loading data¶
If you prefer a file-based workflow instead of the bridge (for example, preparing data on a cluster and tuning in the browser on your laptop), use save_for_tuning and load_tuning_data.
Saving traces for CaTune¶
calab.save_for_tuning(traces, fs=30.0, path="my_recording")
# Creates: my_recording.npy + my_recording_metadata.json
The .npy file can be loaded directly in CaTune’s browser interface via drag-and-drop. The _metadata.json sidecar records the sampling rate, dimensions, and schema version.
calab.save_for_tuning(
traces: np.ndarray,
fs: float,
path: str | Path,
metadata: dict | None = None,
) -> None
Parameter |
Description |
|---|---|
|
Calcium traces. Shape |
|
Sampling rate in Hz. |
|
Output path stem (without extension). Creates |
|
Additional metadata to include in the JSON sidecar. Optional. |
Loading saved data¶
traces, meta = calab.load_tuning_data("my_recording")
# Reads my_recording.npy + my_recording_metadata.json
calab.load_tuning_data(
path: str | Path,
) -> tuple[np.ndarray, dict]
Parameter |
Description |
|---|---|
|
Path stem (without extension), matching what was passed to |
Returns a tuple of (traces, metadata) where traces is a float64 array and metadata is the JSON sidecar contents.
CLI¶
CaTune workflows are also available from the command line.
Interactive tuning¶
calab tune my_traces.npy --fs 30.0
This opens CaTune in the browser. When you export parameters, they are printed as JSON to stdout.
Batch deconvolution¶
calab deconvolve my_traces.npy --params catune_export.json -o activity.npy
Add --full to save diagnostics alongside the activity array:
calab deconvolve my_traces.npy --params catune_export.json -o activity.npy --full
See the CLI Reference for all commands and options.
End-to-end example¶
Putting it all together – load data, tune interactively, then batch deconvolve:
import calab
# 1. Load traces from CaImAn (requires: pip install calab[loaders])
traces, meta = calab.load_caiman("caiman_results.hdf5")
fs = meta["sampling_rate_hz"]
# 2. Tune parameters in the browser
params = calab.tune(traces, fs=fs)
# 3. Apply to all traces
if params is not None:
activity = calab.run_deconvolution(
traces,
fs=params["fs"],
tau_r=params["tau_rise"],
tau_d=params["tau_decay"],
lam=params["lambda_"],
)
np.save("deconvolved_activity.npy", activity)
Or, using the file-based workflow:
import calab
# 1. Save traces for CaTune
calab.save_for_tuning(traces, fs=30.0, path="my_recording")
# -> Drag-and-drop my_recording.npy into CaTune in the browser
# -> Export parameters as catune_export.json
# 2. Batch deconvolve from the export
activity = calab.deconvolve_from_export(traces, "catune_export.json")