3126025a52d8ee7cd03a13869722f78f996063ad
max
  Fri Jul 10 04:52:16 2026 -0700
Fix codon mouseover protein position: 1-based single p. and singular label

The zoomed-in codon mouseover printed the protein position as a 0-based
two-position range, e.g. the first codon read c.1-3 (p.0-1). A codon is a
single amino acid, and p. should be 1-based to match the adjacent c.
numbering, so it now reads c.1-3 (p.1). Also corrected the label from the
plural Codons to Codon since each mouseover covers one codon.

refs #37773

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index 692a941230b..704ac6cd420 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -3092,50 +3092,51 @@
                                 if (w > 0)
                                     {
                                     // temporarily remove the mouseOver from the lf, since linkedFeatureMapItem will always 
                                     // prefer a lf->mouseOver over the itemName
                                     char *oldMouseOver = lf->mouseOver;
                                     lf->mouseOver = NULL;
                                     dyStringClear(codonDy);
                                     // if you change this text, make sure you also change hgTracks.js:mouseOverToLabel
                                     if (!isEmpty(existingText))
                                         dyStringPrintf(codonDy, "<b>Transcript: </b> %s<br>", existingText);
                                     int codonHgvsIx = (codon->codonIndex - 1) * 3;
                                     if (codonHgvsIx >= 0)
                                         {
                                         int cStart = codonHgvsIx + 1;
                                         int cEnd = codonHgvsIx + 3;
-                                        int pStart = codonHgvsIx / 3;
+                                        // a codon is a single amino acid; p. is 1-based like c.
+                                        int pPos = codonHgvsIx / 3 + 1;
                                         // the one-letter amino acid was stored on the codon when it
                                         // was translated (cds.c); map it to its three-letter code
                                         char aaLetter = codon->codonAa;
                                         char aaAbbr[8];
                                         char *aaName = NULL;
                                         if (aaLetter == '*')
                                             {
                                             safecpy(aaAbbr, sizeof(aaAbbr), "Ter");
                                             aaName = "termination";
                                             }
                                         else if (aaLetter == 'X')  // error/partial codon: nothing to show
                                             aaAbbr[0] = '\0';
                                         else
                                             {
                                             aaToAbbr(aaLetter, aaAbbr, sizeof(aaAbbr));
                                             aaName = aaToName(aaLetter);
                                             }
-                                        dyStringPrintf(codonDy, "<b>Codons: </b> c.%d-%d (p.%d-%d)<br>",
-                                                cStart, cEnd, pStart, pStart+1);
+                                        dyStringPrintf(codonDy, "<b>Codon: </b> c.%d-%d (p.%d)<br>",
+                                                cStart, cEnd, pPos);
                                         if (!isEmpty(aaAbbr))
                                             {
                                             if (aaName != NULL)
                                                 dyStringPrintf(codonDy, "<b>Amino acid: </b> %s - %s<br>", aaAbbr, aaName);
                                             else
                                                 dyStringPrintf(codonDy, "<b>Amino acid: </b> %s<br>", aaAbbr);
                                             }
                                         }
                                     // if you change the text below, also change hgTracks:mouseOverToExon
                                     dyStringPrintf(codonDy, "<b>Strand: </b> %s<br><b>Exon: </b>%s %d of %d&nbsp;&nbsp;<b>Length: </b>%d bp<br>%s",
                                                 strandStr, exonIntronText, exonIntronNumber, numExonIntrons, e - s, phaseText);
                                     tg->mapItem(tg, hvg, item, codonDy->string, tg->mapItemName(tg, item),
                                             sItem, eItem, codonsx, y, w, heightPer);
                                     // and restore the mouseOver
                                     lf->mouseOver = oldMouseOver;