# Example 4 — CSV workflow Demonstrates the full plate-reader CSV round-trip: load → subset → fit → save. Full script: `examples/scripts/05_from_csv.py` ## CSV format pykinbiont expects a CSV where: - The **first column** contains time values (any column name is fine) - **Remaining columns** are OD curves, one per well - **Column headers** become the curve labels ``` time,Well_A1,Well_A2,Well_A3 0.0,0.012,0.011,0.013 0.5,0.014,0.013,0.015 1.0,0.017,0.016,0.018 ... ``` ## Load from CSV ```python import pykinbiont from pykinbiont import GrowthData, FitOptions, ModelSpec, MODEL_REGISTRY, fit, save_results pykinbiont.configure("/path/to/KinBiont.jl") data = GrowthData.from_csv("plate_reader.csv") print(f"Loaded: {len(data.labels)} curves, {len(data.times)} time points") print(f"Labels: {data.labels}") ``` ## Load from a DataFrame ```python import pandas as pd from pykinbiont import GrowthData df = pd.read_excel("plate_reader.xlsx") # or any DataFrame source data = GrowthData.from_dataframe(df) ``` ## Subset wells of interest ```python subset = data[["Well_A1", "Well_B1", "Well_A2"]] print(f"Subset: {subset.labels}") ``` ## Fit ```python logistic = MODEL_REGISTRY["NL_logistic"] spec = ModelSpec( models=[logistic], params=[[1.2, 0.01, 0.5]], lower=[[0.0, 0.0, 0.0]], upper=[[5.0, 1.0, 5.0]], ) opts = FitOptions(smooth=True, smooth_method="rolling_avg") results = fit(data, spec, opts) print(results.to_dataframe()[["label", "best_model", "aic"]].to_string(index=False)) ``` ## Save results ```python paths = save_results(results, "output/", prefix="my_experiment") print("Results saved:") for key, path in paths.items(): n_rows = pd.read_csv(path).shape[0] print(f" {key:15s}: {path} ({n_rows} rows)") ``` ## Read results back ```python import pandas as pd summary = pd.read_csv(paths["summary"]) fitted = pd.read_csv(paths["fitted_curves"]) # Plot one well import matplotlib.pyplot as plt well = summary.iloc[0]["label"] wdf = fitted[fitted["label"] == well] plt.plot(wdf["time"], wdf["observed"], ".", label="observed") plt.plot(wdf["time"], wdf["fitted"], "-", label="fitted") plt.title(well) plt.xlabel("Time (h)") plt.ylabel("OD") plt.legend() plt.show() ```