pysigscore
pysigscore is a Python framework for computing and comparing gene signature scores in bulk and single-cell transcriptomics data. It also evaluates score significance and signature robustness and provides plotting utilities for result comparison.
Features
- 18 built-in scores: 14 direct statistics, one Z-score, and three rank-based methods (AUCell, ssGSEA, and GSVA).
- Custom scorer: supply your own scoring function and compare it with the built-in methods.
- Flexible transformation pipelines: log, min-max scale, standardisation, KNN smoothing, step, and quantile normalisation — composable as ordered pipelines.
- Permutation and analytical p-values: assess significance of each computed score.
- Leave-one-out (LOO) robustness experiments: show robustness of each gene signature.
- Summary metrics and visualisation: histograms, boxplots, violin plots, heatmaps, cross-scorer comparisons, sample-set comparisons and statistical test plots.
- HDF5 serialisation: save and reload the object to restart the analysis.
Installation
From source (development)
git clone https://github.com/bioinformatics-hub/pysigscore.git
cd pysigscore
pip install -e ".[full, dev]"
Core dependencies
Installed automatically:
numpy>=1.23
scipy>=1.9
pandas>=1.5
anndata>=0.9
scikit-learn>=1.1
numba>=0.56
h5py>=3.7
matplotlib>=3.5
seaborn>=0.12
Optional dependencies
| Extra | Methods unlocked | Install command |
|---|---|---|
aucell |
AUCell | pip install -e ".[aucell]" |
gsea |
ssGSEA, GSVA | pip install -e ".[gsea]" |
full |
aucell + gsea |
pip install -e ".[full]" |
test |
pytests | pip install -e ".[test]" |
dev |
dev libraries + test |
pip install -e ".[dev]" |
Version details in pyproject.toml
Quick Start
import anndata as ad
from pysigscore import Scorer, configure_logging
# Optional: show progress messages during computations
configure_logging()
# ── 1. Prepare data (cells × genes AnnData) ─────────────────────────────────
adata = ad.read_h5ad("your_data.h5ad") # rows = cells/samples, cols = genes
# ── 2. Initialise scorer ────────────────────────────────────────────────────
scorer = Scorer(
random_state=42,
name="MyProject", # output folder name
path=".", # parent directory
)
# ── 3. Import expression data ──────────────────────────────────────────────
scorer.import_adata(adata)
# or from a DataFrame:
# scorer.import_adata_as_dataframe(df, cluster=cluster_labels)
# ── 4. Import gene sets ────────────────────────────────────────────────────
geneset_dict = {
"Hallmarks_1": ["VEGFA", "GAPDH", "SLC2A1"],
"Hallmarks_2": ["MDM2", "CDKN1A", "BBC3"],
}
scorer.import_geneset_dict(geneset_dict, keys="genesets")
# ── 5. Compute enrichment scores ───────────────────────────────────────────
scorer.compute_scores(
transform_list_data=["raw", "log"], # score raw and log-transformed expression
transform_list_enrich=["raw"], # keep score matrices untransformed
enrich_grid={
"Mean": {"remove_na": True},
"Median": {"remove_na": True},
"Z": {"remove_na": True, "ddof": 0},
},
p_value_grid={ # 1,000 permutation p-values for Mean/Median;
"Mean": 1000, # analytical two-sided normal p-values for Z
"Median": 1000,
"Z": True,
},
loo_grid={"Median": ["log"]}, # LOO errors for Median on log-transformed data
geneset_list_loo_genewise=["Hallmarks_1"],
)
# CSV files are saved under MyProject/<ScoreName>/.
# ── 6. Return results of objects of interest ───────────────────────────────
# Return computed matrices
results = scorer.return_values(
value="score",
enrich=["Mean"],
data_trans=["raw"],
enrich_trans=["raw"],
geneset_list=["Hallmarks_1"],
samples_list=None, # use all samples
)
# ── 7. Compute Summary Metrics ──────────────────────────────────────────────
# Compute one mean Z score for Hallmarks_2 across all samples
metrics = scorer.return_metrics(
value="score",
metric="mean",
enrich=["Z"],
axis=0,
data_trans=["raw"],
enrich_trans=["raw"],
geneset_list=["Hallmarks_2"],
samples_list=None,
return_results=True,
)
# Saved as MyProject/Z/metrics/Z_score_mean.csv
API Overview
Scorer class
Scorer(random_state=42, name='Project01', path=None, dtype=None)
| Method | Description |
|---|---|
import_adata(adata, cluster_column_name=None) |
Load a samples × genes AnnData object; optional cluster labels |
import_adata_as_dataframe(df, cluster=None) |
Load a samples × genes DataFrame; optional cluster labels |
import_geneset_dict(geneset_info, keys='genesets', ...) |
Load gene sets from a dict |
import_geneset_matrix(geneset_info, ...) |
Load gene sets from a binary DataFrame or ndarray |
import_geneset_matrix_from_celloracle(base_GRN, ...) |
Load from a CellOracle base GRN DataFrame |
compute_scores(...) |
Compute selected scores for each requested transformation, with optional p-values and LOO errors |
return_values(value, enrich, data_trans, enrich_trans, ...) |
Return selected result matrices as {csv_stem: DataFrame} |
return_metrics(value, metric, ...) |
Save summary metric CSVs and optionally return them |
plot_values(value, method, ...) |
Save histogram, boxplot, violin or scatter plots |
plot_heatmap(value, ...) |
Save heatmaps of score, pvalue or LOO matrices |
plot_heatmap_loo_genewise(enrich, ...) |
Plot gene-wise LOO errors and optionally return the matrices |
plot_heatmap_corr(value, ...) |
Save geneset correlation heatmaps of scores, pvalues or LOO matrices |
plot_comparison_distribution(...) |
Compare score, p-value, or LOO distributions across scoring methods |
plot_cross_scorer_corr(...) |
Plot cross-scorer correlation for one gene set |
plot_distribution_sampleset(...) |
Compare one geneset across multiple sample groups |
stat_test_geneset_between_samples(...) |
Mann–Whitney U comparison between two sample groups |
stat_test_samples_between_genesets(...) |
Mann–Whitney U comparison between two genesets |
to_hdf5(file_path) |
Serialise the Scorer to HDF5 (.pysigscore.object) |
Use the module-level load_pysigscore(file_path) function to restore a saved Scorer object.
Supported Data Transformations
Data and post enrichment transformations are the following:
| Transformation | Description |
|---|---|
| raw | No transformation |
| log | Either ln(1+x) or log2(1+x) |
| scale | min-max scale |
| standard | Standard-deviation or MAD scaling, with optional centring |
| KNN | CellOracle KNN smoothing |
| quantile | Equalise data distributions across genes or samples |
| step | Apply step thresholding to the data |
Transformations can be composed as space-separated names, such as "log KNN standard" or "log scale"; "raw" must be used alone. The default parameters can be overridden with transform_hyper:
transform_hyper = {"log": {"type": "natural_log"},
"KNN": {"div_by_std": False, "max_n_components": 50,
"pca_curvature": 0.002, "k": None,
"metric": "euclidean", "diag": 1.0,
"n_pca_dims": None, "b_sight": None,
"b_maxl": None, "group_constraint": None,
"n_jobs": -1},
"scale": {"feature_range": (0,1),"axis_scale": 0},
"standard": {"subtract": False, "robust": False, "axis_standard": 0},
"step": {"y": (-1.0, 0.0, 1.0), "thr": None,
"method": "median", "axis_step": 0},
"quantile": {"kind": "mergesort", "axis_quantile": 0}}
Supported enrichment scores
| Score | Key | Description |
|---|---|---|
| Sum | 'Sum' |
Sum of all values in the signature |
| Weighted Sum | 'WeightedSum' |
Sum with gene-specific weights |
| Mean | 'Mean' |
Arithmetic average of values in the signature |
| Weighted Mean | 'WeightedMean' |
Mean after applying gene-specific weights |
| Median | 'Median' |
Median of all values in the signature |
| Trimmed Mean | 'TrimmedMean' |
Mean after removing extreme values of signature genes |
| Mode | 'Mode' |
Most frequent value in the signature |
| Mid-Range | 'MidRange' |
Average of min and max values in the signature |
| Mid-Hinge | 'MidHinge' |
Average of first and third quartiles in the signature |
| Tukey Trimean | 'TriMean' |
Weighted average of median and quartiles in the signature |
| IQR | 'IQR' |
Interquartile range (Q3 − Q1) of values in the signature |
| IQM | 'IQM' |
Mean of values within the IQR in the signature |
| MAD | 'MAD' |
Median absolute deviation of signature genes |
| AAD | 'AAD' |
Average absolute deviation of signature genes |
| Z-score | 'Z' |
Signature mean relative to the sample-wide mean and standard deviation |
| AUCell | 'Aucell' |
AUC-based gene set activity score |
| ssGSEA | 'ssGSEA' |
Single-sample GSEA enrichment score |
| GSVA | 'GSVA' |
Non-parametric gene set variation score |
| Custom | 'Custom' |
User-defined scoring function |
Pass only the methods to run in enrich_grid; omitted parameters use the defaults shown below.
enrich_grid = {
"Sum": {"remove_na": True},
"WeightedSum": {"remove_na": True},
"Mean": {"remove_na": True},
"WeightedMean":{"remove_na": True},
"Median": {"remove_na": True},
"TrimmedMean": {"remove_na": True, "quantile": 0.05},
"Mode": {"remove_na": True},
"MidRange": {"remove_na": True},
"MidHinge": {"remove_na": True},
"TriMean": {"remove_na": True},
"IQR": {"remove_na": True},
"IQM": {"remove_na": True},
"MAD": {"remove_na": True},
"AAD": {"remove_na": True},
"Z": {"remove_na": True, "ddof": 0},
"Aucell": {"auc_threshold": 0.05, "noweights": False},
"ssGSEA": {"sample_norm_method": "rank", "correl_norm_type": "rank",
"min_size": None, "max_size": None, "weight": 0,
"ascending": False, "NES": True, "p_val": "NOM p-val"},
"GSVA": {"min_size": None, "max_size": None, "weight": 0,
"kcdf": None, "mx_diff": True, "abs_rnk": False},
"Custom": {"custom_func": None, "custom_pval": None},
}
Custom scorer
A custom scorer receives arr_geneset, containing the signature-gene values for one sample, and arr_full, containing all gene values for that sample. It must return one numeric score.
def custom_score_example(arr_geneset, arr_full):
return float(arr_geneset.max() - arr_geneset.min())
scorer.compute_scores(
enrich_grid={"Custom": {"custom_func": custom_score_example}},
)
Summaries
return_metrics summarises saved score, p-value, or average LOO matrices using the mean, median, standard deviation, or coefficient of variation (cv). Use axis=0 to summarise each gene set across samples and axis=1 to summarise each sample across gene sets. Results are saved in <path>/<name>/<ScoreName>/metrics/; set return_results=True to also return them as {csv_stem: DataFrame}.
Plotting
Single-matrix visualisation
plot_values creates histograms, boxplots, violin plots, or scatter plots from one saved matrix. axis=0 plots each gene set across samples, axis=1 plots each sample across gene sets, and whole=True plots all entries together. plot_heatmap displays a selected matrix, while plot_heatmap_loo_genewise displays the error caused by removing each gene from a signature. PDFs are saved in <path>/<name>/<ScoreName>/plots/.
# Distribution of one gene set across samples
scorer.plot_values(
value="score",
method="boxplot",
enrich=["Median"],
data_trans=["log"],
enrich_trans=["raw"],
geneset_list=["Hallmarks_1"],
axis=0,
name="per_geneset",
)
# Full score matrix
scorer.plot_heatmap(
value="score",
enrich=["Mean"],
data_trans=["raw"],
enrich_trans=["raw"],
geneset_list=["Hallmarks_1", "Hallmarks_2"],
name="scores",
)
# Per-gene LOO errors computed in the Quick Start
scorer.plot_heatmap_loo_genewise(
enrich=["Median"],
data_trans=["log"],
geneset_list=["Hallmarks_1"],
name="loo",
)
Multiple-matrix comparisons
| Method | Purpose |
|---|---|
plot_comparison_distribution |
Compare one gene set's distribution across scoring methods |
plot_cross_scorer_corr |
Correlate scoring methods across samples for one gene set |
plot_distribution_sampleset |
Compare one gene set across user-defined sample groups |
stat_test_geneset_between_samples |
Test whether the first sample group has lower values than the second |
stat_test_samples_between_genesets |
Test whether the first gene set has lower values than the second |
The two statistical methods use a one-sided Mann–Whitney U test, so group or gene-set order matters. All comparison plots are saved in <path>/<name>/Comparisons/.
groups = {
# Replace these placeholders with sample IDs from scorer.samples.
"Control": ["Cell_1", "Cell_2"],
"Treatment": ["Cell_3", "Cell_4"],
}
scorer.plot_comparison_distribution(
value="score", method="boxplot",
enrich=["Mean", "Median", "Z"],
data_trans="raw", enrich_trans="raw",
geneset="Hallmarks_1", name="scorer_distribution",
)
scorer.plot_cross_scorer_corr(
value="score", enrich=["Mean", "Median", "Z"],
data_trans="raw", enrich_trans="raw",
geneset="Hallmarks_1", samples_list=None,
corr_method="spearman", name="scorer_corr",
)
scorer.plot_distribution_sampleset(
value="score", method="violinplot", enrich="Mean",
data_trans="raw", enrich_trans="raw",
geneset="Hallmarks_1", samples_dict=groups,
name="sample_groups",
)
scorer.stat_test_geneset_between_samples(
value="score", method="boxplot", enrich="Mean",
data_trans="raw", enrich_trans="raw",
geneset="Hallmarks_1", samples_dict=groups,
name="sample_test",
)
scorer.stat_test_samples_between_genesets(
value="score", method="boxplot", enrich="Mean",
data_trans="raw", enrich_trans="raw",
geneset_list=["Hallmarks_1", "Hallmarks_2"],
samples_list=None, name="geneset_test",
)
Output Structure
Each scorer stores its matrices, metrics, and plots under <path>/<name>/<ScoreName>/. Cross-scorer and sample-group comparisons are stored under <path>/<name>/Comparisons/. The examples above produce the following main files (... represents the compared labels inserted into statistical-test filenames):
MyProject/
Mean/
scores/
Mean_score_Data_raw_Enrich_raw.csv
Mean_score_Data_log_Enrich_raw.csv
pvalues/
Mean_pvalue_Data_raw_n_perm_1000.csv
Mean_pvalue_Data_log_n_perm_1000.csv
plots/
Heatmap_Mean_score_Data_raw_Enrich_raw_scores.pdf
Median/
scores/
Median_score_Data_raw_Enrich_raw.csv
Median_score_Data_log_Enrich_raw.csv
pvalues/
Median_pvalue_Data_raw_n_perm_1000.csv
Median_pvalue_Data_log_n_perm_1000.csv
loo_average/
Median_loo_Data_log_Metric_MAE.csv
loo_genewise/
Median_loo_genewise_Hallmarks_1_Data_log_Metric_MAE.csv
plots/
BoxPlot_Median_score_Data_log_Enrich_raw_Hallmarks_1_per_geneset.pdf
Heatmap_Median_loo_genewise_Hallmarks_1_Data_log_Metric_MAE_loo.pdf
Z/
scores/
Z_score_Data_raw_Enrich_raw.csv
Z_score_Data_log_Enrich_raw.csv
pvalues/
Z_pvalue_Data_raw.csv
Z_pvalue_Data_log.csv
metrics/
Z_score_mean.csv
Comparisons/
CompDist_score_Data_raw_Enrich_raw_Hallmarks_1_scorer_distribution.pdf
CrossScorerCorr_score_Data_raw_Enrich_raw_Hallmarks_1_scorer_corr.pdf
DistrSampleSet_Mean_score_Data_raw_Enrich_raw_Hallmarks_1_sample_groups.pdf
MW_SampleSet_Mean_score_Data_raw_Enrich_raw_..._sample_test.pdf
MW_Genesets_Mean_score_Data_raw_Enrich_raw_..._geneset_test.pdf
Score matrices, p-value matrices, and average LOO matrices have samples/cells as rows and gene sets as columns. Gene-wise LOO files have samples/cells as rows and genes from one selected gene set as columns.
Notes
- KNN smoothing requires enough cells to produce a meaningful neighbourhood graph.
- LOO experiments become more expensive as the number of samples and signature genes grows; rank-based methods can be especially slow.
Code Matters
Small parts of the code, explicitly cited, are inspired by these two libraries:
- https://github.com/morris-lab/CellOracle/tree/master/celloracle
- https://github.com/afrendeiro/page-enrichment
Claude Code Sonnet 4.6 was also used for code review and documentation. All AI-written code was manually reviewed and tested.
pysigQC-metrics
As an optional step, pysigQC can be used before scoring to assess how well each gene set is represented in the input expression data:
- https://github.com/Gennappio/pysigQC-metrics (smaller version)
- https://github.com/Gennappio/pysigQC (more extended version)
Citation
If you use pysigscore in your research, please cite:
@article{10.1093/bioadv/vbag021,
author = {Barberis, Alessandro and Buffa, Francesca M},
title = {Sigscores: summary scores for molecular signatures in R},
journal = {Bioinformatics Advances},
volume = {6},
number = {1},
pages = {vbag021},
year = {2026},
month = {01},
issn = {2635-0041},
doi = {10.1093/bioadv/vbag021},
url = {https://doi.org/10.1093/bioadv/vbag021},
}
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pysigscore-0.1.0.tar.gz.
File metadata
- Download URL: pysigscore-0.1.0.tar.gz
- Upload date:
- Size: 95.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4f39d67a511753dab32d0ccdeabf0083cf8fa675b3f54ee6ce690cda4733af6
|
|
| MD5 |
ba83ca4899cd677a72d641f6fafcbc4b
|
|
| BLAKE2b-256 |
14248f9398d8e0be470c74ba44fefb040a75c25fc4ca201b7e11d355a0047383
|
File details
Details for the file pysigscore-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pysigscore-0.1.0-py3-none-any.whl
- Upload date:
- Size: 63.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c2f4675e35143a0b9eb0516228fd475a1ff86d57c87c630977c1db2c032a20f
|
|
| MD5 |
bbd3df0527a538503c8f4782eff4fd27
|
|
| BLAKE2b-256 |
191ac4e3173da29c72644779339d2fd1f7d5470687ededc9e7ae5bd1f80dde3e
|