Skip to content

v4.2.0 — the three real corpora

Choose a tag to compare

@mikessh mikessh released this 28 Sep 02:23
· 148 commits to master since this release

All seven corpora the docs have named since 4.0.0 now exist. blood (11,117 bulk RNA-seq blood samples, 947 study groups), tissue (21,131 / 1,934) and deep-tcr (3,936 amplicon samples, TRA+TRB) are fitted on repertoires rather than drawn from the recombination models, each with an uncapped variant so the per-study cap's effect is measurable.

pip install -U vdjtools
vdjtools signature --corpus blood samples/*.tsv.gz -o vsig.tsv

A real corpus fits real data three times better

Four TCGA tissue samples at --components 32, fraction of the row winsorized: tissue 0.199, blood 0.271, synthetic-tissue 0.595. A real corpus's bounds actually contain real samples. deep-tcr lands far out (median |z| 2.1), correctly — amplicon TCR is the wrong reference for RNA-seq.

The population was re-derived, not inherited

The previous reference slice selected on has_TRB | has_IGH, which means ">= 100 reads" in the base metadata table and "any row present" in ~24,600 appended rows, so a population built on it admits thousands of ultra-shallow repertoires. The harmonized sample table has no per-locus read column at all, so the floor is now applied against reads measured off the raw data. Blood comes out at 22,441 task-disjoint samples against the 23,234 recorded before — that difference is the defect being removed.

TRG and TRD get a 30-read floor rather than 100, because they cannot support 100 at scale: tissue TRG has 367 samples in 78 study groups at 100 and 1,574 in 317 at 30. Each locus is fitted only on the rows that observed it, so this is a stratum, and n_obs records what each column rests on.

k = 256, every component shipped

Up from 128, and verified a strict superset: refitting reproduces all 128 original components at |cos| = 1.000000 with identical eigenvalues to 0.000e+00, so nothing already computed moves. It buys real variance on the statistics half (naive TRB 0.4236 → 0.6283) while on the geometry half 256 is well past diminishing returns — rsig reaches 0.90 in 7–18 components, so --components 32 is usually right there.

Artifacts are fetched, not bundled — the wheel drops from 20 MB to ~1.4 MB

The nine corpora are ~110 MB across both halves. The wheel now ships corpora.json (every name, size and SHA-256) and fetches what you name from corpora-v1 into $VDJTOOLS_CORPUS_DIR (default ~/.cache/vdjtools/signature), verified against that digest. Resolution is path → wheel → cache → release, so a local path always wins; a digest mismatch is deleted rather than cached. vdjtools corpus --fetch all pre-warms.

publish.yml now publishes only for a v* tag, every job gated — without it, creating the data release fires the workflow.

No artifact manifest carries a cohort label, dataset name, accession or sample id.

Fixed

Four deep-tcr samples have their TRA and TRB in different source mirrors, so per-cohort grouping made each two half-samples and the fitter's sample_id join then fanned 3,940 rows into 3,948 — mapping raw rows to the wrong samples while the shapes still lined up.

The geometry half is mirpy-lib 4.2.0; run both against the same corpus name and join on sample_id.

Full changelog: https://github.com/antigenomics/vdjtools/blob/master/CHANGELOG.md