Quick start#

This page walks through the most common workflow end-to-end: load data, fit a growth model, inspect results, and save to CSV.

1. Configure (once per machine)#

If you have a local KinBiont.jl clone, point pykinbiont at it. Skip this step to use the registry-installed version.

import pykinbiont
pykinbiont.configure("/path/to/KinBiont.jl")
# Restart the Python process / Jupyter kernel once after this call.

2. Load data#

from pykinbiont import GrowthData

# From a CSV file (first column = time, remaining columns = wells/curves)
data = GrowthData.from_csv("plate_reader_export.csv")

print(f"{len(data.labels)} curves, {len(data.times)} time points")
print("Labels:", data.labels[:4])

Or build from a NumPy array directly:

import numpy as np
from pykinbiont import GrowthData

times  = np.linspace(0, 20, 100)
curves = np.stack([0.01 + 1.2 / (1 + 119 * np.exp(-0.5 * times))] * 3)

data = GrowthData(
    curves=curves,
    times=times,
    labels=["A1", "A2", "A3"],
)

3. Choose a model#

pykinbiont exposes all KinBiont built-in models via MODEL_REGISTRY:

from pykinbiont import MODEL_REGISTRY, ModelSpec

# List available models
print(list(MODEL_REGISTRY.keys()))

# Pick the logistic model
logistic = MODEL_REGISTRY["NL_logistic"]
print("Parameters:", logistic.param_names)  # ['N_max', 'growth_rate', 'lag']

Parameter naming

KinBiont uses legacy parameter names. For NL_logistic the actual order is [N_max, N0, mu] but the names are ['N_max', 'growth_rate', 'lag']. When setting initial guesses and bounds, use the positional order: params=[[N_max, N0, mu]].

Build a ModelSpec with initial guesses and optional bounds:

spec = ModelSpec(
    models=[logistic],
    params=[[1.2, 0.01, 0.5]],      # [N_max, N0, mu] initial guess
    lower=[[0.3, 1e-3, 0.05]],      # lower bounds
    upper=[[3.0, 0.05, 3.0]],       # upper bounds
)

4. Set fitting options#

from pykinbiont import FitOptions

opts = FitOptions(
    smooth=True,
    smooth_method="rolling_avg",   # smooth before fitting
    multistart=True,
    n_restart=20,                  # multi-start restarts for robustness
)

5. Fit#

from pykinbiont import fit

results = fit(data, spec, opts)

fit() sends data and configuration to Julia, runs the optimizer for every curve, selects the best model by AICc, and returns a GrowthFitResults.

6. Inspect results#

# Summary DataFrame
df = results.to_dataframe()
print(df[["label", "best_model", "aic", "param_1", "param_2", "param_3"]])

# Iterate over individual curve results
for r in results:
    params = dict(zip(r.param_names, r.best_params))
    print(f"{r.label}: N_max={params['N_max']:.3f}  AIC={r.best_aic:.1f}")

7. Plot#

import matplotlib.pyplot as plt

for r in results:
    idx = data.labels.index(r.label)
    plt.plot(data.times, data.curves[idx], ".", alpha=0.4, label=f"{r.label} data")
    plt.plot(r.times, r.fitted_curve, "-", label=f"{r.label} fit")

plt.xlabel("Time (h)")
plt.ylabel("OD")
plt.legend()
plt.tight_layout()
plt.show()

8. Save#

from pykinbiont import save_results

paths = save_results(results, "output/", prefix="my_experiment")
# Writes:
#   output/my_experiment_summary.csv
#   output/my_experiment_fitted_curves.csv
#   output/my_experiment_all_models.csv

Next steps#