4aa77873cb618e254b2f90d091d7bdef844947c2 max Wed Jul 8 04:28:42 2026 -0700 Let assembly hubs assign genetic codes per sequence for amino acid display Adds a "codonTable" genomes.txt setting, e.g. "codonTable default=1 NC_017929.1=13", so an assembly hub can pick the NCBI translation table used to show amino acids for each sequence. New hGeneticCodeForChrom(db, chrom) in hdb.c resolves the code (per-db cached), falling back to the previous behavior: chrM/chrMT use the vertebrate mitochondrial code, everything else the standard code. Wired into the two browser display paths, which both go through cds.c's baseColorLookupCodon: the base position track three-frame translation and codon-colored annotation tracks such as gene predictions (also PSL/BAM). Also used for the hgc SNP amino acid details, and genePredTranslate gains a db parameter (genePredToProt gains an optional -db flag) so command-line translation can honor the same setting. Documented in assemblyHubHelp.html. refs #16550 diff --git src/hg/lib/genePred.c src/hg/lib/genePred.c index 4410902f9f1..0cfbceddf36 100644 --- src/hg/lib/genePred.c +++ src/hg/lib/genePred.c @@ -2339,85 +2339,88 @@ int dir = (gp->strand[0] == '+') ? 1 : -1; int iExon = (dir > 0) ? 0 : gp->exonCount-1; int iStop = (dir > 0) ? gp->exonCount : -1; int exonCdsStart, exonCdsEnd; for (; iExon != iStop; iExon += dir) { if (genePredCdsExon(gp, iExon, &exonCdsStart, &exonCdsEnd)) addCdsExon(genomeSeqs, gp, exonCdsStart, exonCdsEnd, gp->exonFrames[iExon], &cds); } if (cds.nextFrame != 0) removePartialCodon(&cds); assert((strlen(cds.bases) % 3) == 0); // ;-) return cds.bases; } -static char translateCodon(boolean isChrM, char* codon, bool lastCodon, unsigned options) +static char translateCodon(struct geneticCode *code, char* codon, bool lastCodon, unsigned options) /* translate the first three bases starting at codon, handling weird * biology as requested giving */ { -char aa = isChrM ? lookupMitoCodon(codon) : lookupCodon(codon); +char aa = lookupCodonInCode(code, codon); if (aa == '\0') { // stop, contains `N' or selenocysteine boolean isStopOrSelno = isStopCodon(codon); boolean isRealStop = isReallyStopCodon(codon, !lastCodon); // internal could be selenocysteine if (lastCodon) { if ((options & GENEPRED_TRANSLATE_INCLUDE_STOP) != 0) aa = '*'; else if (!isRealStop) aa = 'X'; // others, \0' will terminate } else if (((options & GENEPRED_TRANSLATE_SELENO) != 0) && isStopOrSelno && !isRealStop) aa = 'U'; else if (isRealStop && ((options & GENEPRED_TRANSLATE_STAR_INFRAME_STOPS) != 0)) aa = '*'; else aa = 'X'; } return aa; } -static char* translateCds(char* chrom, char* cds, unsigned options) -/* translate the CDS */ +static char* translateCds(char *db, char* chrom, char* cds, unsigned options) +/* translate the CDS using the genetic code assigned to chrom in db (an + * assembly hub may set this; chrM/chrMT default to the mitochondrial code). */ { int cdsLen = strlen(cds); char *prot = needMem((cdsLen/3)+1); -boolean isChrM = isMito(chrom); +struct geneticCode *code = hGeneticCodeForChrom(db, chrom); int iCds, iProt; for (iCds = 0, iProt = 0; iCds < cdsLen; iCds+=3, iProt++) - prot[iProt] = translateCodon(isChrM, cds+iCds, (iCds == cdsLen-3), options); + prot[iProt] = translateCodon(code, cds+iCds, (iCds == cdsLen-3), options); return prot; } void genePredTranslate(struct genePred *gp, struct nibTwoCache* genomeSeqs, unsigned options, - char **protRet, char **cdsRet) + char *db, char **protRet, char **cdsRet) /* Translate a genePred into a protein. It can also return the CDS part of the - * mRNA sequence. If the chrom is chrM, the mitochondrial translation tables are - * used. If protRet or cdsRet is NULL, those sequences are not returned. + * mRNA sequence. The genetic code is that assigned to gp->chrom in db (an + * assembly hub may set this; chrM/chrMT default to the mitochondrial code). + * db may be NULL, in which case only the chrM/chrMT default applies. + * If protRet or cdsRet is NULL, those sequences are not returned. */ { // note: code tests by genePredToProt bool haveFrames = (gp->exonFrames != NULL); if (!haveFrames) genePredAddExonFrames(gp); // assume correct frame if not included char* cds = getCdsCodons(gp, genomeSeqs); -char *prot = translateCds(gp->chrom, cds, options); +char *prot = translateCds(db, gp->chrom, cds, options); if (protRet != NULL) *protRet = prot; else freeMem(prot); if (cdsRet != NULL) *cdsRet = cds; else freeMem(cds); if (!haveFrames) freez(&gp->exonFrames); } void genePredToCds(struct genePred *gp, struct genbankCds *cds)