d540e9dca3211faf36fab80fa3b640d4bd6ee288 max Tue Jan 23 06:18:20 2024 -0800 adding phase mouseover, refs #32487 diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c index 0aca981..5d0d0c3 100644 --- src/hg/hgTracks/simpleTracks.c +++ src/hg/hgTracks/simpleTracks.c @@ -2830,43 +2830,46 @@ } else { exonText = trackDbSettingClosestToHomeOrDefault(tg->tdb, "exonText" , "Exon" ); intronText = trackDbSettingClosestToHomeOrDefault(tg->tdb, "intronText", "Intron"); } while (exon != NULL) /* Make a stupid list of exons separate from what's given. */ /* It seems like lf->components isn't necessarily sorted. */ { refAdd(&exonList, exon); exon = exon->next; } /* Now sort it. */ slSort(&exonList, exonSlRefCmp); + numExons = slCount(exonList); +struct genePred *gp = lf->original; boolean revStrand = (lf->orientation == -1); int eLast = -1; int s = -1; int e = -1; char mouseOverText[256]; boolean isExon = TRUE; int picStart = insideX; int picEnd = picStart + insideWidth; if (lButton) picStart += buttonW; if (rButton) picEnd -= buttonW; + for (ref = exonList; TRUE; ) { exon = ref->val; if (isExon) { s = exon->start; e = exon->end; } else { s = eLast; e = exon->start; } // skip exons and introns that are completely outside the window if (!(s > winEnd) || (e < winStart)) @@ -2898,40 +2901,85 @@ { exonIntronText = intronText; --numExonIntrons; // introns are one fewer than exons } char strandChar; if (!revStrand) { exonIntronNumber = exonIx; strandChar = '+'; } else { exonIntronNumber = numExonIntrons-exonIx+1; strandChar = '-'; } + // we still need to show the existing mouseover text char* existingText = lf->mouseOver; if (isEmpty(existingText)) existingText = lf->name; + // construct a string that tells the user about the codon frame situation of this exon + char *frameText = ""; + if (gp->exonFrames && isExon) + { + // start/end-phases are in the direction of transcription: + // if transcript is on + strand, the start phase is the exonFrame value, and the end phase is the next exonFrame (3' on DNA) value + // if transcript is on - strand, the start phase is the previous (=3' on DNA) exonFrame and the end phase is the exonFrame + int startPhase = gp->exonFrames[exonIx-1]; + int endPhase = -1; + if (!revStrand) + endPhase = gp->exonFrames[exonIx]; + else + if (exonIx>1) + endPhase = gp->exonFrames[exonIx-2]; + + if (gp->exonFrames[exonIx-1]==-1) // UTRs don't have a frame at all + { + frameText = ", untranslated region"; + } + else + { + //printf("%s %d %d %s_ex_%d_frame_%d<br>", chromName, s, e, gp->name, exonIx, startPhase); + char buf[256]; + char *exonNote = ""; + if (exonIntronNumber<numExons) // do not do this for the last exon (exonIx is 1-based) + { + //printf("exonIx %d, numExons %d<br>", exonIx, numExons); + ////int nextExonFrame = gp->exonFrames[nextExIx]; + //printf("nextExIx %d, nextExonFrame %d, endPhase %d<br>", nextExIx, nextExonFrame, endPhase); + + if (startPhase==endPhase) + exonNote = " → in-frame exon"; + safef(buf, sizeof(buf), ", start-end codon phase %d-%d%s", startPhase, endPhase, exonNote); + } + else + { + if (startPhase==0) + exonNote = " → in-frame exon"; + safef(buf, sizeof(buf), ", start codon phase %d%s", startPhase, exonNote); + } + frameText = buf; + } + } + if (!isEmpty(existingText)) - safef(mouseOverText, sizeof(mouseOverText), "%s, strand %c, %s %d of %d", - existingText, strandChar, exonIntronText, exonIntronNumber, numExonIntrons); + safef(mouseOverText, sizeof(mouseOverText), "%s, strand %c, %s %d of %d%s", + existingText, strandChar, exonIntronText, exonIntronNumber, numExonIntrons, frameText); else - safef(mouseOverText, sizeof(mouseOverText), "strand %c, %s %d of %d", - strandChar, exonIntronText, exonIntronNumber, numExonIntrons); + safef(mouseOverText, sizeof(mouseOverText), "strand %c, %s %d of %d%s", + strandChar, exonIntronText, exonIntronNumber, numExonIntrons, frameText); if (w > 0) // draw exon or intron if width is greater than 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; tg->mapItem(tg, hvg, item, mouseOverText, tg->mapItemName(tg, item), sItem, eItem, sx, y, w, heightPer); // and restore the mouseOver lf->mouseOver = oldMouseOver; picStart = ex; // prevent pileups. is this right? add 1? does it work? } }