How the tables are computed.

This page documents the 28 codon-usage tables and 5 codon-pair tables in data/codon_tables/: the query that selects the sequences, the filters that accept them, the window that is counted, and the defining formulae for the three quantities Nucleora derives from them — RSCU, CAI and codon-pair score.

It also records what these files do not contain, which is the part that usually goes unwritten.

Inventory

data/codon_tables/ holds 33 JSON files, of two distinct kinds. They answer different questions and must not be pooled into one count.

KindFilesShapeQuantity
Species codon-usage table28 {organism, n_cds, table} Within-family relative frequency of each of the 64 codons
Codon-pair (CPS) table5 {organism, n_ref, cps} Log-ratio score for each observed adjacent codon pair

Across the 28 usage tables, 7,636 coding sequences were tallied in total — between 6 and 1,229 per table, median 250. Every table contains all 64 codons grouped into 21 families (20 amino acids plus stop).

Build pipeline

Implemented in engine/codon_builder.py :: build_table(). A table is built once per organism, on first use, and cached to data/codon_tables/<key>.json.

  1. Select. NCBI E-utilities esearch against db=nucleotide with the term <Latin name>[orgn] AND biomol_mrna[PROP] AND refseq[filter], retmax = target_cds (default 250).
  2. Fall back. If that returns nothing — the usual case for bacteria, which have no mRNA-biomol records — the term drops to <Latin name>[orgn] AND refseq[filter] with retmax = min(target_cds, 60).
  3. Fetch. efetch with rettype=fasta_cds_na, in batches of 80 identifiers, 0.4 s apart. Sequences are upper-cased and U is rewritten to T.
  4. Accept. A sequence is tallied only if its length is divisible by 3 and it begins with ATG. These are the only two acceptance criteria. n_cds is the number of sequences that passed.
  5. Count. Every codon from the first to the second-to-last is counted. The initiator ATG is counted; the terminal codon is not. A triplet containing any character outside ACGT is skipped without rejecting the sequence.
  6. Normalise. Counts are grouped by the amino acid each codon encodes and divided by that family's total, then rounded to four decimal places. The stored value is therefore a within-family relative frequency, in [0, 1], summing to 1 across each family.
Not an expression-weighted table. Each accepted CDS contributes equally, regardless of how strongly the gene is transcribed. The tally is also not a whole-transcriptome census: it is a sample of up to 250 RefSeq records in whatever order the query returned them.

What is not stored

The file format is {organism, n_cds, table} and nothing else. Consequently:

  • No raw codon counts. Only the normalised fraction survives the build.
  • No per-1000 frequencies. Converting a within-family fraction to a frequency per 1000 codons needs the organism's amino-acid composition, which is not recorded. Any per-1000 column on a page built from these files would be invented, so none is shown.
  • No usable stop-codon statistics. Because step 5 drops each sequence's terminal codon, the stop family only ever accumulates read-through or mis-annotated internal stops. 6 of the 28 tables have an all-zero stop family. Stop codons are excluded from every figure on the reference page.
  • No sequence accessions. Which RefSeq records went into a given table is not retained, so a build is not re-derivable from the file.
  • No build date. See below.

Build dates: unknown, not assumed

0 of the 28 shipped usage tables carry a build timestamp. Every file contains exactly the three keys organism, n_cds and table, so the date each tally was taken — and therefore the RefSeq contents it reflects — is not recoverable from the data.

engine/codon_table_refresh.py adds a stamp() that writes built_at, source, builder_version and n_cds_requested onto tables built from now on, and its describe() deliberately reports an unstamped table's age as unknown rather than reading the filesystem mtime: a checked-out file's mtime is its checkout date, which would be a fabricated build date.

So no RefSeq release number is quoted anywhere in this section. The tables do not record one, and attaching a release number to a tally that cannot be dated would be a guess dressed as provenance.

RSCU — relative synonymous codon usage

RSCU measures how often a codon is used relative to how often it would be used if all synonyms of its amino acid were chosen equally. It is the standard normalisation that removes both amino-acid composition and family size from codon-usage comparisons (Sharp, Tuohy & Mosurski 1986).

RSCUij  =  Xij(1/ni) · Σk=1..ni Xik  =  ni · fij Xij   observed count of the j-th codon for amino acid i
ni    degeneracy of amino acid i — how many synonymous codons it has
fij    within-family relative frequency, Xij / Σk Xik — the value stored in these files

The right-hand identity is why RSCU is computable from these tables even though raw counts are not stored: RSCU is the stored fraction multiplied by the family's degeneracy. Reading it:

  • RSCU = 1 — the codon is used exactly as often as its synonyms. No bias.
  • RSCU > 1 — preferred. The ceiling is ni, reached when a codon takes its family's entire usage; 6.0 in the six-fold Leu, Arg and Ser families.
  • RSCU < 1 — avoided. The floor is 0.

Two identities follow directly, and both are checked against the shipped files under Verification: within any family the fractions sum to 1, and the RSCU values sum to ni.

CAI — codon adaptation index

CAI (Sharp & Li 1987) scores a whole coding sequence against a reference table on a 0–1 scale. Each codon is first given a relative adaptiveness weight, the ratio of its RSCU to the highest RSCU in its own synonymous family:

wij  =  RSCUijRSCUi,max  =  fijfi,max wij = 1 for the most-used codon of amino acid i, and < 1 for every synonym. The ni factors cancel, so w is also the stored fraction divided by its family maximum.

The sequence's CAI is the geometric mean of the weights of its L codons:

CAI  =  ( Πk=1..L wk )1/L  =  exp  (   1L   Σk=1..L ln wk  ) L   number of codons scored. A sequence built entirely from each family's most-used codon scores 1.0. Because the mean is geometric, one zero-weight codon drives CAI to 0, so implementations exclude non-degenerate families (Met, Trp) and stop codons.
Reference-set caveat, stated plainly. Sharp & Li derive w from a reference set of highly expressed genes, which is what makes CAI a proxy for expression. The tables shipped here are unweighted tallies of up to 250 arbitrary RefSeq records (pipeline, step 1). A CAI computed against them therefore measures how typical a sequence is of that organism's RefSeq sample — not how similar it is to that organism's highly expressed genes. The two coincide only to the extent that overall codon bias tracks expression bias in that organism.

Codon-pair tables (cps_*.json)

These 5 files score a different thing from the usage tables: adjacent codon pairs. Some dicodons occur far less often than the abundance of their two codons and their two amino acids would predict, and systematically substituting under-represented pairs attenuates a virus without altering its protein sequence (Coleman et al. 2008). The codon-pair score of dicodon AB is the log-ratio of its observed count to that expectation:

CPS(AB)  =  ln   F(AB)E(AB) ,    E(AB)  =  F(A) · F(B)F(X) · F(Y)  ·  F(XY) F(AB)   observed count of dicodon AB
F(A), F(B)   counts of codons A and B
F(X), F(Y)   counts of the amino acids X, Y that A and B encode
F(XY)   count of the amino-acid pair XY
The F(X)F(Y) denominator removes amino-acid-pair bias, so CPS reports pair bias over and above the bias already present in single-codon usage and in the protein itself.

As implemented in engine/codon.py :: build_cps_table(), a Laplace pseudocount of 1 is added to both terms so that a pair observed once against a near-zero expectation cannot produce an unbounded score:

CPS(AB)  =  ln   F(AB) + 1E(AB) + 1 Stop codons are excluded before pairing. Scores are rounded to five decimal places.

A sequence's codon-pair bias (codon_pair_bias()) is the arithmetic mean of CPS over its dicodons: negative means it is built largely from under-represented pairs (the attenuating direction), positive the reverse.

FileOrganism keyn_refPairs observedCoverage
cps_Homo sapiens.jsonHomo sapiens000.0%
cps_chicken.jsonchicken603,35890.2%
cps_human.jsonhuman402,85376.7%
cps_mouse.jsonmouse602,95279.3%
cps_yeast.jsonyeast602,80775.4%

Coverage is against 3,721 — the number of distinct ordered pairs of the 61 sense codons. No table observes more than a fraction of that space from 40–60 reference CDSs, and codon_pair_bias() scores an unobserved pair as 0.0, i.e. treats it as unbiased rather than as rare. That is a deliberate floor, not a measurement.

Known defect in the shipped data. cps_Homo sapiens.json has n_ref = 0 and zero scored pairs — a build that failed and was written to disk anyway. It contains no usable scores. The working human table is cps_human.json (40 reference CDSs, 2,853 pairs). The empty file is reported here rather than quietly deleted, because a consumer that loads it will silently score every pair as 0.

Sampling limits

A 250-CDS tally is a sample, and sample-to-sample movement is not a change in the organism. engine/codon_table_refresh.py sets MATERIAL_DELTA = 0.005 — half a percentage point of synonymous usage — as the threshold below which a codon's movement between two builds is reported but not treated as material, on the stated grounds that resampling 250 CDSs moves codons by about that much on its own.

Two tables are far below even that sample size: Giraffe (Giraffa camelopardalis) at 7 CDS, Raccoon (Procyon lotor) at 6 CDS. Both are flagged on the reference page and both are excluded from its comparison figures, which use a 100-CDS floor (26 of 28 tables qualify). A table built from single-digit sequence counts carries essentially no information about its organism's codon bias.

RefSeq queries do not return a stable ordering, so two builds of the same organism need not draw the same records. A diff between an old and a new table is therefore a sample-to-sample comparison, and diff_against_live() labels it as one; it does not claim the source was revised.

Low-data and proxy policy, as implemented

Two mechanisms exist in engine/codon.py :: _organism_info_base(), and both are surfaced to the user rather than applied silently:

  • Low-data flag. A cached empirical table with n_cds < 40 is returned with low_data = true and a note that the table is approximate and a better-sequenced relative should be considered.
  • Declared proxy. An organism entry in data/organisms.json may carry a proxy key naming another organism whose table to use. This is a hand-curated declaration per organism, not a computed taxonomic distance, and the proxy's name is reported in the provenance note.

No table is synthesised by interpolating, blending or weight-averaging across species. An organism either has an empirical tally, a declared proxy, or no table — in which case the builder offers to construct one from NCBI on first use.

Verification against the shipped files

Three checks, run over all 28 usage tables.

1. Structural completeness

Every table contains all 64 codons in 21 families. Distinct codon counts observed across the 28 files: 64. Distinct family counts: 21.

2. The two normalisation identities

Within-family fractions must sum to 1, and the RSCU values derived from them must sum to the family degeneracy ni. Measured maxima over every non-empty family in every table:

IdentityExpectedMax deviationWorst case
Σk fik1 2.00e-04elephant_asian/S
Σk RSCUikni 1.20e-03elephant_asian/Ser

Both residuals are of the order of the four-decimal rounding applied at build time (5×10-5 per codon, up to six codons per family), which is what a correct implementation should leave behind.

3. An external biological anchor

If the RSCU derivation is right, it should recover a bias that was established independently of this pipeline. Mycobacterium tuberculosis H37Rv has a GC-rich genome — 65.6% G+C, reported by Cole et al. 1998 — and a correspondingly strong preference for G/C-ending codons.

Ranking all 28 tables by their mean G/C-ending fraction across the 18 degenerate families puts the two mycobacteria first, and clear of every eukaryote: M. tuberculosis 0.779 and M. bovis 0.774, against a range of 0.411–0.677 across the 24 eukaryotic tables above the 100-CDS floor. The individual M. tuberculosis values:

CodonAmino acidStored fractionRSCU
TTCPhe0.79241.585
ATCIle0.80102.403
CTGLeu0.52283.137
GCCAla0.45081.803
CCGPro0.54912.196

This is a direction-and-magnitude consistency check against a published genome composition, not a codon-by-codon reproduction of a published M. tuberculosis usage table. Two numbers for the reader to compare: the published genomic G+C is 65.6% (Cole et al. 1998); the mean G/C-ending codon fraction computed here from mtb.json is 77.9%. These are different quantities — third-position composition is more biased than whole-genome composition — so they are expected to agree in direction and rank, not in value.

Not assessed. No codon-by-codon comparison against an external codon-usage database (Kazusa, HIVE-CUT or similar) has been run against these 28 tables. Until it is, the claim supported here is that the derivation is internally consistent and recovers a known compositional bias — not that each table matches a published tally within a stated tolerance.

References

  • Sharp PM, Tuohy TMF, Mosurski KR (1986). Codon usage in yeast: cluster analysis clearly differentiates highly and lowly expressed genes. Nucleic Acids Research 14(13):5125–5143. doi:10.1093/nar/14.13.5125 — RSCU.
  • Sharp PM, Li W-H (1987). The codon adaptation index — a measure of directional synonymous codon usage bias, and its potential applications. Nucleic Acids Research 15(3):1281–1295. doi:10.1093/nar/15.3.1281 — CAI.
  • Coleman JR, Papamichail D, Skiena S, Futcher B, Wimmer E, Mueller S (2008). Virus attenuation by genome-scale changes in codon pair bias. Science 320(5884):1784–1787. doi:10.1126/science.1155761 — codon-pair bias.
  • Cole ST, Brosch R, Parkhill J, et al. (1998). Deciphering the biology of Mycobacterium tuberculosis from the complete genome sequence. Nature 393(6685):537–544. doi:10.1038/31159 — the 65.6% G+C figure used as the external anchor above.
  • NCBI E-utilities, esearch and efetch against db=nucleotide — the sequence source for every table.

Implementation: engine/codon_builder.py (tally), engine/codon.py (RSCU, CAI, CPS), engine/codon_table_refresh.py (staleness and stamping). Data: data/codon_tables/. Back to the reference →