Metadata-Version: 2.4
Name: scbiot
Version: 1.2.0
Summary: Single-cell multi-omics integration and spatiotemporal dynamics via optimal transport
Project-URL: Homepage, https://github.com/haihuilab/scbiot
Project-URL: Documentation, https://scbiot.readthedocs.io/en/latest/
Project-URL: Bug Tracker, https://github.com/haihuilab/scbiot/issues
Project-URL: Changelog, https://github.com/haihuilab/scbiot/blob/main/CHANGES.md
Author-email: Haihui Zhang <hanfei19@gmail.com>
License: BSD 3-Clause License
        
        Copyright (c) 2026, Haihui Zhang
        
        Redistribution and use in source and binary forms, with or without
        modification, are permitted provided that the following conditions are met:
        
        1. Redistributions of source code must retain the above copyright notice, this
           list of conditions and the following disclaimer.
        
        2. Redistributions in binary form must reproduce the above copyright notice,
           this list of conditions and the following disclaimer in the documentation
           and/or other materials provided with the distribution.
        
        3. Neither the name of the copyright holder nor the names of its
           contributors may be used to endorse or promote products derived from
           this software without specific prior written permission.
        
        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
        AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
        FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
        CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
        OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License-File: LICENSE
Keywords: atac,bioinformatics,omics,optimal transport,rna,single-cell,spatiotemporal
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: <3.13,>=3.12
Requires-Dist: anndata>=0.10
Requires-Dist: matplotlib>=3.8
Requires-Dist: numpy<2.2,>=2
Requires-Dist: pandas<3,>=1.5
Requires-Dist: pot>=0.9.6.post1
Requires-Dist: pyranges>=0.1.4
Requires-Dist: scanpy>=1.11.4
Requires-Dist: scikit-learn>=1.2
Requires-Dist: scikit-misc>=0.5.2
Requires-Dist: scipy<1.17,>=1.12
Requires-Dist: seaborn>=0.13
Requires-Dist: statsmodels>=0.14
Requires-Dist: torch>=2.5.0
Requires-Dist: wrapt<2,>=1.10.10
Provides-Extra: analysis
Requires-Dist: category-encoders==2.8.1; extra == 'analysis'
Requires-Dist: scib-metrics==0.5.1; extra == 'analysis'
Requires-Dist: scib==1.1.7; extra == 'analysis'
Requires-Dist: wandb==0.21.1; extra == 'analysis'
Provides-Extra: cpu
Requires-Dist: faiss-cpu<2,>=1.12; extra == 'cpu'
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: myst-nb>=1.3; extra == 'docs'
Requires-Dist: myst-parser>=5.0; extra == 'docs'
Requires-Dist: sphinx-rtd-theme>=3.1; extra == 'docs'
Requires-Dist: sphinx<10,>=9.1; extra == 'docs'
Provides-Extra: full
Requires-Dist: category-encoders==2.8.1; extra == 'full'
Requires-Dist: faiss-gpu-cu12==1.14.1.post1; (platform_system == 'Linux') and extra == 'full'
Requires-Dist: ipykernel>=7.1.0; extra == 'full'
Requires-Dist: scib-metrics==0.5.1; extra == 'full'
Requires-Dist: scib==1.1.7; extra == 'full'
Requires-Dist: wandb==0.21.1; extra == 'full'
Provides-Extra: gpu
Requires-Dist: faiss-gpu-cu12==1.14.1.post1; (platform_system == 'Linux') and extra == 'gpu'
Provides-Extra: notebooks
Requires-Dist: ipykernel>=7.1.0; extra == 'notebooks'
Description-Content-Type: text/markdown

# scBIOT

**scBIOT** is a Python library for optimal-transport integration and analysis of
single-cell RNA, ATAC, spatial, and paired or unpaired multi-omics data. Version
1.2.0 provides a compact parameter interface, scalable centroid integration,
linear-autoencoder embeddings, label transfer, and transport-aware downstream
analysis for AnnData objects.

## Highlights

- **Batteries-included preprocessing**: scATAC-seq peak processing, iterative LSI, and gene activity annotation.
- **Accurate atlas integration**: high-fidelity alignment with rare cell-type protection.
- **Unified scBIOT framework**: one interface for RNA, ATAC, spatial, temporal, and multi-omics integration.
- **Fast integration via Optimal Transport (OT)**: scalable alignment for large single-cell datasets.
- **Linear autoencoders**: PCA-like single-dataset embeddings and reference-to-query coembedding.
- **Scales to 100M cells locally**: memory-efficient processing with centroid-level OT.
- **Label transfer**: across multi-omics modalities and between spatial data and scRNA-seq references.
- **Transport-aware analysis**: gene transport scores, trajectory diagnostics, and plotting utilities.
- **Spatiotemporal dynamics**: spatial/time-aware integration and lineage-specific velocity fields.

## Installation

```bash
pip install scbiot
```

The default installation contains the AE and optimal-transport pipeline without
benchmarking frameworks, Jupyter, or FAISS. Add only the features you need:

```bash
# Jupyter kernel for the tutorial notebooks
pip install "scbiot[notebooks]"

# FAISS acceleration: choose one backend
pip install "scbiot[cpu]"
pip install "scbiot[gpu]"       # Linux with CUDA 12

# scIB benchmarking utilities
pip install "scbiot[analysis]"

# Analysis, GPU FAISS, and notebooks together
pip install "scbiot[full]"

# Documentation toolchain
pip install "scbiot[docs]"
```

Do not install the `cpu` and `gpu` FAISS extras together. Without either extra,
scBIOT uses its scikit-learn fallback where available; centroid interpolation
requires a FAISS backend. See the
[installation guide](https://scbiot.readthedocs.io/en/stable/installation.html)
for details.

## Data availability

Prepared tutorial inputs are archived in the
[scBIOT Figshare collection](https://figshare.com/articles/dataset/Anndata_for_scBIOT_analysis/30671669).
Inputs not present there are linked to their original providers in the
[data-source documentation](https://scbiot.readthedocs.io/en/stable/data_source.html).

## Quick start

- Detailed documentation is published on [Read the Docs](https://scbiot.readthedocs.io/en/stable/).
- The [`tutorials/`](tutorials/) directory contains runnable end-to-end notebooks.

The example below deterministically holds out batch `B4` as an unlabeled query
and retains the original `cell_type` column for evaluation:

```python
import scanpy as sc
import scbiot as scb

adata = sc.read(
    "lung_atlas.h5ad",
    backup_url="https://figshare.com/ndownloader/files/24539942",
)

LABEL_KEY = "semi_cell_type"
UNLABELED = "Unknown"
QUERY_BATCH = "B4"
RANDOM_STATE = 0

# The downloaded AnnData contains batch, cell_type, and a counts layer.
required_obs = {"batch", "cell_type"}
missing_obs = required_obs.difference(adata.obs.columns)
if missing_obs:
    raise KeyError(f"Missing required obs columns: {sorted(missing_obs)}")
if "counts" not in adata.layers:
    raise KeyError("Missing required adata.layers['counts']")

# Build the semi-supervised label column used by both AE and supBIOT.
batch = adata.obs["batch"].astype("string")
query_mask = batch.eq(QUERY_BATCH).fillna(False)
if not query_mask.any() or query_mask.all():
    raise ValueError(f"QUERY_BATCH={QUERY_BATCH!r} does not define a valid query")
adata.obs[LABEL_KEY] = adata.obs["cell_type"].astype("string")
adata.obs.loc[query_mask, LABEL_KEY] = UNLABELED

# 1. Learn the v1.2 linear-autoencoder representation.
adata = scb.pp.autoencoder(
    adata,
    input_key="counts",
    out_key="X_ae",
    batch_key="batch",
    random_state=RANDOM_STATE,
)

# 2. Align batches in the autoencoder representation with optimal transport.
adata, metrics = scb.ot.integrate(
    adata,
    obsm_key="X_ae",
    batch_key="batch",
    out_key="X_supbiot",
    label_key=LABEL_KEY,
    unlabeled_category=UNLABELED,
    random_state=RANDOM_STATE,
)
print(metrics)

# 3. Transfer reference labels to the unlabeled query cells.
adata = scb.ot.supbiot(
    adata,
    use_rep="X_supbiot",
    input_rep_key="X_ae",
    label_key=LABEL_KEY,
    unlabeled_category=UNLABELED,
    pred_label_key="pred_cell_type",
    pred_conf_key="pred_confidence",
    min_conf=0.0,
    random_state=RANDOM_STATE,
)

sc.pp.neighbors(adata, use_rep="X_supbiot")
sc.tl.umap(adata, random_state=RANDOM_STATE)

# Combine known reference labels and transferred query labels for visualization.
adata.obs["supbiot_cell_type"] = adata.obs[LABEL_KEY].astype("string")
adata.obs.loc[query_mask, "supbiot_cell_type"] = adata.obs.loc[
    query_mask, "pred_cell_type"
].astype("string")
sc.pl.umap(adata, color=["batch", "supbiot_cell_type", "pred_confidence"])
```



### Scaling options

Replace step 2 above with one of the following calls, then continue with step 3.
For a faster approximate OT run on large datasets, enable the approximate solver:

```python
adata, metrics = scb.ot.integrate(
    adata,
    obsm_key="X_ae",
    batch_key="batch",
    out_key="X_supbiot",
    label_key=LABEL_KEY,
    unlabeled_category=UNLABELED,
    approximate=True,
    random_state=RANDOM_STATE,
)
```

For ultra-large datasets, use centroid-level OT:

```python
adata, metrics = scb.ot.integrate(
    adata,
    obsm_key="X_ae",
    batch_key="batch",
    out_key="X_supbiot",
    label_key=LABEL_KEY,
    unlabeled_category=UNLABELED,
    centroid=True,
    random_state=RANDOM_STATE,
)
```

For cross-modality reference mapping in v1.2.0, use
`scb.pp.autoencoder_map(reference, query, out_key="X_ae")`, then integrate
`X_ae` and transfer labels with `scb.ot.supbiot`.

See the dedicated documentation for
[multi-omics](https://scbiot.readthedocs.io/en/stable/multiomics.html) and
[spatiotemporal dynamics](https://scbiot.readthedocs.io/en/stable/spatiotemporal.html).
