Metadata-Version: 2.4
Name: scfair
Version: 0.7.0
Summary: HVG selection for scRNA-seq: auto list size (n) plus fairer allocation for small populations
Author-email: "Zhao Li (李钊)" <leelieber@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/leelieber2025/scFair
Project-URL: Documentation, https://scfair.readthedocs.io
Project-URL: Changelog, https://scfair.readthedocs.io/en/latest/changelog.html
Project-URL: Source, https://github.com/leelieber2025/scFair
Project-URL: Issues, https://github.com/leelieber2025/scFair/issues
Keywords: single-cell,RNA-seq,HVG,highly-variable-genes,fairness,bioinformatics
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
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.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: anndata>=0.10
Requires-Dist: numpy>=1.24
Requires-Dist: pandas>=2.0
Requires-Dist: scanpy>=1.10
Requires-Dist: scipy>=1.10
Requires-Dist: scikit-learn>=1.2
Requires-Dist: igraph>=0.10
Requires-Dist: scikit-misc>=0.3
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: ruff<0.17,>=0.4.0; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx>=7.0; extra == "docs"
Requires-Dist: sphinx-book-theme>=1.1; extra == "docs"
Requires-Dist: myst-nb>=1.0; extra == "docs"
Requires-Dist: sphinx-copybutton>=0.5; extra == "docs"
Requires-Dist: sphinx-design>=0.5; extra == "docs"
Dynamic: license-file

# scFair

[![PyPI version](https://img.shields.io/pypi/v/scfair.svg)](https://pypi.org/project/scfair/)
[![Python versions](https://img.shields.io/pypi/pyversions/scfair.svg)](https://pypi.org/project/scfair/)
[![Documentation Status](https://readthedocs.org/projects/scfair/badge/?version=latest)](https://scfair.readthedocs.io/en/latest/?badge=latest)
[![CI](https://github.com/leelieber2025/scFair/actions/workflows/tests.yml/badge.svg)](https://github.com/leelieber2025/scFair/actions/workflows/tests.yml)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)

**scFair** is drop-in HVG selection for single-cell RNA-seq that targets two
everyday pain points:

| Problem | What goes wrong | What scFair does |
|---------|-----------------|------------------|
| **How many genes (`n`)?** | Users guess 2000 (or copy a paper). Too short can erase structure; too long adds noise. | **`n_top_genes="auto"`** (default) suggests a base size from the data. It is **not** proven optimal for every dataset — it is a **safe default and a prompt** so unfamiliar users are less likely to ship a silent bad `n`. Override with `n_top_genes=2000` anytime. |
| **Unfair HVG allocation** | Global ranking is driven by large populations. Markers for smaller types often sit just below the cutoff. | Keeps that global ranking as the backbone and, by default, **`append`s** a small extension from the same ranking so near-miss genes are not discarded. The base top-`k` is never displaced. |

Docs: [Read the Docs](https://scfair.readthedocs.io/en/latest/).

## What you need

- Python 3.10+ (tested 3.10–3.12)
- An AnnData object with raw integer counts in `.X` or `layers["counts"]`

## Install

```bash
pip install scfair
```

## First run

```python
import scanpy as sc
import scfair as scf

# raw integer counts in .X or layers["counts"]
scf.pp.highly_variable_genes(adata)
# annotates adata.var["highly_variable"]; keep the full gene matrix
# (scanpy PCA uses that mask by default — no manual subset step)

sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
sc.pp.scale(adata, max_value=10)
sc.tl.pca(adata)
sc.pp.neighbors(adata)
sc.tl.leiden(adata)
```

That is the default path: pick a base size from the data (`n_top_genes="auto"`),
then append a few more genes from the same ranking. Auto is slower than a fixed
`k` (extra multi-seed graph builds). Read `adata.uns["scfair"]["hvg"]["auto_message"]`
for a one-line plain summary of the chosen base size. For a classical fixed list
or a paper protocol:

```python
scf.pp.highly_variable_genes(adata, n_top_genes=2000)
```

To match scanpy with no extension:

```python
scf.pp.highly_variable_genes(adata, n_top_genes=2000, balance_method="none")
```

## Status

**0.7.0 (Beta).** Import as `import scfair as scf` and use names in
`scfair.__all__` and `scf.pp`. See the
[API reference](https://scfair.readthedocs.io/en/latest/api/index.html).

## Next steps

1. [Installation](https://scfair.readthedocs.io/en/latest/installation.html)
2. [Quickstart](https://scfair.readthedocs.io/en/latest/quickstart.html)
3. [Tutorial: PBMC 10k misclustered cells vs standard HVG](https://scfair.readthedocs.io/en/latest/tutorials/index.html)
4. [FAQ](https://scfair.readthedocs.io/en/latest/faq.html) if something looks off

## License

Software: [Apache License 2.0](LICENSE).

## Author

**Zhao Li (李钊)**  
Email: [leelieber@gmail.com](mailto:leelieber@gmail.com)
