f4745cea41950290d1b583f7292996a4f1c09274 braney Fri May 12 16:25:44 2023 -0700 some small tweaks to make sequence logo letters easier to read if zoomed way in, or the viewing range is restricted to a small range. diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c index 62e2573..f19cb0e 100644 --- src/hg/hgTracks/wigTrack.c +++ src/hg/hgTracks/wigTrack.c @@ -1266,38 +1266,44 @@ else { probVals[0].nuc = "A"; probVals[0].color = MG_RED; probVals[1].nuc = "C"; probVals[1].color = MG_BROWN; probVals[2].nuc = "G"; probVals[2].color = MG_BLUE; probVals[3].nuc = "T"; probVals[3].color = MG_GREEN; } probList = probVals; // a sortable list } double xIncr = (double)width / numBases; +int baseWidth = xIncr; +int letterWidth = baseWidth - 1; +if (h < letterWidth) + letterWidth = h; unsigned baseNum; + for(baseNum = 0; baseNum < numBases; baseNum++) { int x1 = ceil(baseNum * xIncr); int x = x1 + xOff; - int baseWidth = xIncr; int base = seq->dna[baseNum]; - int preDrawIndex = x1 + preDrawZero; + // grab our data value from the middle of a zoomed-in region because the edges may be rounded off + // by the math function + int preDrawIndex = ceil(x1 + xIncr/2) + preDrawZero; struct preDrawElement *p = &preDraw[preDrawIndex]; assert(x1/pixelBins->binSize < pixelBins->binCount); unsigned long *bitCount = &pixelBins->bins[x1/pixelBins->binSize]; /* count is non-zero meaning valid data exists here */ if (p->count) { /* data value has been picked by previous scanning. * Could be smoothed, maybe not. */ double dataValue = p->smooth; /* save a number that represents how many pixels that would be set if we were drawing bars. * This may used for sorting later on */ @@ -1313,51 +1319,63 @@ * The Y axis is positive down, negative up. * * Taking a simple coordinate conversion from data space * to the graphing space, the data value is at: * h * ((graphUpperLimit - dataValue)/graphRange) * and a data value zero line is at: * h * (graphUpperLimit/graphRange) * These may end up to be negative meaning they are above * the upper graphing limit, or be very large, meaning they * are below the lower graphing limit. This is OK, the * clipping will be taken care of by the vgBox() function. */ if (vis == tvFull || vis == tvPack) { + double origDataValue = dataValue; // save our original data value to draw the "clipped" lines #define scaleHeightToPixels(val) (min(BIGNUM,(scaleFactor * (graphUpperLimit - (val)) + yOff))) #define doLine(image, x, y, height, color) {vLine(image, x, y, height, color); } { // since we're drawing a sequence logo, we want to scale by the part of the line within the clipping window if (dataValue > graphUpperLimit) dataValue = graphUpperLimit; else if (dataValue < graphLowerLimit) dataValue = graphLowerLimit; int y0 = graphUpperLimit * scaleFactor; int y1 = (graphUpperLimit - dataValue)*scaleFactor; if (yOffsets) { if (numTrack > 0) { y0 = (graphUpperLimit - yOffsets[(numTrack-1) * width + x1]) *scaleFactor; y1 = (graphUpperLimit - dataValue - yOffsets[(numTrack-1) * width + x1])*scaleFactor; } } int boxHeight = max(1,abs(y1 - y0)); + // if our viewing region is clipped on the lower end we need to shrink + // the box to fit all the letters into it + if (graphLowerLimit > 0 ) + boxHeight -= graphLowerLimit * scaleFactor; int boxTop = min(y1,y0); + if (graphUpperLimit < 0 ) + { + // if our viewing region is clipped on the upper end we need to shrink + // the box AND lower the bottom of the box to fit all the letters into it + boxHeight += graphUpperLimit * scaleFactor; + boxTop -= graphUpperLimit * scaleFactor; + } // positive data value exactly equal to Bottom pixel // make sure it draws at least a pixel there if (boxTop == h) boxTop = h - 1; unsigned color = MG_BLACK; char *setting; if (tg->tdb->parent && ((setting = trackDbSetting(tg->tdb->parent,"container")) != NULL) && startsWith("multiWig", setting)) { /* for multiwig display, use track colors */ if (dataValue < 0) color = tg->ixAltColor; else @@ -1395,56 +1413,56 @@ int thisHeight; // we want a sorted list so the most probable gets drawn on top probVals[0].prob = baseProbs[baseNum].aProb; probVals[1].prob = baseProbs[baseNum].cProb; probVals[2].prob = baseProbs[baseNum].gProb; probVals[3].prob = baseProbs[baseNum].tProb; slSort(&probList,probListCmp); int y = yOff+boxTop; struct probVal *pl = probList; for(; pl; pl = pl->next) { thisHeight = pl->prob * boxHeight; if (thisHeight) - hvGfxTextInBox(hvg, x, y, baseWidth - 1, thisHeight, + hvGfxTextInBox(hvg, x + (baseWidth - letterWidth)/2, y, letterWidth, thisHeight, pl->color, font, pl->nuc); y += thisHeight; } } else { if (dataValue < 0) { - hvGfxTextInBox(hvg, x, yOff+boxTop, baseWidth - 1, -boxHeight, + hvGfxTextInBox(hvg, x + (baseWidth - letterWidth)/2, yOff+boxTop, letterWidth, -boxHeight, color, font, string); } else { - hvGfxTextInBox(hvg, x, yOff+boxTop, baseWidth - 1, boxHeight, + hvGfxTextInBox(hvg, x + (baseWidth - letterWidth)/2, yOff+boxTop, letterWidth, boxHeight, color, font, string); } } } if (((boxTop+boxHeight) == 0) && !isnan(dataValue)) boxHeight += 1; } - double stackValue = dataValue; + double stackValue = origDataValue; - if ((yOffsets != NULL) && (numTrack > 0)) - stackValue += yOffsets[(numTrack-1) * width + x1]; + //if ((yOffsets != NULL) && (numTrack > 0)) + //stackValue += yOffsets[(numTrack-1) * width + x1]; if (stackValue > graphUpperLimit) { hvGfxLine(hvg, x, yOff, x+baseWidth, yOff, clipColor); } else if (stackValue < graphLowerLimit) { hvGfxLine(hvg, x, yOff + h - 1, x+baseWidth, yOff + h - 1, clipColor); } #undef scaleHeightToPixels /* No longer use this symbol */ } /* vis == tvFull || vis == tvPack */ } } /* for (x1 = 0; x1 < width; ++x1) */ return(mouseOverData); }