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/utils/genePredToProt/genePredToProt.c src/hg/utils/genePredToProt/genePredToProt.c
index d511fc6a1e0..9fccf685e14 100644
--- src/hg/utils/genePredToProt/genePredToProt.c
+++ src/hg/utils/genePredToProt/genePredToProt.c
@@ -1,114 +1,120 @@
 /* genePredToProt - create protein sequences by translating gene annotations. */
 #include "common.h"
 #include "linefile.h"
 #include "hash.h"
 #include "options.h"
 #include "jksql.h"
 #include "genePred.h"
 #include "genePredReader.h"
 #include "nibTwo.h"
 #include "fa.h"
 
 void usage()
 /* Explain usage and exit. */
 {
 errAbort(
   "genePredToProt - create protein sequences by translating gene annotations\n"
   "usage:\n"
   "   genePredToProt genePredFile genomeSeqs protFa\n\n"
   "This honors frame if genePred has frames, dropping partial codons.\n"
   "genomeSeqs is a 2bit or directory of nib files.\n\n"
   "options:\n"
   "  -cdsFa=fasta - output FASTA with CDS that was used to generate protein.\n"
   "                 This will not include dropped partial codons.\n"
   "  -protIdSuffix=str - add this string to the end of the name for protein FASTA\n"
   "  -cdsIdSuffix=str - add this string to the end of the name for CDS FASTA\n"
   "  -translateSeleno - assume internal TGA code for selenocysteine and translate to `U'.\n"
   "  -includeStop - If the CDS ends with a stop codon, represent it as a `*'\n"
   "  -starForInframeStops - use `*' instead of `X' for in-frame stop codons.\n"
   "                  This will result in selenocysteine's being `*', with only codons\n"
   "                  containing `N' being translated to `X'.  This doesn't include terminal\n"
   "                  stop\n"
+  "  -db=database - use the genetic codes assigned by this genome/assembly hub\n"
+  "                  (its genomes.txt \"codonTable\" line).  Without this, chrM/chrMT\n"
+  "                  use the mitochondrial code and all else the standard code.\n"
   );
 }
 
 /* Command line validation table. */
 static struct optionSpec options[] = {
     {"cdsFa", OPTION_STRING},
     {"protIdSuffix", OPTION_STRING},
     {"cdsIdSuffix", OPTION_STRING},
     {"translateSeleno", OPTION_BOOLEAN},
     {"includeStop", OPTION_BOOLEAN},
     {"starForInframeStops", OPTION_BOOLEAN},
+    {"db", OPTION_STRING},
     {NULL, 0},
 };
 
 static char *protIdSuffix = "";
 static char *cdsIdSuffix = "";
+static char *clDb = NULL;
 
 static void writeFa(struct genePred *gp, char* seq, FILE* faFh, char* suffix)
 /* write fasta record, generating comment with genomic location */
 {
 char startLine[512];
 safef(startLine, sizeof(startLine), "%s%s %s:%d-%d", gp->name, suffix,
       gp->chrom, gp->txStart, gp->txEnd);
 faWriteNext(faFh, startLine, seq, strlen(seq));
 }
 
 static void translateGenePred(struct genePred *gp, struct nibTwoCache* genomeSeqs,
                               unsigned options, FILE* protFaFh, FILE* cdsFaFh)
 /* translate one genePred record. */
 {
 char *cds, *prot;
-genePredTranslate(gp, genomeSeqs, options, &prot, &cds);
+genePredTranslate(gp, genomeSeqs, options, clDb, &prot, &cds);
 
 writeFa(gp, prot, protFaFh, protIdSuffix);
 if (cdsFaFh != NULL)
     writeFa(gp, cds, cdsFaFh, cdsIdSuffix);
 freeMem(prot);
 freeMem(cds);
 }
 
 void genePredToProt(char *genePredFile, char* genomeSeqsFile, unsigned options,
                     char* protFaFile, char *cdsFaFile)
 /* genePredToProt - create protein sequences by translating gene annotations. */
 {
 struct genePred *genePreds = genePredReaderLoadFile(genePredFile, NULL);
 struct nibTwoCache* genomeSeqs = nibTwoCacheNew(genomeSeqsFile);
 slSort(&genePreds, genePredCmp);  // genomic order is much faster
 FILE* protFaFh = mustOpen(protFaFile, "w");
 FILE* cdsFaFh = (cdsFaFile != NULL) ? mustOpen(cdsFaFile, "w") : NULL;
 
 struct genePred *gp;
 for (gp = genePreds; gp != NULL; gp = gp->next)
     {
     if (gp->cdsStart < gp->cdsEnd)
         translateGenePred(gp, genomeSeqs, options, protFaFh, cdsFaFh);
     }
 
 carefulClose(&protFaFh);
 carefulClose(&cdsFaFh);
 genePredFreeList(&genePreds);
 nibTwoCacheFree(&genomeSeqs);
 }
 
 int main(int argc, char *argv[])
 /* Process command line. */
 {
 optionInit(&argc, argv, options);
 if (argc != 4)
     usage();
 protIdSuffix = optionVal("protIdSuffix", ""),
 cdsIdSuffix = optionVal("cdsIdSuffix", "");
+clDb = optionVal("db", NULL);
 unsigned options = 0;
 if (optionExists("translateSeleno"))
     options |= GENEPRED_TRANSLATE_SELENO;
 if (optionExists("includeStop"))
     options |= GENEPRED_TRANSLATE_INCLUDE_STOP;
 if (optionExists("starForInframeStops"))
     options |= GENEPRED_TRANSLATE_STAR_INFRAME_STOPS;
 
 genePredToProt(argv[1], argv[2], options, argv[3],
                optionVal("cdsFa", NULL));
 return 0;
 }