Plant-DNA-Designer / cool /tools /build_codon_usage.py
Dinesh4311's picture
Add application code
aa752f5 verified
Raw
History Blame Contribute Delete
4.72 kB
"""Generate per-species codon-usage tables from real Kazusa CUTG data.
Reads ``core/data/cutg_plant_subset.spsum`` (the nuclear codon counts for the 18
supported crops, taken verbatim from the Kazusa Codon Usage Tabulated from
GenBank plant division) and writes ``core/codon_usage_tables.py`` containing:
CODON_USAGE_TABLES {species: {aa: {codon: fraction}}} real per-AA usage
SPECIES_CDS_COUNT {species: int} CDS compiled (provenance)
Every species therefore uses its OWN measured codon usage — no cross-species
proxies. Run from the ``cool/`` directory:
python -m tools.build_codon_usage
This keeps the data reproducible: the spsum subset is committed, and re-running
the generator reproduces the table module byte-for-byte.
"""
import os
from core.codons import CODON_TO_AMINO_ACID
HERE = os.path.dirname(os.path.abspath(__file__))
CORE = os.path.normpath(os.path.join(HERE, "..", "core"))
SUBSET = os.path.join(CORE, "data", "cutg_plant_subset.spsum")
OUT = os.path.join(CORE, "codon_usage_tables.py")
# CUTG / SPSUM codon order (RNA), per the SPSUM_LABEL file shipped with CUTG.
ORDER_RNA = ("CGA CGC CGG CGU AGA AGG CUA CUC CUG CUU UUA UUG UCA UCC UCG UCU AGC AGU "
"ACA ACC ACG ACU CCA CCC CCG CCU GCA GCC GCG GCU GGA GGC GGG GGU GUA GUC GUG GUU "
"AAA AAG AAC AAU CAA CAG CAC CAU GAA GAG GAC GAU UAC UAU UGC UGU UUC UUU "
"AUA AUC AUU AUG UGG UAA UAG UGA").split()
ORDER = [c.replace("U", "T") for c in ORDER_RNA]
assert len(ORDER) == 64
# amino-acid order for stable, readable output
AA_ORDER = list("ACDEFGHIKLMNPQRSTVWY") + ["_"]
def parse_subset(path):
species, counts, names = {}, {}, {}
cur = None
with open(path, errors="replace") as fh:
lines = [ln.rstrip("\n") for ln in fh]
i = 0
while i < len(lines):
ln = lines[i]
if ln.startswith("# species="):
cur = ln.split("=", 1)[1].strip()
elif cur and ln and ln[0].isdigit() and ":" in ln:
names[cur] = ln.split(":", 1)[1].rsplit(":", 1)[0].strip()
counts[cur] = int(ln.rsplit(":", 1)[1])
nums = list(map(int, lines[i + 1].split()))
assert len(nums) == 64, f"{cur}: expected 64 codon counts"
species[cur] = nums
i += 1
cur = None
i += 1
return species, counts, names
def to_usage(raw):
by_aa = {}
for codon, n in zip(ORDER, raw):
by_aa.setdefault(CODON_TO_AMINO_ACID[codon], {})[codon] = n
out = {}
for aa, cod in by_aa.items():
tot = sum(cod.values())
out[aa] = {c: (round(v / tot, 3) if tot else 0.0) for c, v in cod.items()}
return out
def fmt_table(usage):
rows = []
for aa in AA_ORDER:
if aa not in usage:
continue
inner = ", ".join(f"'{c}': {f:.3f}" for c, f in usage[aa].items())
rows.append(f" '{aa}': {{{inner}}},")
return "\n".join(rows)
def main():
species, counts, names = parse_subset(SUBSET)
order = ['arabidopsis', 'rice', 'maize', 'tomato', 'soybean', 'wheat', 'barley',
'sorghum', 'potato', 'cassava', 'tobacco', 'grape', 'cotton', 'sugarcane',
'canola', 'banana', 'peanut', 'sunflower']
lines = ['"""Per-species codon-usage tables — GENERATED, do not edit by hand.',
"",
"Source: Kazusa CUTG (Codon Usage Tabulated from GenBank), plant division.",
"Each table is the measured nuclear codon usage for that species' own taxid —",
"no cross-species proxies. Regenerate with: python -m tools.build_codon_usage",
"",
"SPECIES_CDS_COUNT records how many CDS were compiled per species (provenance /",
"confidence): larger = more reliable codon statistics.",
'"""',
"",
"CODON_USAGE_TABLES = {"]
for sp in order:
u = to_usage(species[sp])
lines.append(f" # {names[sp]} (taxid in subset; {counts[sp]:,} CDS compiled)")
lines.append(f" '{sp}': {{")
lines.append(fmt_table(u))
lines.append(" },")
lines.append("}")
lines.append("")
lines.append("SPECIES_CDS_COUNT = {")
for sp in order:
lines.append(f" '{sp}': {counts[sp]},")
lines.append("}")
lines.append("")
with open(OUT, "w") as fh:
fh.write("\n".join(lines))
print("wrote", os.path.relpath(OUT), "—", len(order), "species")
for sp in order:
print(f" {sp:12} {counts[sp]:>7,} CDS")
if __name__ == "__main__":
main()