Metadata-Version: 2.4
Name: pysaysuite
Version: 0.2.2
Summary: Python Assay Suite for quick and reproducible assay analyses in python.
Project-URL: Homepage, https://github.com/hasanalsharoh/pySaySuite
Project-URL: Repository, https://github.com/hasanalsharoh/pySaySuite
Project-URL: Issues, https://github.com/hasanalsharoh/pySaySuite/issues
Author: Hasan Alsharoh
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ANCOVA,MIQE,bioinformatics,differential-expression,qPCR
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Requires-Python: >=3.10
Requires-Dist: matplotlib>=3.6
Requires-Dist: numpy>=1.23
Requires-Dist: openpyxl>=3.1
Requires-Dist: pandas>=1.5
Requires-Dist: patsy>=0.5
Requires-Dist: scipy>=1.9
Requires-Dist: seaborn>=0.12
Requires-Dist: statsmodels>=0.14
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: xlrd>=2.0
Provides-Extra: dev
Requires-Dist: black>=24.0; extra == 'dev'
Requires-Dist: ipykernel>=6.0; extra == 'dev'
Requires-Dist: nbconvert>=7.0; extra == 'dev'
Requires-Dist: nbformat>=5.9; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: xlwt>=1.3; extra == 'dev'
Description-Content-Type: text/markdown

# pySaySuite
**py**thon as**Say** **Suite** for quick, robust and reproducible assay analyses in python.

# Installation (general)
The package can be obtained from PyPI:
```bash
pip install pySaySuite
```

## qPCR module
Standardized, reproducible **qPCR differential-expression analysis** for the lab.
One canonical, tested implementation of the ANCOVA / multivariable-linear-model method of

> Hampton et al., *Analyzing qPCR data: better practices to facilitate rigor and
> reproducibility*, **Biochem. Biophys. Rep. 44 (2025) 102356**.

The statistical method is theirs; this package ports it to Python for Applied Biosystems
**ViiA 7 / QuantStudio** exports. 

### Details

The module is qPCR-focused and reproduces the published *better practices* paper **1:1**
(Tables 3 & 4 ANCOVA to 3 dp, geNorm conclusion, GAPDH–MMP10 correlation, and the
amplification efficiencies 1.53/1.57 to ~1e-6 against the `qpcR` R oracle). The whole
analysis is a short, curated set of functions in two modules:

- **`pysaysuite.qpcr.core`** — the headline pipeline:
  - `read_plates({name: path}, kind="results"|"amplification", batch_map=None)` — ingest
    QuantStudio/ViiA 7 exports into a tidy long table, **retaining plate identity** (D9).
  - `assign_group(long, group)` — configurable sample→group assignment (prefix-dict /
    callable / layout table), flagging unmatched samples instead of silently grouping them.
  - `build_wide(long, ...)` — collapse technical replicates to mean CT; flag noisy
    replicate groups (`wide.attrs["noisy_replicates"]`, D11).
  - `run_ancova(wide, targets, refs, ...)` — per-target ANCOVA on raw CT, returning a
    **tidy coefficient DataFrame** (one row per model term). Supports a `formula=` override
    and `reference="gmean"` (default) / a gene name / `"separate"` (D3); BH-FDR across the
    panel (D5) and an observations-per-parameter guard (D8).
  - `check_identifiability(...)` — Group⊥plate separability (D6); `run_ancova` also warns
    on confounded designs automatically.
- **`pysaysuite.qpcr.qc`** — quality screens and efficiency-based cross-checks:
  - `genorm2` — geNorm *M* reference selection, a 1:1 port of `ctrlGene::geNorm2` (D14).
  - `reference_stability`, `target_reference_correlation` — reference QC.
  - `estimate_eff(amp, design=..., method="spline")` — per-gene efficiency; the optional
    `design=` metadata join restricts the screen to real sample wells (drops NTC/water),
    which is what makes the published 1.53/1.57 reproduce exactly. Two estimators are kept
    and never conflated (D15): `well_efficiency_spline` (qpcR-faithful) and `well_efficiency`
    (a robust, baseline-subtracted LinRegPCR screen).
  - `run_ancova_efficiency` — ANCOVA on efficiency-weighted CT (robustness variant).
  - `pfaffl_compare` — Pfaffl / 2^-ΔΔCt efficiency-corrected cross-check (D7).
- **`pysaysuite.qpcr.plot`** / **`pysaysuite.qpcr.report`** — figures (forest, efficiency,
  reference stability, diagnostics, covariate, Pfaffl) and the methods-stamp / output writers (D10).
- **`pysaysuite.Config`** — typed analysis config, loadable from TOML.
- **`pysaysuite.core`** — intentionally **empty** for now; a shared cross-assay layer is
  premature with only the qPCR module present (each assay's input differs), and is deferred
  until a second assay lands (D12).

The headline functions are also re-exported at the top level:
`from pysaysuite import read_plates, build_wide, run_ancova, genorm2, estimate_eff, ...`.

### Quickstart

```python
import pysaysuite as ps

# 1. Ingest QuantStudio exports (one entry per plate) and assign groups.
long = ps.read_plates({"Plate1": "plate1.xls", "Plate2": "plate2.xls"})
long = ps.assign_group(long, {"N": "Control", "T": "Case"})   # by sample-name prefix

# 2. Reference-gene QC and selection.
wide = ps.build_wide(long)
stability = ps.genorm2(wide, ["RNU48", "U6", "GAPDH"])         # geNorm M ranking

# 3. Headline differential expression (ANCOVA on raw CT, geometric-mean reference).
result = ps.run_ancova(wide, targets=["MIR-21", "MIR-331"], refs=["RNU48", "U6"])
groups = result[result["is_group_effect"]]                    # one row per target
print(groups[["target", "estimate", "p_value", "p_fdr", "direction"]])

# 4. (Optional) efficiency screen + Pfaffl cross-check.
amp  = ps.read_plates({"Plate1": "plate1.xls"}, kind="amplification")
eff  = ps.estimate_eff(amp, design=long[["well"]].drop_duplicates())
xchk = ps.pfaffl_compare(wide, ["MIR-21"], ["RNU48", "U6"], eff, result)
```

`run_ancova` returns a tidy table with columns `target, term, estimate, se, t, p_value,
is_group_effect, p_fdr, direction, n, n_params, obs_per_param, r2_adj`; the analysis
parameters for the methods stamp live in `result.attrs["params"]`.

### Reproduce the paper, 1:1

`docs/qpcr_examples/qpcr_paper_replication_pysaysuite.ipynb` runs the **package** end-to-end on
Hampton et al.'s own data (`docs/qpcr_examples/data/`) and asserts, in-notebook, that every
result matches the published values: Tables 3 & 4 (ANCOVA), the geNorm conclusion, the
GAPDH–MMP10 correlation, and the GAPDH/MMP10 amplification efficiencies. Execute it with:

```bash
conda run -n pysaysuite jupyter nbconvert --to notebook --execute --inplace \
  docs/testfiles/qpcr_paper_replication_pysaysuite.ipynb
```

## Install (for development)

The package is developed in its own conda environment:

```bash
conda create -n pysaysuite python=3.12 -y
conda activate pysaysuite
pip install -e ".[dev]"
```