3d2299a0b9690e88341c660965d913ad105970f2 kent Sun Jul 3 15:03:16 2022 -0700 Improving caching behavior. Allowing it to cache less than a complete sequence. Handling reverse strand better. diff --git src/hg/hgTracks/cds.c src/hg/hgTracks/cds.c index c6cbe98..d9c24b9 100644 --- src/hg/hgTracks/cds.c +++ src/hg/hgTracks/cds.c @@ -1,36 +1,38 @@ /* cds.c - code for coloring of bases, codons, or alignment differences. */ + /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "hCommon.h" #include "hash.h" #include "jksql.h" #include "memalloc.h" #include "dystring.h" #include "memgfx.h" #include "hvGfx.h" #include "dnaseq.h" #include "dnautil.h" #include "hdb.h" #include "psl.h" #include "fa.h" #include "genePred.h" #include "cds.h" #include "genbank.h" #include "twoBit.h" +#include "cacheTwoBit.h" #include "hgTracks.h" #include "cdsSpec.h" #include "axt.h" #include "lrg.h" /* * WARNING: this code is incomprehensible: * - variables named codon often contain amino acids, not condons * - it does two passes, one undocumented function encodes both a * color and an amino acid into the struct simpleFeature grayIx * field and this is decoded in the second pass. * - baseColorDrawItem doesn't draw a item, it draws a single codon, * or a maybe even a single base. * - there are many assumptions and state shared between this module * and the simpleTracks.c. @@ -44,40 +46,93 @@ Color lighterShade(struct hvGfx *hvg, Color color, double percentLess); /* Find a color which is a percentless 'lighter' shade of color */ /* Forward declaration */ /* Array of colors used in drawing codons/bases/differences: */ Color cdsColor[CDS_NUM_COLORS]; boolean cdsColorsMade = FALSE; Color getCdsColor(int index) { assert(index < CDS_NUM_COLORS); return cdsColor[index]; } +boolean pslTargetToQueryRangeMap(struct psl *psl, int tStart, int tEnd, + int *retQStart, int *retQEnd) +/* Comes up with qStart/qEnd that corresponds to tStart/tEnd in psl. Returns + * FALSE if there's no corresponding part for target in query */ +{ +if (rangeIntersection(tStart, tEnd, psl->tStart, psl->tEnd) <= 0) + return FALSE; +int qStart = psl->qStart, qEnd = psl->qEnd; +boolean foundStart = FALSE, foundEnd = FALSE; +int lastBqEnd = psl->qStart; +int i; +for (i=0; i<psl->blockCount; ++i) + { + int bSize = psl->blockSizes[i]; + int bqStart = psl->qStarts[i]; + int bqEnd = bqStart + bSize; + int btStart = psl->tStarts[i]; + int btEnd = btStart + bSize; + if (!foundStart) + { + if (btStart <= tStart && tStart < btEnd) + { + qStart = bqStart + (tStart - btStart); + foundStart = TRUE; + } + else if (btStart >= tStart) + { + qStart = bqStart; + foundStart = TRUE; + } + } + if (!foundEnd) + { + if (btStart < tEnd && tEnd <= btEnd) + { + qEnd = bqStart + (tEnd - btStart); + foundEnd = TRUE; + break; + } + else if (btStart >= tEnd) + { + qEnd = lastBqEnd; + foundEnd = TRUE; + break; + } + } + lastBqEnd = bqEnd; + } +*retQStart = qStart; +*retQEnd = qEnd; +return TRUE; +} + + static void drawScaledBoxWithText(struct hvGfx *hvg, int chromStart, int chromEnd, double scale, int xOff, int y, int height, Color color, int score, MgFont *font, char *text, bool zoomed, int winStart, int maxPixels, boolean isCoding, boolean justifyString) /* Draw a box scaled from chromosome to window coordinates with a codon or set of 3 or less bases drawn in the box. */ { - /*first draw the box itself*/ drawScaledBox(hvg, chromStart, chromEnd, scale, xOff, y, height, color); /*draw text in box if space, and align properly for codons or DNA*/ if (zoomed) { int i; Color textColor = hvGfxContrastingColor(hvg, color); int x1, x2, w; x1 = round((double)(chromStart-winStart)*scale) + xOff; x2 = round((double)(chromEnd-winStart)*scale) + xOff; if (x2 >= maxPixels) x2 = maxPixels - 1; w = x2-x1; @@ -420,60 +475,67 @@ { Color ci = tg->itemColor(tg, lf, hvg); if (sameString(tickColor, "contrastingColor")) c = hvGfxContrastingColor(hvg, ci); else if (sameString(tickColor, "lighterShade")) c = lighterShade(hvg, ci, 1.5); } for (sf = lf->components; sf != NULL; sf = sf->next) { int s = max(winStart, sf->start); int e = min(winEnd, sf->end); if (s > winEnd || e < winStart) continue; if (e > s) { - int mrnaS = -1; + int mrnaS = -1, mrnaE = 0; if (psl) - mrnaS = convertCoordUsingPsl(s, psl); + { + // mrnaS = convertCoordUsingPsl(s, psl); + pslTargetToQueryRangeMap(psl, s, e, &mrnaS, &mrnaE); + } else + { mrnaS = sf->qStart + (s - sf->start); + } if(mrnaS >= 0) { int i; for (i=0; i < (e - s); i++) { if (qSeq->dna[mrnaS+i-qOffset] != winDna[s-winStart+i]) drawScaledBox(hvg, s+i, s+i+1, scale, xOff, y+1, heightPer-2, c); } } } } } -static void maskDiffString( char *retStr, char *s1, char *s2, char mask ) +static void maskDiffString( char *retStr, char *s1, char *s2, char mask, int size) /*copies s1, masking off similar characters, and returns result into retStr. *if strings are of different size it stops after s1 is done.*/ { -int s1Len = strlen(s1); -memset(retStr, mask, s1Len); +memset(retStr, mask, size); int i; -for (i=0; i < s1Len; i++) +for (i=0; i < size; i++) + { + char c = s1[i]; + if (c != s2[i]) { - if (s1[i] != s2[i]) - retStr[i] = s1[i]; + retStr[i] = c; + } } retStr[i] = '\0'; } Color lighterShade(struct hvGfx *hvg, Color color, double percentLess) /* Get lighter shade of a color, with a variable level */ { struct rgbColor rgbColor = hvGfxColorIxToRgb(hvg, color); rgbColor.r = (int)((rgbColor.r+127)/percentLess); rgbColor.g = (int)((rgbColor.g+127)/percentLess); rgbColor.b = (int)((rgbColor.b+127)/percentLess); return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b); } @@ -980,72 +1042,45 @@ /* seqSource is: extFile seqTbl extFileTbl */ static struct dyString *buf = NULL; if (buf == NULL) buf = dyStringNew(0); dyStringClear(buf); dyStringAppend(buf, seqSource); char *words[3]; int nwords = chopByWhite(buf->string, words, ArraySize(words)); if ((nwords != ArraySize(words)) || !sameString(words[0], "extFile")) errAbort("invalid %s track setting: %s", BASE_COLOR_USE_SEQUENCE, seqSource); return hDnaSeqGet(database, name, words[1], words[2]); } -static struct dnaSeq *fetchCachedTwoBitSeq(char *url, char *seqName, boolean doRc) +static struct dnaSeq *fetchCachedTwoBitSeq(char *url, char *seqName, + int seqStart, int seqEnd, boolean doRc, int *retSeqOffset) /* fetch a sequence from a 2bit. Caches open two bit files and sequence in * both forward and reverse strand */ { -/* Init static url hash */ -static struct hash *urlHash = NULL; // hash of open files -if (urlHash == NULL) - urlHash = hashNew(0); - -/* Get cache for a particular two bit URL */ -struct twoBitCache -/* An open two bit file and a hash of sequences in it */ - { - struct twoBitFile *tbf; - struct hash *seqHash; - struct hash *rcSeqHash; - }; -struct twoBitCache *cache = hashFindVal(urlHash, url); +/* Init static url cache */ +static struct cacheTwoBitRanges *cache = NULL; // hash of open files if (cache == NULL) - { - AllocVar(cache); - cache->tbf = twoBitOpen(url); - cache->seqHash = hashNew(0); - cache->rcSeqHash = hashNew(0); - hashAdd(urlHash, url, cache); - } -struct hash *seqHash = (doRc ? cache->rcSeqHash : cache->seqHash); -struct dnaSeq *seq = hashFindVal(seqHash, seqName); - -if (seq == NULL) - { - seq = twoBitReadSeqFrag(cache->tbf, seqName, 0, 0); - touppers(seq->dna); - if (doRc) - reverseComplement(seq->dna, seq->size); - hashAdd(seqHash, seqName, seq); - } -return seq; + cache = cacheTwoBitRangesNew(TRUE); +return cacheTwoBitRangesMayFetch(cache, url, seqName, seqStart, seqEnd, doRc, retSeqOffset); } -static struct dnaSeq *maybeGetSeqUpper(struct linkedFeatures *lf, char *mrnaName, - char *tableName, struct track *tg, boolean doRc) +static struct dnaSeq *maybeGetSeqUpper(struct linkedFeatures *lf, + char *mrnaName, int mrnaStart, int mrnaEnd, + char *tableName, struct track *tg, boolean doRc, int *retMrnaOffset) /* Look up the sequence in genbank tables (hGenBankGetMrna also searches * seq if it can't find it in GB tables) or user's blat sequence, * uppercase and return it if we find it, return NULL if we don't find it. */ { boolean doUpper = TRUE; struct dnaSeq *mrnaSeq = NULL; char *name = getItemDataName(tg, mrnaName); if (sameString(tableName,"refGene") || sameString(tableName,"refSeqAli")) mrnaSeq = hGenBankGetMrna(database, name, "refMrna"); else { char *seqSource = trackDbSetting(tg->tdb, BASE_COLOR_USE_SEQUENCE); if (seqSource != NULL) { if (sameString(seqSource, "ss")) @@ -1076,31 +1111,31 @@ errAbort("baseColorDrawSetup: sequence for track '%s' not loaded when sequence option is set in trackDb\n", tg->track); mrnaSeq = newDnaSeq(cloneString(lf->extra), strlen(lf->extra), lf->extra); if (lf->orientation == -1) reverseComplement(mrnaSeq->dna, mrnaSeq->size); } else if (sameString("lrg", seqSource)) { struct lrg *lrg = lf->original; mrnaSeq = lrgReconstructSequence(lrg, database); } else if (sameString("2bit", seqSource)) { char *url = trackDbSetting(tg->tdb, "otherTwoBitUrl"); if (url == NULL) errAbort("missing otherTwoBitUrl in baseColorUseSequence 2bit trackDb setting"); - mrnaSeq = fetchCachedTwoBitSeq(url, name, doRc); + mrnaSeq = fetchCachedTwoBitSeq(url, name, mrnaStart, mrnaEnd, doRc, retMrnaOffset); doRc = FALSE; // Handled it already doUpper = FALSE; // Handled it already } else if (startsWith("table ", seqSource)) { char *table = seqSource; nextWord(&table); mrnaSeq = hGenBankGetMrna(database, name, table); } else if (startsWithWord("db", seqSource)) { char *sourceDb = seqSource; nextWord(&sourceDb); if (isEmpty(sourceDb)) sourceDb = database; @@ -1477,31 +1512,31 @@ starts[i] < winEnd && exonStart > winStart) { AllocVar(sf); sf->start = starts[i]; sf->end = exonStart; slAddHead(&sfList, sf); } } // end loop on exons if(posStrand) slReverse(&sfList); return(sfList); } -static void getMrnaBases(struct psl *psl, struct dnaSeq *mrnaSeq, +static void getMrnaBases(struct psl *psl, struct dnaSeq *mrnaSeq, int mrnaOffset, int mrnaS, int s, int e, boolean isRc, char retMrnaBases[4], boolean *retQueryInsertion) /* Get mRNA bases for the current mRNA codon triplet. If this is a split * codon, retrieve the adjacent mRNA bases to make a full triplet. */ { int size = e - s; if(size < 3) { if (mrnaSeq != NULL && mrnaS-(3-size) > 0) { int i=0; int idx = -1; int newIdx = -1; unsigned *gaps = NULL; boolean appendAtStart = FALSE; @@ -1523,80 +1558,89 @@ else if (e == tEnd) { idx = i+1; appendAtStart = FALSE; break; } } getHiddenGaps(psl, gaps); if(idx >= 0 && gaps[idx] > 0 && retQueryInsertion != NULL) *retQueryInsertion = TRUE; if (!appendAtStart) { newIdx = mrnaS + size; - memcpy(retMrnaBases, &mrnaSeq->dna[mrnaS], size); - memcpy(retMrnaBases+size, &mrnaSeq->dna[newIdx], 3-size); + memcpy(retMrnaBases, &mrnaSeq->dna[mrnaS - mrnaOffset], size); + memcpy(retMrnaBases+size, &mrnaSeq->dna[newIdx - mrnaOffset], 3-size); } else { newIdx = mrnaS - (3 - size); - memcpy(retMrnaBases, &mrnaSeq->dna[newIdx], 3); + memcpy(retMrnaBases, &mrnaSeq->dna[newIdx - mrnaOffset], 3); } } else { memcpy(retMrnaBases, "NNN", 3); } } else - memcpy(retMrnaBases, &mrnaSeq->dna[mrnaS], 3); + memcpy(retMrnaBases, &mrnaSeq->dna[mrnaS - mrnaOffset], 3); retMrnaBases[3] = '\0'; if (isRc) reverseComplement(retMrnaBases, strlen(retMrnaBases)); } static void drawDiffTextBox(struct hvGfx *hvg, int xOff, int y, double scale, int heightPer, MgFont *font, Color color, char *chrom, unsigned s, unsigned e, struct simpleFeature *sf, struct psl *psl, - struct dnaSeq *mrnaSeq, struct linkedFeatures *lf, + struct dnaSeq *mrnaSeq, int mrnaOffset, struct linkedFeatures *lf, int grayIx, enum baseColorDrawOpt drawOpt, int maxPixels, Color *trackColors, Color ixColor) { -int mrnaS = -1; +int mrnaS = -1, mrnaE = -1; +/* Clip s and e to what is actually visible */ +if (s < winStart) s = winStart; +if (e > winEnd) e = winEnd; if (psl) - mrnaS = convertCoordUsingPsl( s, psl ); + pslTargetToQueryRangeMap(psl, max(psl->tStart, s), min(psl->tEnd, e), + &mrnaS, &mrnaE); else if (sf) mrnaS = sf->qStart; if (mrnaS >= 0) { + if (mrnaS < mrnaOffset) + { + warn("curious mrnaS %d < mrnaOffest %d\n", mrnaS, mrnaOffset); + mrnaS = mrnaOffset; + } struct dyString *dyMrnaSeq = dyStringNew(256); char mrnaBases[4]; char genomicCodon[2]; char mrnaCodon[2]; boolean queryInsertion = FALSE; boolean isCoding = (drawOpt == baseColorDrawItemCodons || drawOpt == baseColorDrawDiffCodons); mrnaBases[0] = '\0'; if (psl && isCoding) - getMrnaBases(psl, mrnaSeq, mrnaS, s, e, (lf->orientation == -1), + getMrnaBases(psl, mrnaSeq, mrnaOffset, mrnaS, s, e, (lf->orientation == -1), mrnaBases, &queryInsertion); if (queryInsertion && isCoding) color = cdsColor[CDS_QUERY_INSERTION]; - dyStringAppendN(dyMrnaSeq, (char*)&mrnaSeq->dna[mrnaS], e-s); + dyStringAppendN(dyMrnaSeq, (char*)&mrnaSeq->dna[mrnaS - mrnaOffset], e-s); if (drawOpt == baseColorDrawItemBases) { if (cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE)) complement(dyMrnaSeq->string, dyMrnaSeq->stringSize); drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, color, lf->score, font, dyMrnaSeq->string, zoomedToBaseLevel, winStart, maxPixels, isCoding, TRUE); } else if (drawOpt == baseColorDrawItemCodons) { if (e <= lf->tallEnd) { boolean startColor = FALSE; /* re-set color of this block based on mrna codons rather than @@ -1610,31 +1654,32 @@ if (startColor && sameString(mrnaCodon,"M")) color = cdsColor[CDS_START]; drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, color, lf->score, font, mrnaCodon, zoomedToCodonLevel, winStart, maxPixels, isCoding, TRUE); } else drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color); } else if (drawOpt == baseColorDrawDiffBases) { char *diffStr = NULL; char *genoDna = getCachedDna(s, e); diffStr = needMem(sizeof(char) * (e - s + 1)); - maskDiffString(diffStr, dyMrnaSeq->string, genoDna, ' '); + maskDiffString(diffStr, dyMrnaSeq->string, genoDna, ' ', dyMrnaSeq->stringSize); + // fprintf(stderr, "drawOpt =- diffBases. %d %d %d %d\n", (int)strlen(genoDna), (int)strlen(dyMrnaSeq->string), (int)dyMrnaSeq->stringSize, e-s); if (cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE)) complement(diffStr, strlen(diffStr)); drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, color, lf->score, font, diffStr, zoomedToBaseLevel, winStart, maxPixels, isCoding, TRUE); freeMem(diffStr); } else if (drawOpt == baseColorDrawDiffCodons) { if (e <= lf->tallEnd) { /* Color codons red wherever mrna differs from genomic; * keep the odd/even cycle of dark/light shades. */ colorAndCodonFromGrayIx(hvg, genomicCodon, grayIx, ixColor); int mrnaGrayIx = mrnaCodonToGrayIx(mrnaBases, genomicCodon[0], @@ -1652,42 +1697,45 @@ winStart, maxPixels, isCoding, TRUE); } else drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color); } else drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color); } else if (drawOpt != baseColorDrawCds) errAbort("Unknown drawOpt: %d<br>\n", drawOpt); dyStringFree(&dyMrnaSeq); } else { + if (s < e) + { /*show we have an error by coloring entire exon block yellow*/ drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, MG_YELLOW); // FIXME: this shouldn't ever happen, should be an errAbort warn("Bug: drawDiffTextBox: convertCoordUsingPsl failed<br>\n"); } } +} void baseColorDrawItem(struct track *tg, struct linkedFeatures *lf, int grayIx, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, int s, int e, int heightPer, boolean zoomedToCodonLevel, - struct dnaSeq *mrnaSeq, int qOffset, struct simpleFeature *sf, struct psl *psl, + struct dnaSeq *qSeq, int qOffset, struct simpleFeature *sf, struct psl *psl, enum baseColorDrawOpt drawOpt, int maxPixels, int winStart, Color originalColor) /* Draw codon/base-colored item. */ { char codon[64] = " "; Color color = colorAndCodonFromGrayIx(hvg, codon, grayIx, originalColor); if (sf->codonIndex && ( e - s >= 3)) // don't put exon numbers on split codons because there isn't space. safef(codon, sizeof(codon), "%c %d", codon[0], sf->codonIndex); /* When we are zoomed out far enough so that multiple bases/codons share the * same pixel, we have to draw differences in a separate pass (baseColorOverdrawDiff) * so don't waste time drawing the differences here: */ boolean zoomedOutToPostProcessing = ((drawOpt == baseColorDrawDiffBases && !zoomedToBaseLevel) || (drawOpt == baseColorDrawDiffCodons && !zoomedToCdsColorLevel)); @@ -1697,64 +1745,63 @@ if (lf->highlightColor) { drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, lf->highlightColor); drawScaledBoxWithText(hvg, s, e, scale, xOff, y+1, heightPer-2, color, lf->score, font, codon, zoomedToCodonLevel, winStart, maxPixels, TRUE, !sf->codonIndex); } else { drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, color, lf->score, font, codon, zoomedToCodonLevel, winStart, maxPixels, TRUE, !sf->codonIndex); } } -else if (mrnaSeq != NULL && (psl != NULL || sf != NULL) && !zoomedOutToPostProcessing && +else if (qSeq != NULL && (psl != NULL || sf != NULL) && !zoomedOutToPostProcessing && drawOpt != baseColorDrawGenomicCodons && drawOpt != baseColorDrawOff) { if (lf->highlightColor) { drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, lf->highlightColor); drawDiffTextBox(hvg, xOff+1, y+1, scale, heightPer-2, font, - color, chromName, s, e, sf, psl, mrnaSeq, lf, + color, chromName, s, e, sf, psl, qSeq, qOffset, lf, grayIx, drawOpt, maxPixels, tg->colorShades, originalColor); } else { drawDiffTextBox(hvg, xOff, y, scale, heightPer, font, - color, chromName, s, e, sf, psl, mrnaSeq, lf, + color, chromName, s, e, sf, psl, qSeq, qOffset, lf, grayIx, drawOpt, maxPixels, tg->colorShades, originalColor); } } else { /* revert to normal coloring */ if (lf->highlightColor) { drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, lf->highlightColor); drawScaledBox(hvg, s, e, scale, xOff+1, y+1, heightPer -2, color); } else { - drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, - color); + drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color); } } } static void drawCdsDiffCodonsOnly(struct track *tg, struct linkedFeatures *lf, struct hvGfx *hvg, int xOff, int y, double scale, int heightPer, struct dnaSeq *qSeq, int qOffset, struct psl *psl, int winStart) /* Draw red boxes only where mRNA codons differ from genomic. This assumes * that lf has been drawn already, we're zoomed out past zoomedToCdsColorLevel, * we're not in dense mode etc. */ { struct simpleFeature *sf = NULL; @@ -1770,31 +1817,31 @@ if (s < lf->tallStart) s = lf->tallStart; if (e > lf->tallEnd) e = lf->tallEnd; if (s > winEnd || e < winStart) continue; if (e > s) { int mrnaS = convertCoordUsingPsl( s, psl ); if (mrnaS >= 0) { char mrnaBases[4]; char genomicCodon[2], mrnaCodon; boolean queryInsertion = FALSE; Color color = cdsColor[CDS_STOP]; - getMrnaBases(psl, qSeq, mrnaS, s, e, (lf->orientation == -1), + getMrnaBases(psl, qSeq, qOffset, mrnaS, s, e, (lf->orientation == -1), mrnaBases, &queryInsertion); if (queryInsertion) color = cdsColor[CDS_QUERY_INSERTION]; mrnaCodon = baseColorLookupCodon(mrnaBases); colorAndCodonFromGrayIx(hvg, genomicCodon, sf->grayIx, dummyColor); if (queryInsertion) drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color); if (mrnaCodon != genomicCodon[0]) { if (mrnaCodon != genomicCodon[0] && protEquivalent(genomicCodon[0], mrnaCodon)) color = cdsColor[CDS_SYN_PROT]; /* this was a call to drawScaledBoxBlend, but this breaks under * 32-bit color, so for the moment we're going to depend * on the painter's algorithm */ drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color); @@ -2110,70 +2157,77 @@ { enum baseColorDrawOpt drawOpt = baseColorGetDrawOpt(tg); boolean indelShowDoubleInsert, indelShowQueryInsert, indelShowPolyA; indelEnabled(cart, (tg ? tg->tdb : NULL), basesPerPixel, &indelShowDoubleInsert, &indelShowQueryInsert, &indelShowPolyA); if (drawOpt <= baseColorDrawOff && !(indelShowQueryInsert || indelShowPolyA)) return drawOpt; checkTrackInited(tg, "calling baseColorDrawSetup"); /* If we are using item sequence, fetch alignment and sequence: */ struct psl *psl = NULL; struct dnaSeq *mrnaSeq = NULL; int mrnaOffset = 0; +int mrnaStart = 0, mrnaEnd = 0; if (indelShowQueryInsert || indelShowPolyA || drawOpt > baseColorDrawOff) { char *type = tg->tdb->type; boolean needPsl = FALSE; char *qName = lf->name; if (sameString("lrg", tg->tdb->track)) { psl = lrgToPsl(lf->original, hChromSize(database, chromName)); needPsl = TRUE; } else if (startsWith("psl", type) || sameString("bigPsl", type) || startsWithWord("bam", type)) { psl = (struct psl *)(lf->original); needPsl = TRUE; } else if (startsWithWord("chain", type) || startsWithWord("bigChain", type)) { qName = cloneFirstWord(lf->name); psl = linkedFeatureToPsl(lf, qName, chromName, hChromSize(database, chromName)); needPsl = TRUE; } boolean doRc = FALSE; if (needPsl) { if (psl == NULL) drawOpt = baseColorDrawOff; else + { doRc = (psl->strand[0] == '-' || psl->strand[1] == '-'); + pslTargetToQueryRangeMap(psl, max(psl->tStart, winStart), min(psl->tEnd, winEnd), + &mrnaStart, &mrnaEnd); + } } /* Do we need the sequence for display, if so get it */ if (drawOpt == baseColorDrawItemBases || drawOpt == baseColorDrawDiffBases || drawOpt == baseColorDrawItemCodons || drawOpt == baseColorDrawDiffCodons || indelShowPolyA) { - mrnaSeq = maybeGetSeqUpper(lf, qName, tg->table, tg, doRc); + mrnaSeq = maybeGetSeqUpper(lf, qName, mrnaStart, mrnaEnd, tg->table, tg, doRc, &mrnaOffset); if (mrnaSeq == NULL) + { drawOpt = baseColorDrawOff; } } + } *retPsl = psl; *retMrnaSeq = mrnaSeq; *retMrnaOffset = mrnaOffset; return drawOpt; } void baseColorDrawRulerCodons(struct hvGfx *hvg, struct simpleFeature *sfList, double scale, int xOff, int y, int height, MgFont *font, int winStart, int maxPixels, bool zoomedToText) /* Draw amino acid translation of genomic sequence based on a list of codons. Used for browser ruler in full mode*/ { struct simpleFeature *sf; if (!cdsColorsMade)