Skip to main content

scFair

PyPI version Python versions Documentation Status CI License

scFair is drop-in HVG selection for single-cell RNA-seq aimed at two problems every pipeline hits — plus an optional density population count:

Problem What goes wrong What scFair does
How many genes (n)? Nobody knows a priori what length is safe. Copying 2000 is a silent gamble. n_top_genes="auto" (default) estimates a base size from density structure. That multi-seed cost is intentional: avoiding a wrong n is worth the compute. Pass a fixed int only when the protocol is already locked.
Unfair HVG allocation at the cutoff Global ranking is driven by large populations. Markers for smaller types often sit just below a hard top-k cut and are discarded — not because they are uninformative, but because bulk variation fills the list first. Default append freezes the global top-k backbone and adds a short same-rank tail (append_budget) so near-miss genes are not thrown away. The set equals top-(k+m). This is a conservative response to cutoff unfairness, not cluster-conditional reallocation (those methods were removed). Use balance_method="none" for pure top-k.

Optional: estimate_n_populations reads a 3D density field after sc.pp.neighbors (how many populations, without sweeping Leiden resolution; works best up to ~20 well-separated populations).

Docs: Read the Docs.

What you need

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

Install

pip install scfair

First run

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, flavor="igraph", n_iterations=2, directed=False)

Default path: structure auto-n + same-rank append (cutoff buffer). Auto runs extra multi-seed graph builds and is slower than a fixed k — that is by design. A silent wrong list length is more expensive than the compute. Read adata.uns["scfair"]["hvg"]["auto_message"] for a one-line summary of the chosen base size. Use a fixed int only for a locked paper/protocol:

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

Pure top-k (no buffer):

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

Population count without resolution sweep (after neighbors):

sc.pp.neighbors(adata)
est = scf.pp.estimate_n_populations(adata)
print(est.n_populations, est.confidence)

Status

0.8.0 (Beta). Import as import scfair as scf and use names in scfair.__all__ and scf.pp. See the API reference.

Next steps

  1. Installation
  2. Quickstart
  3. Tutorial: PBMC 10k misclustered cells vs standard HVG
  4. FAQ if something looks off

License

Software: Apache License 2.0.

Author

Zhao Li (李钊)
Email: leelieber@gmail.com

Metadata

Release files for scfair 0.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for scfair 0.8.0
File Size Uploaded
scfair-0.8.0.tar.gz 1.7 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for scfair 0.8.0
File Interpreter ABI Platform
scfair-0.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.8 MB

Release files / scfair-0.8.0.tar.gz

Download URL scfair-0.8.0.tar.gz
Size 1.7 MB
Tags Source
SHA-256 checksum
How to use checksums
85cd6f9d2ae139dc08a5c31be54e2634afc839ea6f813a27080fede9ac2f02e1
BLAKE2b-256 checksum
How to use checksums
90e8113c600e6634672d9973dc97746aa80960192fa8d1b135d31455a36c475b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release files / scfair-0.8.0-py3-none-any.whl

Download URL scfair-0.8.0-py3-none-any.whl
Size 79.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dba0b84179a139fc3ab0e0bc9a370e94489eb08a07ad2ac4fc702e8ebc194dac
BLAKE2b-256 checksum
How to use checksums
fb99eb46c4b8a75e03196090851ef8870c24de97abbed119fa716884a5f6a673
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 8, 2026.

Transparency log

Release history Release notifications | RSS feed

0.10.2

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.9.0

2 release files

This release

0.8.0 This release

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page