Metadata-Version: 2.4
Name: pykinbiont
Version: 0.2.1
Summary: Python interface for KinBiont.jl microbial kinetics analysis
Project-URL: Homepage, https://pykinbiont.fuzue.tech
Project-URL: Documentation, https://pykinbiont.fuzue.tech
Project-URL: Repository, https://github.com/fuzue/pykinbiont
Project-URL: Bug Tracker, https://github.com/fuzue/pykinbiont/issues
Author-email: Fuzue Tech <contact@fuzue.tech>
License: MIT License
        
        Copyright (c) 2026 Fuzue Tech
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: bioinformatics,growth curves,julia,kinetics,microbiology
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Python: >=3.11
Requires-Dist: juliacall>=0.9.31
Requires-Dist: numpy>=2.0
Requires-Dist: pandas>=2.0
Provides-Extra: dev
Requires-Dist: jupyter>=1.1.1; extra == 'dev'
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: myst-parser>=3.0; extra == 'docs'
Requires-Dist: pydata-sphinx-theme>=0.14; extra == 'docs'
Requires-Dist: sphinx-autodoc-typehints>=2.0; extra == 'docs'
Requires-Dist: sphinx-copybutton>=0.5; extra == 'docs'
Requires-Dist: sphinx>=7.0; extra == 'docs'
Description-Content-Type: text/markdown

# pykinbiont

Python interface for [KinBiont.jl](https://github.com/pinheiroGroup/KinBiont.jl) — a Julia package for model-based analysis of microbial kinetics data.

## Requirements

- Python ≥ 3.11
- Julia ≥ 1.10 (installed separately — [julialang.org](https://julialang.org/downloads/))

## Installation

```bash
pip install pykinbiont
```

Or with [uv](https://docs.astral.sh/uv/):

```bash
uv add pykinbiont
```

---

## Two modes of operation

### Mode 1 — Managed environment (default)

juliacall creates and manages its own isolated Julia environment with Kinbiont
installed automatically. No local KinBiont.jl clone needed.

**First run is slow** (Julia downloads and installs Kinbiont and its dependencies).
Subsequent runs are fast because the environment is cached.

```python
import pykinbiont

result = pykinbiont.fitting.fitting_one_well_log_lin(data, "A1", "exp1")
```

---

### Mode 2 — Existing local KinBiont.jl environment

If you already have KinBiont.jl installed locally with all dependencies resolved,
you can point pykinbiont directly at that Julia project. This skips the managed
environment and reuses what you already have.

**One-time setup** — add PythonCall to your KinBiont.jl project:

```bash
julia --project=/path/to/KinBiont.jl -e 'using Pkg; Pkg.add("PythonCall")'
```

Then configure pykinbiont to use that path (persisted across sessions):

```python
import pykinbiont

pykinbiont.configure("/path/to/KinBiont.jl")  # run once
```

From then on, just import and use — no reinstallation:

```python
import pykinbiont

result = pykinbiont.fitting.fitting_one_well_log_lin(data, "A1", "exp1")
```

You can also set the path via environment variable before launching Python,
which avoids calling `configure()` entirely:

```bash
export JULIA_PROJECT=/path/to/KinBiont.jl
```

---

## API

### `pykinbiont.configure(project_path)`

Persist a local KinBiont.jl path for Mode 2. Saved to
`~/.config/pykinbiont/config.json`. Must be called before the first fitting
or conversion call (i.e. before Julia starts).

### `pykinbiont.init(project_path=None)`

Explicitly start Julia and load Kinbiont. Optional — all functions trigger
this automatically on first use.

---

### Conversion utilities — `pykinbiont.convert`

```python
import numpy as np
import pandas as pd
import pykinbiont

# numpy array (2, N) or DataFrame → Julia Matrix{Float64}
jl_mat = pykinbiont.convert.to_julia_matrix(np_array)
jl_mat = pykinbiont.convert.to_julia_matrix(df)  # DataFrame with columns [time, OD]

# Julia array → numpy
arr = pykinbiont.convert.from_julia_array(jl_mat)

# Julia matrix → DataFrame
df = pykinbiont.convert.julia_matrix_to_dataframe(jl_mat, columns=["time", "OD"])
```

Input data layout for time-series: shape `(2, N)` where row 0 is time and
row 1 is OD. A DataFrame is expected to have time in the first column and OD
in the second.

---

### Fitting — `pykinbiont.fitting`

#### `fitting_one_well_log_lin`

Log-linear fit of the exponential growth phase for a single growth curve.

```python
import numpy as np
import pykinbiont

data = np.array([
    [0.0, 0.5, 1.0, ..., 7.0],   # time points
    [0.01, 0.012, 0.015, ..., 0.65],  # OD values
])

result = pykinbiont.fitting.fitting_one_well_log_lin(
    data,
    name_well="A1",
    label_exp="exp1",
    # optional parameters:
    type_of_smoothing="rolling_avg",  # "rolling_avg", "lowess", or "NO"
    pt_avg=7,                         # rolling average window (needs ≥ pt_avg points)
    pt_smoothing_derivative=7,        # growth rate estimation window
    pt_min_size_of_win=7,             # minimum exponential window size
    threshold_of_exp=0.9,             # quantile threshold for exp phase detection
)
```

Minimum number of data points required: `pt_avg + pt_smoothing_derivative`
(default: 14). For small datasets reduce these parameters, e.g. `pt_avg=3,
pt_smoothing_derivative=3, pt_min_size_of_win=3`.

**Returns** a `LogLinResult` dataclass:

| Field | Type | Description |
|---|---|---|
| `method` | `str` | Always `"Log-lin"` |
| `params` | `pd.Series` | 14 named fitting parameters (see below) |
| `fit` | `pd.DataFrame` | Columns `time`, `log_fit` over the exponential window |
| `smoothed` | `pd.DataFrame` | Columns `time`, `OD` — smoothed input curve |
| `confidence_band` | `np.ndarray` | 95% confidence band over the fitted window |

**`params` fields:**

| Name | Description |
|---|---|
| `label_exp` | Experiment label |
| `name_well` | Well name |
| `t_start_exp` | Start time of exponential window |
| `t_end_exp` | End time of exponential window |
| `t_max_gr` | Time of maximum specific growth rate |
| `gr_max` | Maximum specific growth rate |
| `growth_rate` | Fitted growth rate (log-linear slope) |
| `sigma_growth_rate` | Standard error of growth rate |
| `doubling_time` | `log(2) / growth_rate` |
| `doubling_time_lower_95` | Doubling time lower 95% bound |
| `doubling_time_upper_95` | Doubling time upper 95% bound |
| `intercept` | Log-linear fit intercept |
| `sigma_intercept` | Standard error of intercept |
| `pearson_r` | Pearson correlation coefficient of the fit |

All numeric fields are `NaN` if the exponential window could not be detected.
