DATA · METHODS
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.
| Kind | Files | Shape | Quantity |
|---|---|---|---|
| Species codon-usage table | 28 | {organism, n_cds, table} |
Within-family relative frequency of each of the 64 codons |
| Codon-pair (CPS) table | 5 | {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.
- Select. NCBI E-utilities
esearchagainstdb=nucleotidewith the term<Latin name>[orgn] AND biomol_mrna[PROP] AND refseq[filter],retmax = target_cds(default 250). - 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]withretmax = min(target_cds, 60). - Fetch.
efetchwithrettype=fasta_cds_na, in batches of 80 identifiers, 0.4 s apart. Sequences are upper-cased andUis rewritten toT. - 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_cdsis the number of sequences that passed. - Count. Every codon from the first to the second-to-last is counted. The initiator
ATGis counted; the terminal codon is not. A triplet containing any character outsideACGTis skipped without rejecting the sequence. - 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.
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.
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).
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:
The sequence's CAI is the geometric mean of the weights of its L codons:
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:
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:
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.
| File | Organism key | n_ref | Pairs observed | Coverage |
|---|---|---|---|---|
| cps_Homo sapiens.json | Homo sapiens | 0 | 0 | 0.0% |
| cps_chicken.json | chicken | 60 | 3,358 | 90.2% |
| cps_human.json | human | 40 | 2,853 | 76.7% |
| cps_mouse.json | mouse | 60 | 2,952 | 79.3% |
| cps_yeast.json | yeast | 60 | 2,807 | 75.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.
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 < 40is returned withlow_data = trueand a note that the table is approximate and a better-sequenced relative should be considered. - Declared proxy. An organism entry in
data/organisms.jsonmay carry aproxykey 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:
| Identity | Expected | Max deviation | Worst case |
|---|---|---|---|
| Σk fik | 1 | 2.00e-04 | elephant_asian/S |
| Σk RSCUik | ni | 1.20e-03 | elephant_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:
| Codon | Amino acid | Stored fraction | RSCU |
|---|---|---|---|
| TTC | Phe | 0.7924 | 1.585 |
| ATC | Ile | 0.8010 | 2.403 |
| CTG | Leu | 0.5228 | 3.137 |
| GCC | Ala | 0.4508 | 1.803 |
| CCG | Pro | 0.5491 | 2.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.
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,
esearchandefetchagainstdb=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 →