85bd10da37f403d155c4434d90edcd146e682948
braney
  Mon May 15 13:03:32 2017 -0700
add sorting to composite wiggles.

diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c
index 24f6c7b..fabbf13 100644
--- src/hg/hgTracks/wigTrack.c
+++ src/hg/hgTracks/wigTrack.c
@@ -823,58 +823,60 @@
 return wgo;
 }
 
 struct wigGraphOutput *wigGraphOutputSolid(int xOff, int yOff, struct hvGfx *image)
 /* Get appropriate wigGraphOutput for non-transparent rendering */
 {
 struct wigGraphOutput *wgo;
 AllocVar(wgo);
 wgo->image = image;
 wgo->vLine = vLineViaHvg;
 wgo->xOff = xOff;
 wgo->yOff = yOff;
 return wgo;
 }
 
-static void graphPreDraw(struct preDrawElement *preDraw, int preDrawZero, int width,
+void graphPreDraw(struct preDrawElement *preDraw, int preDrawZero, int width,
     struct track *tg, void *image, WigVerticalLineVirtual vLine, int xOff, int yOff, double *yOffsets, int numTrack,
     double graphUpperLimit, double graphLowerLimit, double graphRange,
     double epsilon, Color *colorArray, enum trackVisibility vis,
-    struct wigCartOptions *wigCart)
+    struct wigCartOptions *wigCart, struct pixelCountBin *pixelBins)
 /*	graph the preDraw array */
 {
 int x1;
 int h = tg->lineHeight;	/*	the height of our drawing window */
 double scaleFactor = h/graphRange;
 Color oldDrawColor = colorArray[0] + 1;	/* Just to be different from 1st drawColor. */
 Color mediumColor = MG_BLACK;	// Will be overriden
 Color lightColor = MG_BLACK;	// Will be overriden
 Color clipColor = MG_MAGENTA;
 enum wiggleTransformFuncEnum transformFunc = wigCart->transformFunc;
 enum wiggleGraphOptEnum lineBar = wigCart->lineBar;
 boolean whiskers = (wigCart->windowingFunction == wiggleWindowingWhiskers
 			&& width < winEnd-winStart);
 
 /*	right now this is a simple pixel by pixel loop.  Future
  *	enhancements could draw boxes where pixels
  *	are all the same height in a run.
  */
 for (x1 = 0; x1 < width; ++x1)
     {
     int x = x1 + xOff;
     int preDrawIndex = x1 + preDrawZero;
     struct preDrawElement *p = &preDraw[preDrawIndex];
+    assert(x1/pixelBins->binSize < pixelBins->binCount);
+    unsigned long *bitCount = &pixelBins->bins[x1/pixelBins->binSize];
 
     Color drawColor = colorArray[x1];
     if (drawColor != oldDrawColor)
         {
 	mediumColor = somewhatLighterColor32(drawColor);
 	lightColor = somewhatLighterColor32(mediumColor);
 	oldDrawColor = drawColor;
         }
 
     /*	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.
 	 */
@@ -887,59 +889,60 @@
 	 *
 	 *	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)
             {
 #define scaleHeightToPixels(val) (min(BIGNUM,(scaleFactor * (graphUpperLimit - (val)) + yOff)))
+#define doLine(image, x, y, height, color) {vLine(image, x, y, height, color); *bitCount += height;}
 	    if (lineBar == wiggleGraphBar)
 		{
 		if (whiskers)
 		    {
 		    int zeroPos = max(0,scaleHeightToPixels(0));
 		    int scaledVal = scaleHeightToPixels(dataValue);
 		    double std = calcStdFromSums(p->sumData, p->sumSquares, p->count);
 		    double mean = p->sumData/p->count;
 
 		    if (dataValue < 0)
 		        {
 			int scaledMin = scaleHeightToPixels(doTransform(p->min, transformFunc));
 			int lightHeight = max(1,scaledMin-zeroPos);
 			int mediumHeight = lightHeight;
 			if (!isnan(std))
 			    { // Test needed due to bug in version 1.5 bigWiles
 			    double minus = doTransform(mean - std, transformFunc);
 			    int scaledMinus = scaleHeightToPixels(minus);
 			    mediumHeight = max(1,scaledMinus-zeroPos);
 			    }
 			int darkHeight = max(1,scaledVal-zeroPos);
 			if (zeroPos == (yOff+h))  // bottom pixel special case
 			    zeroPos -= 1;
 		        if (((zeroPos-yOff)+darkHeight) == 0)
 			    darkHeight += 1;	  // top pixel special case
-			vLine(image, x,zeroPos, darkHeight, drawColor);
-                        vLine(image, x, zeroPos+darkHeight, mediumHeight-darkHeight,
+			doLine(image, x,zeroPos, darkHeight, drawColor);
+                        doLine(image, x, zeroPos+darkHeight, mediumHeight-darkHeight,
 				mediumColor);
-                        vLine(image, x, zeroPos+mediumHeight, lightHeight-mediumHeight,
+                        doLine(image, x, zeroPos+mediumHeight, lightHeight-mediumHeight,
 				lightColor);
 			}
 		    else
 		        {
                         /* The calculations here are a little convoluted because
                          * of the history.  Originally it drew from the baseline
                          * up to the max first in the lightest color, then from the
                          * baseline to the mean+std in medium color, and finally
                          * from baseline to mean in dark color.  This ended up
                          * drawing the same pixels up to three times which messed
                          * things up in transparent overlay mode.   The code was
                          * refactored to accomplish this without having to worry
                          * about +/- 1 differences.   In particular be aware the
                          * xyzHeight calculations are done assuming the other end is
                          * the baseline. */
@@ -959,133 +962,137 @@
 			    double plus = doTransform(mean + std, transformFunc);
 			    int scaledPlus = scaleHeightToPixels(plus);
 			    int boxHeight = max(1,zeroPos-scaledPlus);
 			    mediumTop = scaledPlus, mediumHeight = boxHeight;
 			    }
 
 			/* Calculate light part from max. */
 			int scaledMax = scaleHeightToPixels(doTransform(p->max, transformFunc));
 			if (scaledMax == (h+yOff))
                             scaledMax = (h+yOff) - 1;
                         boxHeight = max(1,zeroPos-scaledMax);
                         int lightTop = scaledMax, lightHeight = boxHeight;
 
                         /* Draw, making sure not to overwrite pixels since
                          * would mess up transparent drawing. */
-                        vLine(image,x,darkTop, darkHeight, drawColor);
-			vLine(image, x, mediumTop, mediumHeight-darkHeight, mediumColor);
-			vLine(image,x,lightTop,lightHeight-mediumHeight, lightColor);
+                        doLine(image,x,darkTop, darkHeight, drawColor);
+			doLine(image, x, mediumTop, mediumHeight-darkHeight, mediumColor);
+			doLine(image,x,lightTop,lightHeight-mediumHeight, lightColor);
 			}
 		    }
 		else
 		    {
 		    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));
 		    int boxTop = min(y1,y0);
 
 		    //	positive data value exactly equal to Bottom pixel
 		    //  make sure it draws at least a pixel there
 		    if (boxTop == h)
 			boxTop = h - 1;
 
 		    // negative data value exactly equal to top pixel
 		    // make sure it draws something
 		    if ((boxTop+boxHeight) == 0)
 			boxHeight += 1;
-		    vLine(image,x, yOff+boxTop, boxHeight, drawColor);
+		    doLine(image,x, yOff+boxTop, boxHeight, drawColor);
 		    }
 		}
 	    else
 		{	/*	draw a 3 pixel height box	*/
 		if (whiskers)
 		    {
 		    int scaledMin = scaleHeightToPixels(doTransform(p->min, transformFunc));
 		    int scaledMax = scaleHeightToPixels(doTransform(p->max, transformFunc));
 		    double mean = p->sumData/p->count;
 		    int boxHeight = max(1,scaledMin - scaledMax);
-		    vLine(image, x, scaledMax, boxHeight, lightColor);
+		    doLine(image, x, scaledMax, boxHeight, lightColor);
 		    int scaledMean = scaleHeightToPixels(dataValue);
 		    double std = calcStdFromSums(p->sumData, p->sumSquares, p->count);
 		    if (!isnan(std))  // Test needed because of bug in version 1.5 bigWiles
 			{
 			int scaledPlus = scaleHeightToPixels(doTransform(mean+std, transformFunc));
 			int scaledMinus = scaleHeightToPixels(doTransform(mean-std, transformFunc));
 			int boxHeight = max(1,scaledMinus - scaledPlus);
-			vLine(image, x, scaledPlus, boxHeight, mediumColor);
+			doLine(image, x, scaledPlus, boxHeight, mediumColor);
 			}
-		    vLine(image, x, scaledMean, 1, drawColor);
+		    doLine(image, x, scaledMean, 1, drawColor);
 		    }
 		else
 		    {
 		    double y0 = dataValue;
 		    if ((yOffsets != NULL) && (numTrack > 0))
 			y0 += yOffsets[(numTrack-1) *  width + x1];
 		    int yPointGraph = scaleHeightToPixels(y0) - 1;
-		    vLine(image, x, yPointGraph, 3, drawColor);
+		    doLine(image, x, yPointGraph, 3, drawColor);
 		    }
 		}
 	    double stackValue = dataValue;
 
 	    if ((yOffsets != NULL) && (numTrack > 0))
 		stackValue += yOffsets[(numTrack-1) *  width + x1];
 	    if (stackValue > graphUpperLimit)
-		vLine(image, x, yOff, 2, clipColor);
+                {
+		doLine(image, x, yOff, 2, clipColor);
+                }
 	    else if (stackValue < graphLowerLimit)
-		vLine(image, x, yOff + h - 1, 2, clipColor);
+                {
+		doLine(image, x, yOff + h - 1, 2, clipColor);
+                }
 #undef scaleHeightToPixels	/* No longer use this symbol */
             }   /*	vis == tvFull || vis == tvPack */
         else if (vis == tvDense || vis == tvSquish)
 	    {
 	    double grayValue;
 	    int grayIndex;
 	    /* honor the viewLimits, data below is white, data above is black */
 	    grayValue = max(dataValue,graphLowerLimit);
 	    grayValue = min(grayValue,graphUpperLimit);
 	    grayIndex = ((grayValue-graphLowerLimit)/graphRange)*MAX_WIG_VALUE;
 
 	    drawColor =
 		tg->colorShades[grayInRange(grayIndex, 0, MAX_WIG_VALUE)];
-	    vLine(image, x, yOff, tg->lineHeight, drawColor);
+	    doLine(image, x, yOff, tg->lineHeight, drawColor);
             }   /*	vis == tvDense || vis == tvSquish	*/
 	}	/*	if (preDraw[].count)	*/
     }	/*	for (x1 = 0; x1 < width; ++x1)	*/
 }	/*	graphPreDraw()	*/
 
 static void graphPreDrawContainer(struct preDrawContainer *preDrawContainer, 
     int preDrawZero, int width, struct track *tg, struct hvGfx *hvg, 
     int xOff, int yOff, double graphUpperLimit, double graphLowerLimit, 
     double graphRange, enum trackVisibility vis, struct wigCartOptions *wigCart)
 /* Draw the graphs for all tracks in container. */
 {
 double epsilon = graphRange / tg->lineHeight;
 struct preDrawElement *preDraw = preDrawContainer->preDraw;
 Color *colorArray = makeColorArray(preDraw, width, preDrawZero, wigCart, tg, hvg);
 struct wigGraphOutput *wgo = tg->wigGraphOutput;
 graphPreDraw(preDraw, preDrawZero, width,
 	tg, wgo->image, wgo->vLine, wgo->xOff, wgo->yOff, wgo->yOffsets, wgo->numTrack,
 	graphUpperLimit, graphLowerLimit, graphRange,
-	epsilon, colorArray, vis, wigCart);
+	epsilon, colorArray, vis, wigCart, wgo->pixelBins);
 
 freez(&colorArray);
 }
 
 
 void drawZeroLine(enum trackVisibility vis,
     enum wiggleGridOptEnum horizontalGrid,
     double graphUpperLimit, double graphLowerLimit,
     struct hvGfx *hvg, int xOff, int yOff, int width, int lineHeight)
 /*	draw a line at y=0 on the graph	*/
 {
 /*	Do we need to draw a zero line ?
  *	This is to be generalized in the future to allow horizontal grid
  *	lines, perhaps user specified to indicate thresholds.
  */
@@ -1195,35 +1202,39 @@
     Span = ptToInt(el->val);
     if ((Span < basesPerPixel) && (Span > usingDataSpan))
 	usingDataSpan = Span;
     if (Span < minimalSpan)
 	minimalSpan = Span;
     }
 hashElFreeList(&elList);
 
 /*	There may not be a span of 1, use whatever is lowest	*/
 if (minimalSpan > usingDataSpan)
     usingDataSpan = minimalSpan;
 
 return usingDataSpan;
 }
 
-void wigTrackSetGraphOutputDefault(struct track *tg, int xOff, int yOff, struct hvGfx *hvg)
+void wigTrackSetGraphOutputDefault(struct track *tg, int xOff, int yOff, int width, struct hvGfx *hvg)
 /* Set up to draw on hvg if no other destination set already */
 {
 if (tg->wigGraphOutput == NULL)
+    {
     tg->wigGraphOutput = wigGraphOutputSolid(xOff, yOff, hvg);
+void AllocPixelBins(struct wigGraphOutput *wgo, int width);
+    AllocPixelBins(tg->wigGraphOutput, width);
+    }
 }
 
 void wigPreDrawPredraw(struct track *tg, int seqStart, int seqEnd,
                     struct hvGfx *hvg, int xOff, int yOff, int width,
                     MgFont *font, Color color, enum trackVisibility vis,
                     struct preDrawContainer *preContainer, int preDrawZero,
                     int preDrawSize, double *retGraphUpperLimit, double *retGraphLowerLimit)
 /* Figure out graph limits after running windowingFunction and smoothing if needed.
  * This code is shared by wig, bigWig, and bedGraph drawers. */
 {
 
 /*	determined from data	*/
 double graphUpperLimit=0;	/*	scaling choice will set these	*/
 double graphLowerLimit=0;	/*	scaling choice will set these	*/
 double epsilon;			/*	range of data in one pixel	*/
@@ -1265,31 +1276,31 @@
 /* Draw once we've figured out predraw (numerical values to graph) we draw it here.
  * This code is shared by wig, bigWig, and bedGraph drawers. */
 {
 struct wigCartOptions *wigCart = (struct wigCartOptions *) tg->wigCartData;
 double graphRange;   /*	scaling choice will set this */
 /* if we're autoscaling and the range is 0 this implies that all values 
  * in the given range are the same.  We create a bottom of the scale  
  * by subtracting one from the only value.
  * This results in drawing a box that fills the range. */
 if (graphUpperLimit == graphLowerLimit)
     {
     graphLowerLimit = graphUpperLimit - 1;
     }
 graphRange = graphUpperLimit - graphLowerLimit;
 
-wigTrackSetGraphOutputDefault(tg, xOff, yOff, hvg); 
+wigTrackSetGraphOutputDefault(tg, xOff, yOff, width, hvg); 
 
 graphPreDrawContainer(preContainer, preDrawZero, width, tg, hvg, xOff, yOff, 
     graphUpperLimit, graphLowerLimit, graphRange, vis, wigCart);
 
 drawZeroLine(vis, wigCart->horizontalGrid,
     graphUpperLimit, graphLowerLimit,
     hvg, xOff, yOff, width, tg->lineHeight);
 
 drawArbitraryYLine(vis, (enum wiggleGridOptEnum)wigCart->yLineOnOff,
     graphUpperLimit, graphLowerLimit,
     hvg, xOff, yOff, width, tg->lineHeight, wigCart->yLineMark, graphRange,
     wigCart->yLineOnOff);
 
 wigMapSelf(tg, hvg, seqStart, seqEnd, xOff, yOff, width);