Repository navigation
Add activities of regulators and pathways, with CollecTRI and PROGENy - #59
Merged
Merged
Conversation
parashardhapola
force-pushed
the
49-combined-p-values-and-replication
branch
from
October 26, 2026 20:18
9383780 to
12ddeba
Compare
parashardhapola
changed the base branch from
49-combined-p-values-and-replication
to
master
October 26, 2026 20:21
ulm, mlm and weighted_aggregate score the activity of transcription factors and pathways from their targets as decoupler computes them, from a samples x genes array, a cube's cell type or the contrasts of a differential-expression result. collectri and progeny download the networks from their releases on first use, pinned by SHA-256, with their licences; CollecTRI's default level leaves out the interactions whose only source does not allow commercial use. plot_activities and plot_top_activities draw the heatmap and decoupler's bar plot. Checked against decoupler 2.2.0 and progeny 1.28.0 (validation/activity.py: 89 checks, none failed).
parashardhapola
marked this pull request as ready for review
October 26, 2026 20:22
parashardhapola
force-pushed
the
52-activity
branch
from
October 26, 2026 20:22
3f0cbb5 to
77b4959
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Which transcription factors and pathways are active, in each sample or in a contrast, is
the question decoupler answers for most single-cell users.
ulm,mlmandweighted_aggregatenow compute decoupler's activities from an expression matrix, acell type of a cube or the statistics of a differential-expression result, and return a
record that the linear models and the heatmap take as they take pathway scores. The
networks CollecTRI and PROGENy are downloaded from their releases on first use, pinned
by size and SHA-256, cached, and returned with their licence, source and citation;
CollecTRI comes by default at a licence level usable by a company. The results agree
with decoupler 2.2.0 and progeny 1.28.0 to rounding (89 checks, none failed).
Changes
cytepool.activity.ulm(data, network, *, gene_ids, sample_ids, group, contrast, min_cells, expression_filter, id_column, statistic_column, min_targets=5, n_threads): one linear model per source of the profile's genes on the source's weights; t-statistics, slopes, p-values.cytepool.activity.mlm(...)(same arguments, withoutn_threads): one model of all the sources with an intercept; refuses, by name, sources it cannot tell apart.cytepool.activity.weighted_aggregate(..., statistic="mean" | "sum", n_permutations=1000, rng=None): the weighted mean or sum of the targets' values, normalized by permutations of the genes, with permutation p-values.cytepool.activity.Activities: profiles x sourcesscores,estimates,p_values,adjusted_p_values(Benjamini-Hochberg over the sources of each profile),n_targets,profiles(aTablewithprofile_id),network,method,settings;sources;table().cytepool.networks.Network(edges, *, name, version, url, licence, citation, file, sha256): a read-only mapping of source to {target: weight}, from a table or DataFrame ofsource,target,weight(extra columns kept), a mapping of columns, or a mapping of source to targets (aGeneSetsincluded);edges,sources,select().cytepool.networks.collectri(*, licence="commercial", cache_dir=None)andprogeny(*, organism="human", top=None, max_p_value=0.05, cache_dir=None).cytepool.plotting.plot_activities(activities, *, sources, top=25, color_by, standardize, ax), a heatmap drawn by the pathway scores' heatmap, andplot_top_activities(activities, profile, *, top=25, ax), decoupler'spl.barplot.cytepool/_expression_values.py: the reading of an array or a cube's group thatpathway_scoresused, moved so that both modules share it (behaviour and messages of the pathway scores unchanged but for naming what ids are matched to).validation/activity.py;tests/test_activity.py,tests/test_networks.py, fixtures intests/data/activity; entries intests/test_masked_inputs.py.cytepool.activityandcytepool.networks; a row in the capability matrix (and its line under not implemented removed); the networks and their licences on the Datasets page; the Validation page (row, section, totals, command, R environment); five works inreferences.biband the Bibliography page; Choosing a method, How to cite, Related software, Glossary, the Overview and the README (status row, planned list, known limits).THIRD_PARTY_NOTICES.mdrecords what is adapted from decoupler, with its BSD 3-Clause licence, and the two networks.Design notes
min_targetstargets among a profile's genes has no score there; sources keep the network's order._ridxdoes (a tiled range shuffled row by row by numpy's generator), so that decoupler's seed and gene order give decoupler's permutations; the mean and standard deviation of the permuted scores are accumulated in one pass (Welford 1962).topkeeps ties at the cutoff, as progeny'sgetModel(dplyr'stop_n) does.Networks and their licences
CollecTRI_regulons.csv, 4,345,649 bytes, SHA-2564473c9189dd53dacc80297709ad1452dda1086a1cc2185f9a56146c261668701(Zenodo's MD5cee4a3943c059e6dd8796ced6dec44f6)progeny_1.28.0.tar.gz, 10,642,873 bytes, SHA-2562c41531ef6d088047e2830ccc5741aa0f28f48fb51d4c164cc8331e19b925d7b(Bioconductor's MD598f76e162cce19fd43ab13251969b117)CollecTRI's licence levels follow the licence purposes that OmniPath's resources service
lists for its twelve resources. Every resource but GEREDB is listed for commercial use
(CC BY 4.0 for ExTRI, NTNU Curated, TFactS, SIGNOR, IntAct, CytReg, GOA and
Pavlidis2021; CC BY-SA 4.0 for TRRUST; LGPL 3.0 for HTRIdb; an informal licence for
DoRothEA's level A).
licence="commercial", the default, keeps the 39,896 interactionsthat one of them supports and leaves out the 3,279 that GEREDB alone supports;
licence="academic"keeps all 43,175. OmniPath lists GEREDB's licence, the AcademicFree License 3.0, for academic use, although that OSI-approved licence does not itself
forbid commercial use, so the commercial level errs on the safe side. decoupler 2.2.0
accepts a licence for CollecTRI but returns the whole file at every level. PROGENy's
genes keep the symbols of its release; decoupler's
op.progenyreads PROGENy throughOmniPath, which renames some genes to current symbols. VIPER is not included: the
licence of its reference implementation allows only non-profit academic use.
Deliberate differences from decoupler
p_valuesare the raw ones andadjusted_p_valuesare adjusted as for ULM.decoupler also keeps adjusted p-values in single precision and computes MLM's
p-values as 1 - cdf (0 below about 1e-16); here both are double precision, from the
upper tail.
score exceeds the absolute observed score, then folds that share as for a one-sided
count, so a score near zero gets about 2 / n; here the p-value doubles the smaller
one-sided p-value, (1 + b) / (1 + n). A normalized score with no spread among the
permutations is NaN here, infinite or 0 in decoupler.
scores are NaN. Missing values, which decoupler refuses, are left out per profile.
from a singular inverse; here the call is refused, naming the source.
drops them (pandas'
dropna); here they are kept, as the file and the paper countthem.
only for |r| within about 1e-6 of 1.
Validation
RSCRIPT=$REF/r-progeny/bin/Rscript PYTHONPATH=. $REF/python/bin/python validation/activity.py(decoupler 2.2.0 and scipy 1.18.1 in
$REF/python; progeny 1.28.0 on R 4.4.3 in$REF/r-progeny, run underulimit -v 8000000). 89 checks: 82 pass, 5 deliberatedifferences, 2 information; 2 min 39 s, 987 MiB.
mt.ulmmt.ulm; scipymt.ulmmt.mlmt.sfofmt.mlm's tmt.waggrprogeny(scale = FALSE)plot_top_activities: sources and lengths of 15 barspl.barplotop.collectri, OmniPath's resources, progeny's models andgetModelop.collectriat its levels; PROGENy through OmniPathScores and estimates are compared relative to the largest absolute value of a case,
p-values relative to each value.
Tests
tests/test_activity.py(34) andtests/test_networks.py(15), 1.9 s warm and 37 scold (compiling), and 96 new checks of the masked-input inventory. They compare with
decoupler's outputs written by the validation (its permutations replayed through a
numpy.random.Generatorsubclass, so the check does not depend on numpy's streams);with values derived by hand (a source of two targets on three samples, t = -13 /
sqrt(108) and p = 1 - 13 / sqrt(385); MLM of one source equal to ULM; the weighted mean
and sum; weights of one sign as Student's pooled two-sample t-test); with the exact
null distribution over all 120 permutations of five genes; and with invariants (orders
of genes, sources and samples; negated weights negate scores; scaling and shifting a
profile scales ULM's slopes and keeps its t; zero weights, zero genes and genes
without ids change nothing; a profile with missing values equals that profile alone
over its observed genes). Networks: decoupler's parse of rows in CollecTRI's format,
the commercial level, R's values of R data files (factor and text genes) and dplyr's
top_nwith a tie; refusal of a file that is not the one pinned, a refused downloadthat leaves nothing behind, offline use from the cache,
XDG_CACHE_HOME, thename of the client sent; the tests never connect.
Checks
skipped; the same with bounds checks, and with the rounding changed
(
OPENBLAS_CORETYPE=Sandybridge, 4 threads,NUMBA_CPU_NAME=generic, a freshcache); Python 3.14: 4,737 passed; Python 3.15: 4,631 passed, 107 skipped.
uv run ruff check cytepool tests validation docsandruff format --check: clean.uv run mypy cytepool: no issues in 76 files.make -C docs api: no warning;make -C docs html(Node.js 24): built;tests/test_documentation.py: 74 passed.