Repository navigation
v4.1.0 — corpora that describe a real compartment
Four signature corpora now ship, up from two. The two new ones — synthetic-blood and
synthetic-tissue — draw every repertoire as a naive/memory mixture across three quantile
ladders measured per locus on the compartment they are named after, so a corpus spans the depth and
clone-size range the samples it will be applied to actually have.
pip install -U vdjtools
vdjtools signature --corpus synthetic-blood samples/*.tsv.gz -o vsig.tsvNo build step and no cohort sample: every receptor comes from the bundled recombination models, and a
rebuild is bit-identical at any core count.
Why
A corpus fixes the winsorization bounds, the centre, the scale and the rotation, and all four are
estimated from the repertoires it was drawn across. None extrapolates. The 4.0 corpora drew depth over
2.4x (TRD) to 11.0x (IGH), from 1,168 deep blood samples. One streaming pass over the whole
reference store — every sample with at least 100 reads in the locus — puts the real axis an order of
magnitude wider:
| cohort | locus | samples | richness p05 | median | p95 | spread |
|---|---|---|---|---|---|---|
| blood | TRB | 34,365 | 74 | 457 | 3,162 | 43x |
| blood | IGH | 33,245 | 84 | 697 | 6,200 | 74x |
| tissue | TRB | 22,298 | 30 | 158 | 2,977 | 99x |
| tissue | IGH | 47,031 | 40 | 602 | 10,352 | 259x |
Three ladders per locus, five quantiles each: clonotype richness; reads per expanded clone,
(reads - singletons) / (richness - singletons); and the singleton fraction f1, which in a
reasonably deep library is what stands in for the naive compartment and which falls with donor age
(Britanova et al. 2014,
2016). V and J usage need no ladder — the rearrangement
model produces it.
The mixture is constructed, not sampled: round(f1 x N) clonotypes get one read and the rest
share the remainder with Zipf rank-abundance frequencies on a floor of 2, so each sample hits its
drawn richness, read count and singleton fraction exactly.
Two things that had to be measured rather than assumed
Reads per expanded clone, not per clonotype. A repertoire with f1 singletons whose other
clones all carry at least 2 reads has at least 2 - f1 reads per clonotype. That is an identity, and
a pair drawn from those two marginals lands in the region it forbids about half the time on blood
TRB; drawing the read count itself does so for 21.1% of 20,000 draws. Reads per expanded clone is
>= 2 whatever f1 is, so the trio has no forbidden region and nothing is clipped back out of one.
Five quantiles, not two. The read count is a product of all three drawn quantities, so it is the
sharpest check: against blood TRB's measured median of 763 reads, a 40,000-draw simulation gives
762 at five quantiles and 846 at three; blood IGH's 1,298 comes out 1,276 against 1,490.
The three are drawn through a Gaussian copula at the cohort's measured rank correlations — for the
rotation rather than for any marginal, since a corpus's rotation is its covariance structure and
f1 against expansion size is -0.503 on blood TRB and -0.846 on blood IGK.
What it reproduces, and what it does not
500 drawn samples per cohort, against the cohort's own percentiles: f1 within 0.03 everywhere,
richness within 10% on all 14 (cohort, locus) pairs, read count within 15% on 10 of 14. The
exceptions are the four shallow tissue TR loci, where the read count runs 20-52% high (tissue TRB 467
against 308) — a product of three heavy-tailed factors has a median above the product of their
medians unless the joint tails match exactly, and no marginals-plus-copula draw does that. The drawn
p95 of the read count is also ~29% below the cohort's (blood TRB 3,755 against 5,274), so the
fitted depth ceiling is that much tighter. Full table in the
docs.
On four TCGA tumour-tissue repertoires the corpora rank as their names say — median |z| over the PC
columns 0.246 through synthetic-tissue, 0.318 through synthetic-blood, 0.351 through memory,
0.674 through naive.
Also
--depth-spreadon bothcorpuscommands, and--size autoas the default. On asynthetic-*
corpus--depth-spreadis refused rather than silently ignored, because that band is measured;
--sizerescales the whole ladder about its median instead.synthesizetakes a corpus name, not a regime.corpus_planresolves a name for both halves and
corpus_metawrites both manifests, so avsig_<name>/rsig_<name>pair cannot disagree about the
cohort, the ladders, the correlations or the germline it was drawn from.- The manifest gains
cohort,richness_band,expanded_count_band,singleton_frac_band,
rank_corr,depth_spreadanddepth_spread_requested; thersighalf records depth for the
first time. naiveandmemoryare unchanged and still rebuild bit-for-bit, checked byte by byte against
4.0.1.
The geometry half is mirpy-lib 4.1.0; run both against the
same corpus name and join on sample_id (947 + 904 -> 1,852 columns).
Full changelog: https://github.com/antigenomics/vdjtools/blob/master/CHANGELOG.md