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