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);
 }