Metadata-Version: 2.4
Name: sphere-pca
Version: 0.3.0
Summary: Interpretable spherical coordinates for single-cell state transitions from principal components.
Author-email: Long Yuan <lyuan13@jhmi.edu>
License-Expression: MIT
Project-URL: Homepage, https://github.com/imlong4real/SPHERE-PCA
Project-URL: Repository, https://github.com/imlong4real/SPHERE-PCA
Project-URL: Issues, https://github.com/imlong4real/SPHERE-PCA/issues
Project-URL: Preprint, https://doi.org/10.64898/2026.09.11.751061
Keywords: single-cell,principal-component-analysis,spherical-geometry,trajectory-analysis
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23.5
Requires-Dist: scikit-learn>=1.2
Provides-Extra: plot
Requires-Dist: matplotlib>=3.6; extra == "plot"
Provides-Extra: singlecell
Requires-Dist: anndata>=0.9; extra == "singlecell"
Provides-Extra: legacy
Requires-Dist: matplotlib>=3.6; extra == "legacy"
Requires-Dist: pandas>=1.5; extra == "legacy"
Requires-Dist: plotly>=5.15; extra == "legacy"
Requires-Dist: scipy>=1.9; extra == "legacy"
Requires-Dist: seaborn>=0.12; extra == "legacy"
Requires-Dist: statsmodels>=0.14; extra == "legacy"
Provides-Extra: app
Requires-Dist: matplotlib>=3.6; extra == "app"
Requires-Dist: pandas>=1.5; extra == "app"
Requires-Dist: plotly>=5.15; extra == "app"
Requires-Dist: pyyaml>=6; extra == "app"
Requires-Dist: scipy>=1.9; extra == "app"
Requires-Dist: seaborn>=0.12; extra == "app"
Requires-Dist: statsmodels>=0.14; extra == "app"
Requires-Dist: streamlit>=1.30; extra == "app"
Provides-Extra: manuscript
Requires-Dist: anndata>=0.9; extra == "manuscript"
Requires-Dist: gseapy>=1.1; extra == "manuscript"
Requires-Dist: h5py>=3.8; extra == "manuscript"
Requires-Dist: matplotlib>=3.6; extra == "manuscript"
Requires-Dist: pandas>=1.5; extra == "manuscript"
Requires-Dist: plotly>=5.15; extra == "manuscript"
Requires-Dist: pyyaml>=6; extra == "manuscript"
Requires-Dist: rdata>=0.9; extra == "manuscript"
Requires-Dist: scanpy>=1.10; extra == "manuscript"
Requires-Dist: scipy>=1.9; extra == "manuscript"
Requires-Dist: seaborn>=0.12; extra == "manuscript"
Requires-Dist: statsmodels>=0.14; extra == "manuscript"
Requires-Dist: streamlit>=1.30; extra == "manuscript"
Provides-Extra: dev
Requires-Dist: anndata>=0.9; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: matplotlib>=3.6; extra == "dev"
Requires-Dist: pandas>=1.5; extra == "dev"
Requires-Dist: plotly>=5.15; extra == "dev"
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pyyaml>=6; extra == "dev"
Requires-Dist: scipy>=1.9; extra == "dev"
Requires-Dist: seaborn>=0.12; extra == "dev"
Requires-Dist: statsmodels>=0.14; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

<div align="center">
  <img src="assets/images/SPHERE-PCA_logo.png" alt="SPHERE-PCA logo" width="190">
  <h1>SPHERE-PCA</h1>
  <p><strong>Interpretable spherical coordinates for single-cell state transitions from principal components.</strong></p>

  <p>
    <a href="https://doi.org/10.64898/2026.09.11.751061"><img src="https://img.shields.io/badge/bioRxiv-10.64898%2F2026.09.11.751061-B31B1B" alt="bioRxiv DOI"></a>
    <a href="https://github.com/imlong4real/SPHERE-PCA/actions/workflows/tests.yml"><img src="https://github.com/imlong4real/SPHERE-PCA/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
    <a href="https://github.com/imlong4real/SPHERE-PCA/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license"></a>
    <img src="https://img.shields.io/badge/python-%E2%89%A53.9-3776AB" alt="Python 3.9 or newer">
    <a href="https://academic.oup.com/jimmunol/article/214/Supplement_1/vkaf283.978/8332132"><img src="https://img.shields.io/badge/AAI%202025-Oral-6A5ACD" alt="AAI 2025 Oral"></a>
  </p>
</div>

## What is SPHERE-PCA?

SPHERE-PCA L2-normalizes PC1-PC3 onto the unit sphere, rotates a biologically
defined root population to the north pole, and returns three transparent
coordinates for every cell. It is deterministic, preserves the original PCA
loadings, and can start from either existing PC coordinates or a normalized
cell-by-gene matrix.

SPHERE-PCA is a geometric description—not automatic evidence of a causal
trajectory, developmental direction, or experimental perturbation response.
Root choice and coordinate interpretations should be validated independently.

## Installation

Install the current source release:

```bash
python -m pip install "sphere-pca[plot] @ git+https://github.com/imlong4real/SPHERE-PCA.git"
```

For local development or manuscript reproduction:

```bash
git clone https://github.com/imlong4real/SPHERE-PCA.git
cd SPHERE-PCA
python -m pip install -e ".[dev]"
```

Optional extras are `plot`, `singlecell`, `app`, `manuscript`, and `dev`. The
core install contains only NumPy and scikit-learn. The preserved historical
namespace is available through the `legacy` extra; the dashboard uses `app`:

```bash
python -m pip install "sphere-pca[app] @ git+https://github.com/imlong4real/SPHERE-PCA.git"
sphere-trace
```

The installed dashboard includes a small synthetic example and accepts CSV
uploads. Large manuscript datasets are not included in the distribution.

## Quick start

Transform existing PC1-PC3 coordinates:

```python
import sphere_pca

result = sphere_pca.transform(pcs, root_mask=is_stem_cell)

# Or reuse an explicitly recorded centroid in PC1-PC3 coordinates:
result = sphere_pca.transform(pcs, root_centroid=published_centroid)

result.theta
result.phi
result.r
sphere_pca.plot(result, color=cell_type)
```

Use an `AnnData` object with `adata.obsm["X_pca"]` (or pass `use_rep=None` to
fit PCA from `adata.X`):

```python
result = sphere_pca.fit(
    adata,
    root="stem_cell",
    root_key="cell_type",
    write_back=True,
)
```

This writes `sphere_pca_theta`, `sphere_pca_phi`, and `sphere_pca_r` to
`adata.obs` and aligned unit vectors to `adata.obsm["X_sphere_pca"]`.
`fit()` does not normalize counts, log-transform, select highly variable
genes, or scale features. Supply an existing PCA representation for exact
workflow control, or perform the required preprocessing before fitting PCA.

## What the coordinates mean

| Coordinate | Meaning |
|---|---|
| **θ** | Root-aligned geodesic progression: angular distance from the chosen root direction. |
| **φ** | Angular state or branch position around the root-aligned sphere. |
| **r** | Pre-projection radial magnitude in PC1-PC3 space; it is retained, not normalized away. |

Angles are returned in radians. A structured coordinate can be biologically
useful without being causal; compare it with sampling time, lineage labels,
known markers, perturbations, or other independent evidence.

## Tutorials / examples

Two download-free tutorials live in [`examples/`](examples/README.md):

- [`existing_pca.py`](examples/existing_pca.py) — transform and visualize a
  tiny synthetic PC1-PC3 matrix.
- [`anndata_workflow.py`](examples/anndata_workflow.py) — fit from AnnData,
  define a root population, and write coordinates back to `adata.obs`.

## Reproducing the paper

The published analysis namespace remains available as
`pca_sphere_projection`; its numerical implementation has not been replaced by
the new public wrapper. The public API uses a proper orthogonal Rodrigues
rotation, while the frozen Figure 1 pathway retains its original implementation
for reproduction and can therefore produce different numerical coordinates.
Manuscript entry points and expected inputs are documented in
[`scripts/manuscript/`](scripts/manuscript/README.md).

```bash
python -m pip install -r requirements-manuscript.txt
python scripts/manuscript/make_manuscript_figures.py --figure 1
```

Large source datasets and generated outputs are intentionally excluded from
the Python distribution. Follow the preprint's data-access instructions and
place inputs under `raw_data/` before running the figure workflows.

## Citation

If you use SPHERE-PCA, please cite:

> Yuan L, Li X, Le M, Hicks SC, Deshpande A, Taube JM, Szalay AS.
> *Interpretable spherical geometry of single-cell state transitions from dominant principal components.*
> bioRxiv (2026). <https://doi.org/10.64898/2026.09.11.751061>

Machine-readable metadata is available in [`CITATION.cff`](CITATION.cff).

## License

SPHERE-PCA is released under the [MIT License](LICENSE).
