Skip to content

Add the guides of Compare conditions, with executed figures - #61

Merged
parashardhapola merged 1 commit into
masterfrom
38b-compare-conditions-guides
Oct 26, 2026
Merged

parashardhapola merged 1 commit into
masterfrom
38b-compare-conditions-guides

Conversation

@parashardhapola

Copy link
Copy Markdown
Member

Summary

The section Compare conditions had one simulated tutorial. It now has six short guides, one per question: normalization, filtering and sample quality; genes that change in each cell type; repeated measures and donors; cell-type composition; gene sets and pathways; pathway and regulator activity. Each is an executed notebook whose cells mostly draw the figures users know from limma, edgeR, speckle, variancePartition, fgsea, GSVA and decoupler through cytepool.plotting, ends with a short Choices section, and links to How the statistics work for the theory. Real data (Kang et al. 2018) where it shows the method, simulation where the truth must be known. Documentation only: no library code changed.

Pages

File Title What it shows Figures Data check-outputs in CI
guides/normalization_and_quality.ipynb Normalization, filtering and sample quality MDS of the monocytes (stimulation on dimension 1, donors on 2 and 3); voom's trend with and without filter_by_expression, and how many genes the paired design and the condition keep; TMM, RLE, upper-quartile and DESeq2 factors (the interferon response takes a fifth of the stimulated libraries; factors 1.19 against 0.83); plotSA after robust moderation (217 outlying variances: hemoglobin and response genes; prior df 11.4 to 27.7); sample quality weights for the noisy bulk sample (0.30) and their effect on calls against the truth; Design.check on a mislabelled sample plot_mds (2 panels), plot_mean_variance (2), plot_residual_variances, plot_mds + plot_sample_weights kang2018, simulated_bulk no (download)
guides/genes_per_cell_type.ipynb Genes that change in each cell type Cells per profile and which profiles min_cells leaves out; the paired design and its check; limma_voom on all eight cell types; MD and volcano plots and a top table of the monocytes; voom against trend, with each cell type's spread of library sizes; adjustment within or across cell types (across is not stricter everywhere: the monocytes lose calls, the others gain) plot_cell_numbers, plot_significant_genes, plot_md + plot_volcano, plot_significant_genes (2 panels, twice) kang2018 no (download)
guides/repeated_measures.ipynb Repeated measures and donors Paired fixed effects against dream on the Kang monocytes (log2 fold changes correlate at 0.999); a simulation of 3 patients and 3 healthy donors at 3 time points: the paired design's check, dream_voom with Kenward-Roger and an F-test across time points, calls against the truth, the calibration of the test between donors against profiles pooled by donor; variance partitioning of the monocytes plot_p_values (2 panels), plot_variance_fractions + plot_gene_variance_fractions kang2018, page simulation no (download)
guides/composition.ipynb Cell-type composition propeller on the simulated study where only the monocytes change: every cell type tests significant, and the proportion ratios (0.77 to 0.81 for the others) show why; the same test within the lymphocytes finds nothing; paired against unpaired designs, logit against arcsine plot_composition, plot_proportions (twice) simulated_pbmc yes
guides/gene_sets.ipynb Gene sets and pathways One set chosen in advance (Hallmark interferon-alpha) with fry, roast and camera; CollecTRI's regulons as a collection ranked by camera; over-representation among the genes up and down; GSEA's enrichment plot and fgsea's table plot_barcode, plot_gene_sets, plot_over_representation, plot_enrichment, plot_gsea_table kang2018, hallmark_interferon_alpha, CollecTRI (downloaded on first use) no (download)
guides/pathway_activity.ipynb Pathway and regulator activity ULM of CollecTRI on each cell type's response (bars for the monocytes, heatmap of all cell types); PROGENy in every monocyte sample, tested with the paired design; GSVA scores of the regulons tested as GSVA's guide does plot_top_activities, plot_activities (twice), plot_pathway_scores kang2018, CollecTRI and PROGENy (downloaded on first use) no (download)

collectri() is called with its default, the licence level a company may use, and the pages say so. Every figure has a description for its alternative text. Warm execution takes 2 to 5 s per page (12 s cold for the first).

Changes to shared files

  • docs/source/myst.yml: the six guides under Compare conditions, in the agreed order with Pathway and regulator activity added after Gene sets and pathways; differential_expression.ipynb moved to Start here, after the Quick start, as "From cells to results".
  • docs/source/differential_expression.ipynb: its heading becomes "From cells to results", and a sentence points to the guides. Prose only; its outputs and code fingerprint are unchanged (check-outputs: current).
  • docs/source/index.md: the tutorial's link text, and the "Where to read" cells of five questions (genes per cell type, composition, pathways and regulators, donor variation, effects of time and context) point to the guides.
  • docs/coverage_exemptions.toml: 14 [planned] entries removed, now covered: plot_barcode, plot_cell_numbers, plot_composition, plot_gene_sets, plot_md, plot_mds, plot_mean_variance, plot_p_values, plot_proportions, plot_residual_variances, plot_sample_weights, plot_significant_genes, plot_volcano, Table.to_pandas.
  • .github/workflows/docs.yml: guides/composition appended to the check-outputs pages; the five other guides need the Kang download.
  • How the statistics work: one sentence each in Choosing a method, Precision weights, Mixed models, Gene-set tests, Composition tests and Multiple testing linking to the guide that shows the method on data. The API pages' "Used in" lists come from the site's machinery and now name the guides.
  • No test changed: tests/test_documentation.py already covers the new notebooks (80 tests, 74 before).

Design notes

  • differential_expression.ipynb stays the simulated tutorial. The guide on genes per cell type is a new page on the Kang data rather than a rewrite of it, because the two answer different needs: the tutorial walks from simulated cells to a cube, a result and its provenance trace, with the truth known, which is what the agreed quick start becomes; the guide answers one question on real data with its choices. The tutorial also holds what no other page has yet (tracing a result back to the cube's profiles, a rank-deficient cell type, a cell type that is not fitted, which the guide links to), and it runs without downloads in CI. It moved to Start here, so that Compare conditions holds guides only; the quick start pull request can take it over and remove it.
  • Gene sets and pathways became two pages. One page with camera, fry, roast, over-representation, GSEA, GSVA and two networks would have had nine figure cells. The split follows the kind of answer: tests of a contrast (Gene sets and pathways) and scores of every profile (Pathway and regulator activity), as the Choices of the Gene-set tests page already separate them.
  • The gene-set collection. CytePool bundles no pathway collection, and adding one (MSigDB's Hallmarks, say) would mean a new registered dataset and notice. The pages use the targets of each transcription factor in CollecTRI as a collection (199 sets of 15 to 500 tested genes), which the activity page then scores with their signs; the text says that any GMT file read by read_gmt works under its provider's terms.
  • Numbers in the prose are those the cells print or the figures show; literature is cited for methods only, and no number is quoted from a paper.
  • Two-panel figures use matplotlib's constrained layout, which keeps the plotting functions' outside legends clear of the next panel.
  • The GSEA cell keeps gsea's warning that the MYC regulon (383 genes, enrichment score -0.25) has too few random scores of its sign; the text explains it. More permutations (10,000) did not change it.

Findings

  1. dream's tests of a variable of the donors are anti-conservative with few donors; this is the reference method's behaviour. In the repeated-measures page's simulation (3 patients and 3 healthy donors at 3 time points, gene-wise dispersions and donor variances), 8.8% of the p-values of the 3,850 genes without a disease effect fall below 0.05, and 28 of the 109 genes called at 5% FDR are false; the tests within donors hold (5.2% at 6 h). Over three seeds the share was 8.0 to 8.9%, while limma_voom on the profiles pooled by donor (Cube.collapse_samples("donor")) gave 4.8 to 5.0%. In runs with a constant dispersion it was 9.5 to 10.5% with 3 donors per group and 6.9% with 8, and there the unmoderated Kenward-Roger tests (fixed_effect_tests on the same fits) gave 3.6 to 5.2% and the pooled profiles 4.2 to 5.5%. Run as a black box on the same counts (CytePool's filtered genes, library sizes times TMM factors), variancePartition 1.36.2's voomWithDreamWeights, dream (Kenward-Roger at 18 samples), eBayes and topTable(coef = "diseasepatient") give the same 8.83%, with p-values within 1.0e-5 (relative) of dream_voom(span=0.5). A likely cause: the moderated tests take the test's degrees of freedom plus the prior's, while the prior describes the variance within donors and a contrast between donors rests mostly on the donor variance, estimated from six donors. The page shows it (cells 2 to 4) and recommends pooling by donor for such questions; the mixed-models statistics page and dream_voom's docstring could say it too. Reproducer: the imports and the second to fourth code cells of docs/source/guides/repeated_measures.ipynb, whose simulation needs no download.
  2. plot_significant_genes can draw the count of the longest bar over the left frame. It sets the limits to 1.2 times the longest bar, which leaves too little room for a five-character label at 8 points in a narrow panel:
    figure, (left, right) = plt.subplots(1, 2, figsize=(11, 4.5), layout="constrained", sharey=True)
    plot_significant_genes(limma_trend(kang, design), ax=right)  # "1,553" crosses the frame
    (with kang and design as on the genes page). In a single default figure the count "1,549" of limma_voom touches it.
  3. Design.check does not flag numeric donor ids. Ids such as 101, 1015, 1016 enter the model as one slope without a warning, because numeric_codes asks for consecutive values:
    samples = {"sample_id": [f"s{i}" for i in range(8)],
               "donor": [101, 101, 1015, 1015, 1016, 1016, 1039, 1039],
               "condition": ["ctrl", "stim"] * 4}
    Design(samples, "~ donor + condition").check()  # no problems found; 3 columns
    With the codes 1 to 4 it warns. A whole-number variable whose every value is shared by several samples looks like ids whatever their spacing.

Awkward APIs, for the API and language pull request

  • camera, fry, roast, mroast and romer take a matrix or a VoomResult, not a cube's cell type or a DifferentialExpressionResult as gsea, over_representation, gsva and ulm do: the gene-set page repeats limma_voom's steps by hand (layer, filter_by_expression with the design, tmm_factors, voom, the kept genes' symbols), and a user whose samples min_cells left out must also subset the design.
  • DifferentialExpressionResult keeps no fit, so plotSA and voom's plot of a limma_voom run need the fit redone (the quality page does it).
  • expression_filter has no grouping: with a paired design the design-based filter keeps genes with counts in about two samples (5,125 genes in the monocytes, 3,651 with the condition as the group), and dream_voom, which filters with its fixed effects, tests different genes from limma_voom on the same data.
  • Testing scores or activities with a design takes moderated_statistics(contrasts_fit(fit_linear_model(x.scores, Design(...)), design.contrasts), trend=...) and adjust_p_values, and the design is built again from PathwayScores.samples or Activities.profiles (two names for the same table) with the same levels and contrasts; the pages build the same levels and contrasts for four designs. A way to reuse a design on another sample table, and one call that tests scores, would remove most of it.
  • A Network becomes a GeneSets only by a comprehension, GeneSets({s: list(t) for s, t in network.items()}, source=..., version=..., licence=...), which loses its provenance unless copied by hand.
  • The same idea has two names: gene_ids (camera, fry, roast; a features column for gsva and ulm on a cube) and id_column (gsea, over_representation, ulm on a result).
  • roast returns one row per alternative while camera and fry return one row per set, so reading its "up" p-value takes a filter.
  • gsea's warning recommends n_permutations=10000, which did not help the MYC regulon here.

Note for the PCA pull request

Normalization, filtering and sample quality shows the samples with plot_mds in "Do the samples group as expected?". plot_pca belongs beside it (DESeq2's plotPCA of the same monocytes), with a line in the page's Choices on the MDS plot's leading fold changes against PCA's most variable genes. The page has no placeholder for it.

Needed change in THIRD_PARTY_NOTICES.md

Under "Test, validation and documentation data", the paragraph on the documentation's data lists only the datasets of docs/datasets.py. Two guides now download the networks: add that docs/source/guides/gene_sets.ipynb and docs/source/guides/pathway_activity.ipynb call collectri() (both) and progeny() (the second), which download CollecTRI and PROGENy into the cache outside the repository, and name the documentation beside cytepool/networks.py and validation/activity.py in the sections "CollecTRI" and "PROGENy".

Merging

The edits to shared files are local: one appended page in the check-outputs line of docs.yml (likely to meet another guide's addition on the same line), removed lines in [planned], the navigation of Start here and Compare conditions, five cells of the Overview's table, and one sentence per statistics page.

Checks

  • make -C docs html with Node.js 24 first on PATH: built, without warnings beyond Node.js's notice about url.parse(); the API pages list the new guides under "Used in".
  • make -C docs check-outputs PAGES="quickstart differential_expression guides/export_cubes guides/bulk_rna_seq guides/composition": outputs current; the five Kang guides are also current when run again locally.
  • uv run pytest tests/test_documentation.py: 80 passed.
  • uv run python docs/coverage_report.py: 243 public names, 183 used or explained in a page, 53 exempt, 7 planned (before: 169, 53, 21); no problems.
  • uv run ruff check docs and uv run ruff format --check docs (which include the notebooks): clean.
  • The full suite, on top of the SumRank pull request: 4,822 passed, 18 skipped.

@parashardhapola
parashardhapola changed the base branch from 50-sumrank to master October 26, 2026 21:16
Six short guides, each an executed notebook with the figures users expect:
normalization, filtering and sample quality; genes that change in each cell
type (Kang et al. 2018); repeated measures and donors (dream, Kenward-Roger,
F-tests, variance partitioning); cell-type composition; gene sets and
pathways (fry, roast, camera, over-representation, GSEA); and pathway and
regulator activity (CollecTRI, PROGENy, GSVA). The simulated tutorial moves
to Start here as "From cells to results".
@parashardhapola
parashardhapola marked this pull request as ready for review October 26, 2026 21:16
@parashardhapola
parashardhapola force-pushed the 38b-compare-conditions-guides branch from a3ef790 to 024a278 Compare October 26, 2026 21:16
@parashardhapola
parashardhapola merged commit f90552d into master Oct 26, 2026
6 checks passed
@parashardhapola
parashardhapola deleted the 38b-compare-conditions-guides branch October 26, 2026 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant