b707eeb51bad2091d226fc58e025fde1c7646c94 hiram Fri Oct 16 16:09:40 2020 -0700 initial prototype of wiggle mouse over values, it is really slow refs #21980 diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c index 27ffea1..508d7a7 100644 --- src/hg/hgTracks/wigTrack.c +++ src/hg/hgTracks/wigTrack.c @@ -831,58 +831,135 @@ 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; } +/* prototype version of mouseOverData using this static array, + * will alter this to be a private linked list + */ +static struct wigMouseOver *mouseOverData = NULL; +static int mouseOverIdx = -1; + +struct wigMouseOver + { + int x; /* x,y coordinates bottom left corner of box */ + int y; + int width; /* width,height of this box */ + int height; + double value; /* data value for this region */ + }; + 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 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); +AllocArray(mouseOverData, width); + +int mouseOverX2 = -1; +double previousValue = 0; +boolean skipMouseOvers = FALSE; +#define epsilonLimit 1.0e-6 +// if (psOutput) +// skipMouseOvers = TRUE; + /* 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]; + /* ===== mouseOver calculations===== */ + if (!skipMouseOvers && (p->count > 0)) /* checking mouseOver construction */ + { + if (p->count < 3) /* allow 1 or 2 values to display */ + { + double thisValue = p->sumData/p->count; /* average if 2 */ + if (mouseOverX2 < 0) /* first valid data found */ + { + ++mouseOverIdx; + mouseOverX2 = x1+1; + mouseOverData[mouseOverIdx].x = xOff+x1; + mouseOverData[mouseOverIdx].width = mouseOverX2 - x1; + mouseOverData[mouseOverIdx].y = yOff; + mouseOverData[mouseOverIdx].height = h; + mouseOverData[mouseOverIdx].value = thisValue; + previousValue = thisValue; + } + else /* see if we need a new item */ + { + if (fabs(thisValue - previousValue) > epsilonLimit) + { + /* finish off the existing run of data */ + mouseOverData[mouseOverIdx].width = mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff); + mouseOverX2 = x1+1; + ++mouseOverIdx; + mouseOverData[mouseOverIdx].x = xOff+x1; + mouseOverData[mouseOverIdx].width = mouseOverX2 - x1; + mouseOverData[mouseOverIdx].y = yOff; + mouseOverData[mouseOverIdx].height = h; + mouseOverData[mouseOverIdx].value = thisValue; + previousValue = thisValue; + } + else /* continue run of same data value */ + mouseOverX2 = x1+1; + } + } + else + skipMouseOvers = TRUE; /* has become too dense to make sense */ + } + else /* perhaps entered region without values after some data already */ + { + if (mouseOverX2 > 0) /* yes, been in data, end it here */ + { + mouseOverData[mouseOverIdx].width = mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff); + mouseOverX2 = -1; /* start over with new data when found */ + } + } + /* potentially end the last mouseOver box */ + if (mouseOverX2 > 0 && (mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff)) > mouseOverData[mouseOverIdx].width) + mouseOverData[mouseOverIdx].width = mouseOverX2 - (mouseOverData[mouseOverIdx].x - xOff); + + /* ===== done with mouseOver calculations===== */ + 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. @@ -1069,30 +1146,34 @@ 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)]; doLine(image, x, yOff, tg->lineHeight, drawColor); } /* vis == tvDense || vis == tvSquish */ } /* if (preDraw[].count) */ } /* for (x1 = 0; x1 < width; ++x1) */ + + if (skipMouseOvers || mouseOverIdx < 0) + freez(&mouseOverData); + } /* 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, @@ -1350,30 +1431,45 @@ 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); +if (mouseOverData) + { + int i; + /* could put up a 'no data' box when these items are not contiguous + * e.g. when gaps interrupt the track data + */ + for (i = 0; i <= mouseOverIdx; ++i) + { + char value[64]; + safef(value, sizeof(value), " %g", mouseOverData[i].value); + mapBoxHc(hvg, seqStart, seqEnd, mouseOverData[i].x, mouseOverData[i].y, mouseOverData[i].width, mouseOverData[i].height, + tg->track, value, value); + } + } +else wigMapSelf(tg, hvg, seqStart, seqEnd, xOff, yOff, width); } struct preDrawContainer *wigLoadPreDraw(struct track *tg, int seqStart, int seqEnd, int width) /* Do bits that load the predraw buffer tg->preDrawContainer. */ { /* Just need to do this once... */ if (tg->preDrawContainer) return tg->preDrawContainer; struct wigItem *wi; double pixelsPerBase = scaleForPixels(width); double basesPerPixel = 1.0; int itemCount = 0;