Source code for pyglmGamPoi.trackcell_compat
"""
Trackcell-compatible offset model fitting API.
Primary integration surface — see ``docs/INTEGRATION.md``.
"""
from __future__ import annotations
from typing import Union
import numpy as np
import pandas as pd
from scipy import sparse
from pyglmGamPoi.constants import METHOD_GLMGAMPOI_OFFSET
from pyglmGamPoi.fitting import fit_glmGamPoi_offset_matrix as _fit_matrix
from pyglmGamPoi.validate import (
assert_model_pars_contract,
format_model_pars,
normalize_model_pars_columns,
validate_genes_by_cells_matrix,
validate_gene_index,
validate_regressor_data,
)
[docs]
def is_available() -> bool:
"""Return True when the native C++ extension is importable."""
try:
from pyglmGamPoi import _core as _c # noqa: F401
return True
except ImportError:
return False
[docs]
def fit_offset_model(
umi: Union[np.ndarray, sparse.spmatrix],
regressor_data: pd.DataFrame,
gene_index: pd.Index,
*,
method: str = METHOD_GLMGAMPOI_OFFSET,
allow_inf_theta: bool = True,
apply_shrinkage: bool = True,
) -> pd.DataFrame:
"""
Fit glmGamPoi offset models (sctransform ``fit_glmGamPoi_offset``).
Parameters
----------
umi
UMI count matrix, **genes × cells** (CSR sparse or dense).
regressor_data
Cell-level covariates, one row per cell. Must contain ``log_umi`` in
**log10** scale, indexed by cell barcodes in the same order as umi columns.
gene_index
Gene identifiers, length ``umi.shape[0]``.
method
Must be ``"glmGamPoi_offset"``.
allow_inf_theta
When False, cap theta at ``mean(mu)/1e-4`` (Seurat default).
apply_shrinkage
When True (default), apply ``loc_median_fit`` dispersion trend and refit
intercepts (R ``glm_gp(overdispersion_shrinkage=TRUE)``).
Returns
-------
DataFrame with columns ``theta``, ``Intercept``, ``log_umi``.
"""
if method != METHOD_GLMGAMPOI_OFFSET:
raise ValueError(
f"Unsupported method '{method}'. pyglmGamPoi only implements "
f"'{METHOD_GLMGAMPOI_OFFSET}'."
)
umi_csr, n_genes, n_cells = validate_genes_by_cells_matrix(umi)
gene_index = validate_gene_index(gene_index, n_genes)
validate_regressor_data(regressor_data, n_cells)
log10_umi = regressor_data["log_umi"].to_numpy(dtype=np.float64)
offset = np.log(np.power(10.0, log10_umi))
raw = _fit_matrix(
umi_csr,
offset,
allow_inf_theta=allow_inf_theta,
apply_shrinkage=apply_shrinkage,
n_cells=n_cells,
)
model_pars = format_model_pars(
np.asarray(raw["theta"], dtype=np.float64),
np.asarray(raw["intercept"], dtype=np.float64),
gene_index,
)
return assert_model_pars_contract(model_pars)
__all__ = [
"fit_offset_model",
"is_available",
"normalize_model_pars_columns",
"METHOD_GLMGAMPOI_OFFSET",
]