Repository navigation
Restructure the documentation as a short book, with one home for each fact - #70
Merged
Merged
Conversation
parashardhapola
force-pushed
the
39c-docs-structure-and-language
branch
from
October 28, 2026 05:15
7709c69 to
ce134e6
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.
The explanatory pages said the same things several times, from different angles: once in
the chapters, again in the module docstrings that the API reference renders, again in the
README's status table and known limits, and in four lists of the same capabilities. This
pull request gives every fact one home and links to it from everywhere else. "How the
statistics work" becomes "Understand the methods", a short book of 17 pages that reads from
the first chapter to the last, each chapter placing itself after the one before and leading
to the next. The guides stay practical: each opens with the default for its question, with
the alternatives under Choices and links to the chapters for the statistics. The copy rules
reach every page, the README, the docstrings, the messages and the figure labels, and every
guide was executed again.
The new structure
default and why, the choices, and the limits and deliberate differences from the
reference tools in plain words. The Validation page holds the agreement with each tool,
with the numbers the scripts print, and the timings. Docstrings define behaviour. The
guides show tasks on data. "Choosing a method" lists every question with its default,
the alternatives and when to choose them, and the one list of what is not implemented
yet. Every other place gives a clause and a link to the section that states the fact,
by its label.
and its guide, the sections of the model, then "Defaults and choices", "Limits and
differences" and "Checks and further reading", which links the Validation sections it
rests on and the works it draws on. A test checks the parts a machine can check.
limma_voom, with limma-trend and the adjustment across cell types under Choices;Repeated measures and donors with
dream_voom, with the fixed donor effect and theprofiles pooled by donor under Choices; Gene sets and pathways with
cameraon acollection and GSEA, with one set chosen in advance and over-representation under
Choices; Bulk RNA-seq with
limma_voomon a cube of one group, with edgeR'squasi-likelihood F-tests and DESeq2 under Choices; Align and combine studies with
meta_analysis, with the joint model of stacked studies under Choices; Replicationacross studies with
sumrank, with the replication tables and combined p-values underChoices. Each guide's first paragraph reads well on its own, since it becomes the page's
description in search results and link previews.
functions share, the conventions that match the reference tool, and their references.
The models, steps and comparisons moved to the chapters. Where a module listed again
the differences from its reference tool that its chapter states, the list became the
address of the chapter's "Limits and differences", and each difference that changes
what a function returns or refuses is stated in that function's docstring. Without
their references, module docstrings went from about 43,500 words to 25,800, and
function and class docstrings from about 100,800 to 107,700, as they took over the
rules that help() needs. A function that sent readers to its module's documentation
now gives the rules itself or its chapter's address, and every site address in a
docstring is checked to resolve.
chapters that appear word for word in a docstring, in a run of eight words or more,
the repetition fell from 3,000 of the chapters' 15,400 words on master (19.5%) to 143
of 36,200 (0.4%), all of them in formulas that a chapter shares with the function
that computes them.
Validation page's summary, one row per method with its functions, the reference and
version, the tier with the bounds its checks use, and its section. Validation's
sections are grouped as the API reference is, each opening with its script's checks,
run time and memory and a link to the chapter section it checks, and the scaling rules
of its comparisons are stated once. "Cube files and provenance records" is now the
complete specification of the file, and a test checks that it names every key that
CytePool writes. The glossary gives one sentence per term with a link to the section
that defines it, and gains 29 terms. The bibliography is grouped by the chapters that
cite each work, and How to cite gains rows for every function that had none.
Pages added, renamed and removed
Addresses are below https://docs.nygen.io/CytePool/.
statistics/precision-weights("Precision weights")statistics/limma-voomstatistics/normalization-and-filtering(new)statistics/over-representation-and-gsea(new)statistics/pathway-scores(new)statistics/activities(new)statistics/aligning-studies(new)statistics/replication(new)reference/capabilitiesreference/literatureKept addresses with new titles or narrower content:
statistics/cubes("Pseudobulkprofiles and cubes", was "The cube and its additive layers"),
statistics/empirical-bayes("Empirical Bayes moderation", was "... and TREAT"),
statistics/count-models("edgeR andDESeq2", was "Count models"),
statistics/mixed-models("Mixed models and dream", was"Mixed models, REML and dream"),
statistics/gene-set-tests(camera, fry, roast, mroast andromer; the other methods have chapters of their own),
statistics/meta-analysis(SumRank,held-out prediction, combined p-values and pi1 moved to Replication, and pi0 to Multiple
testing) and
guides/combine-studies("Align and combine studies"). The section "Otherdesigns and data" is gone: Bulk RNA-seq joined Compare conditions, and the guides on
several studies have their own section.
Statements that were wrong, and what is right
Moving each fact to its home brought out places that disagreed. Each was settled against
the code, the output of the validation scripts or the reference tool's documentation, and
by running the tool where its documentation leaves the answer open.
Cubes and files:
known without reading lazy layers; for a lazy cube whose groups were not read whole the
input is null (the code of the provenance record).
splits samples otherwise. The Cube files page also missed the operation
with_columnsand the imports from AnnData and MuData, and now the test that every key CytePool
writes is on the page keeps it complete.
value of each component positive, not the largest coordinate (the code of
principal_componentsandplot_mds; the docstrings and the Validation page saidotherwise).
Cube.fingerprint(about 0.4 s per 100 million values with SHA instructions, 1.3 swithout), and the other docstrings cite it.
features), a fingerprint covers the normalization too, and a library size is the total
count of a cell or of a profile.
Designs, linear models and moderation:
estimator, which down-weights outlying genes and Winsorizes nothing; Winsorizing is the
method of moments' (the code of
fit_f_distribution_likelihood).differ; genes without residual degrees of freedom do not count (the code, and the
Validation page, which said "when the residual df differ").
one place and "0.56 to 2.55 times" in another; the measured range remains (the
validation output).
voomWithQualityWeightsonly;arrayWeightschooses REML for data without prior weights or missing values (limma's help pages).
limma_voomfollows limma's workflow with two additions, the minimum of 10 cells persample and exact contrast standard errors.
capped, and linked a section that gave only the t-tests' cap; the empirical Bayes
chapter now says that the F-tests' are not capped, as in limma (the code, which follows
a run of limma).
quasi_likelihood_f_test, like DESeq2's likelihood ratio test, tests severalcoefficients at once; the map offered only the latter.
Models of counts:
pages said near 1e-7 in one place and near 1e-8 in another (edgeR 4.4.0's
glmFitand
glmQLFitrun on the validation's data: 2.6e-8 to 9.8e-8).designs stop short of the maximum (the validation output).
minReplicatesForReplaceis 7, not Inf: the comparisons are withDESeq(..., minReplicatesForReplace = Inf), which gives DESeq2's defaults where no rowof the design occurs seven times or more.
fit_quasi_likelihoodandfit_deseq2do not take; it isrewritten from their signatures. Where edgeR 4.4.0 alone was checked, the pages name
that version rather than "edgeR 4".
Mixed models and dream:
ModeratedFixedEffectTestssaid that dream's moderated tests use Satterthwaite'sdegrees of freedom;
dream_voomuses Kenward-Roger's below 20 samples by default(the code, and variancePartition's help page, now quoted once, with what running it on
20 samples showed).
validation/mixed_models.py --benchmarknow times both methods: on 20,000 genes on onethread, Kenward-Roger's tests took 0.15 s for 18 samples and 8.5 to 9.7 s for 120,
against 0.06 to 0.08 s for Satterthwaite's.
which replace "tens of percent" (the validation output).
reports gives unbiased fractions where REML can show substantial bias; what REML does
is now worded one way. A mixed model's residual degrees of freedom are approximate,
between n - p and n minus the rank of the fixed and random effects.
p-values agree with lmerTest to 1e-5, since lmerTest differentiates numerically (the
validation output).
Gene sets and pathways:
1/(2B + 1) for up or down: 0.0005 and 0.00025 with 1,999 rotations, where the guide said
"about one over its number of rotations" (run with 99 and 1,999 rotations).
lists them once, and the Validation page adds that decoupler reports MLM's p-values
unadjusted under the name of its adjusted p-values.
results of
dream_voom; one place said "any design and contrast".gseakeeps every size,as fgsea does. PLAGE's sign is a deliberate difference: CytePool's scores rise with the
mean standardized expression of a set's genes, and GSVA's follow its linear algebra
library, so they are compared up to sign.
kernel="auto"uses no kernel,as GSVA documents, where GSVA 2.0.0 stops with an error; the README had said "as GSVA
does". PROGENy's gene symbols are those of progeny 1.28.0 from Bioconductor 3.20, and
the version of GSVA whose licence the module names is 2.0.0.
Activitiessaid to test activities withfit_linear_modeland a design built from theprofiles;
limmawith the cube's design does it, as for pathway scores.keggadoes; the list of genes in either direction is CytePool's own.
adjusts them"; decoupler leaves MLM's unadjusted (the comparison with decoupler 2.2.0
on the Validation page).
Several studies:
pi0estdoes, not those above it."in most"; its p-values come from permutations only when
n_permutationsis set.disease called differentially expressed were not reproduced in any of 16 others, where
some places said "not found in the next". The arm of their comparison that they call
inverse-variance is a random-effects meta-analysis, while "inverse-variance" elsewhere
names the fixed-effect model.
likelihood is higher at zero than at the maximum it found.
combine_p_valuesnow says; SumRank takes the results of the studies, not the stacked cube.
(
"mudholkar_george"), whose t distribution approximates the sum of logisticvariables also for one study; the chapter said that one study gives its own p-value
by every method (run: one p-value of 0.03 combines to 0.0289 by the logit, and to 0.03
by the six other methods).
Across the site:
matrix, the Overview and the chapters; the map now holds the one list.
Validation summary now gives its own bound. GSEA's runs with their own random sets and
SumRank's permutations are calibrated too, not only the rotation tests, and the tests of
scores and activities with a design (
limma) are checked bytests/test_score_tests.pyagainst the functions this page validates.guide's pointer to the cell types that are not fitted, the glossary's entry for CPM, and
Design.checkandmodel_matrix, whose rules the designs page of the API reference nowrenders.
The README
The README is GitHub's and PyPI's front page, and it now says what CytePool does and
links to the site (about 570 words, from about 6,100): a first paragraph that leads with
the task; the status; how to install; an example that pools cells, tests a stimulation
in every cell type and tests gene sets, checked by running it; the questions CytePool
answers, each with its default function, linked to "Choosing a method" for the
alternatives and to Validation for the agreement with each tool; where the documentation
is; the development checks; and the licence. Its links are absolute, since PyPI does not
resolve relative ones. The status table, the list of planned work and the known limits
moved to their homes: the Validation summary, the map, the chapters and the docstrings.
Messages unified
bool" (and "trend must be True, False or one covariate value per feature").
more", or with "; " between items that hold commas, as "a; b; and 3 more"; the design
checks, the model matrix and the reprs of gene sets and networks built their own.
expected, such as "an integer", and ends "got ", and the range is the
ValueError's, such as "at least 1".
The tests that match these messages changed with them.
Other changes
AGENTS.md("Writing"), with the homes of each kind of fact("Documentation"). A test scans the pages, the README,
AGENTS.mdand every string andcomment of the package for em dashes, en dashes used as punctuation, centred dots
between words, stock metaphors and all-caps headings; others were read for, such as "the
X behind it", and reworded.
map links every chapter and leads to the first; labels are unique and unlike the
headings of other pages; every site address in a docstring, the README and the API
pages resolves; the Validation summary agrees with its sections; the Cube files page
names every key CytePool writes; and every repository path that
THIRD_PARTY_NOTICES.mdnames exists, which would have caught the three files the renames left behind there.
validation/mixed_models.py --benchmarktimes Kenward-Roger's tests as well asSatterthwaite's, at 120 samples and in a study of 18, and the Validation page's Timings
give its output.
cytepool.plotting's docstrings say which tool each figure follows and how the signsof components are chosen, and list each reference once.
Checks
uv run pytest: 5,183 passed, 18 skipped (the zstd tests, which need Python 3.14).uv run ruff check cytepool tests validation docsanduv run ruff format --check cytepool tests validation docs: clean.uv run mypy cytepool: no issues.make -C docs apiandmake -C docs html: built without warnings.make -C docs check-outputson every page reports its outputs current. The printedresults are those of the previous run, but for one message of
Design.checkthat hadchanged; the figures are unchanged, and their descriptions were checked against them,
six of them corrected. The README's example was run on the simulated study of the
guides.
validation/mixed_models.py --benchmarkandvalidation/quasi_likelihood.pywere runagain for the changes to them; the second printed the same 223 checks as before.