9944d8c4a72a426a07ed2d33a5ea535811dd4461 galt Sun Feb 7 23:26:52 2016 -0800 Issue 16666. Makes autoscale work with multi-region for wig, bedGraph, bigWig, and multiWig. doWiggle still TODO. diff --git src/hg/hgTracks/multiWig.c src/hg/hgTracks/multiWig.c index a2dd849..7c05cff 100644 --- src/hg/hgTracks/multiWig.c +++ src/hg/hgTracks/multiWig.c @@ -158,31 +158,31 @@ int blue = fp[2]*FLOAT_FOR_BIGGEST_BYTE; *cp++ = MAKECOLOR_32(red, green, blue); fp += 3; } if (hvg->rc) reverseLineOfColors(lineBuf, width); hvGfxVerticalSmear(hvg, xOff, y + yOff, width, 1, lineBuf, TRUE); } freez(&lineBuf); } static void minMaxVals(struct slRef *refList, double *retMin, double *retMax, enum wiggleWindowingEnum windowingFunction,enum wiggleAlwaysZeroEnum alwaysZero, double *yOffsets) /* Figure out min/max of everything in list. The refList contains pointers to - * preDrawContainers */ + * preDrawContainers. Calculates the yOffsets used to make the stacked-graph overlay mode. */ { /* Turns out to be *much* shorter to rewrite than to reuse preDrawAutoScale */ double max = -BIGDOUBLE, min = BIGDOUBLE; struct slRef *ref; int numTrack = 0; for (ref = refList; ref != NULL; numTrack++,ref = ref->next) { struct preDrawContainer *pre = ref->val; if (pre == NULL) // pre may be null if the bigWig file didn't load continue; struct preDrawElement *p = pre->preDraw + pre->preDrawZero; int width = pre->width; int i; int offset = numTrack * pre->width; @@ -250,117 +250,191 @@ case wiggleAggregateStacked: { wgo = wigGraphOutputStack(xOff, yOff, width, numTracks, hvg); break; } default: { errAbort("bad aggregate function (value: %d)\n", wigCart->aggregateFunction); break; } } return wgo; } -static void multiWigDraw(struct track *tg, int seqStart, int seqEnd, +static void multiWigPreDraw(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) -/* Draw items in multiWig container. */ +/* Pre-Draw multiWig container calls preDraw on all subtracks. */ { +int y = yOff; // The y value here should not matter. struct track *subtrack; -boolean errMsgShown = FALSE; -int y = yOff; -boolean errMsgFound = FALSE; + +struct wigCartOptions *wigCart = tg->wigCartData; + +// we want to the order to be the same in all the modes +if (wigCart->aggregateFunction == wiggleAggregateStacked) + slReverse(&tg->subtracks); + int numTracks = 0; // determine if any subtracks had errors and count them up for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next) { if (isSubtrackVisible(subtrack) ) { numTracks++; - if (subtrack->networkErrMsg) - errMsgFound = TRUE; } } -if (errMsgFound) - { - Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor); - hvGfxBox(hvg, xOff, yOff, width, tg->height, yellow); - } - -struct wigCartOptions *wigCart = tg->wigCartData; struct wigGraphOutput *wgo = setUpWgo(xOff, yOff, width, tg->height, numTracks, wigCart, hvg); +tg->wigGraphOutput = wgo; -// we want to the order to be the same in all the modes -if (wigCart->aggregateFunction == wiggleAggregateStacked) - slReverse(&tg->subtracks); - -/* Cope with autoScale and stacked bars - we do it here rather than in the child tracks, so that - * all children can be on same scale. */ +// Cope with autoScale and stacked bars - we do it here rather than in the child tracks, so that +// all children can be on same scale. double minVal, maxVal; -/* Force load of all predraw arrays so can do calcs. Build up list, and then - * figure out max/min. No worries about multiple loading, the loaders protect - * themselves. */ +// Force load of all predraw arrays so can do calcs. Build up list, and then +// figure out max/min. No worries about multiple loading, the loaders protect +// themselves. struct slRef *refList = NULL; for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next) { if (isSubtrackVisible(subtrack)) { struct preDrawContainer *pre = subtrack->loadPreDraw(subtrack, seqStart, seqEnd, width); if (pre != NULL) // pre maybe null if the load fails { - preDrawWindowFunction(pre->preDraw, pre->preDrawSize, wigCart->windowingFunction, - wigCart->transformFunc, wigCart->doNegative); - preDrawSmoothing(pre->preDraw, pre->preDrawSize, wigCart->smoothingWindow); - pre->smoothingDone = TRUE; + pre->skipAutoscale = TRUE; + subtrack->preDrawItems(subtrack, seqStart, seqEnd, hvg, xOff, y, width, font, color, vis); refAdd(&refList, pre); } } } slReverse(&refList); + minMaxVals(refList, &minVal, &maxVal, wigCart->windowingFunction, wigCart->alwaysZero, wgo->yOffsets); slFreeList(&refList); if (!wigCart->autoScale) { minVal = wigCart->minY; maxVal = wigCart->maxY; } -/* Loop through again setting up the wigCarts of the children to have minY/maxY for - * our limits and autoScale off. */ +// Loop through again setting up the wigCarts of the children to have minY/maxY for +// our limits and autoScale off. for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next) { - if (!isSubtrackVisible(subtrack)) - continue; - + if (isSubtrackVisible(subtrack)) + { struct wigCartOptions *wigCart = subtrack->wigCartData; wigCart->minY = minVal; wigCart->maxY = maxVal; wigCart->autoScale = wiggleScaleManual; struct preDrawContainer *pre = subtrack->preDrawContainer; - if (pre != NULL) // pre maybe null if the load fails { pre->graphUpperLimit = maxVal; pre->graphLowerLimit = minVal; } } + } +} + +static void multiWigMultiRegionGraphLimits(struct track *tg) +/* Set graphLimits for subtracks. */ +{ +struct track *subtrack; + +double graphUpperLimit = -BIGDOUBLE; +double graphLowerLimit = BIGDOUBLE; +struct window *w; +struct track *tgs; + +for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next) + { + if (isSubtrackVisible(subtrack)) + { + // find common graphLimits across all windows. + for(w=windows,tgs=subtrack; w; w=w->next,tgs=tgs->nextWindow) + { + struct preDrawContainer *pre = tgs->preDrawContainer; + if (pre != NULL) // pre maybe null if the load fails + { + if (pre->graphUpperLimit > graphUpperLimit) + graphUpperLimit = pre->graphUpperLimit; + if (pre->graphLowerLimit < graphLowerLimit) + graphLowerLimit = pre->graphLowerLimit; + } + } + break; // can exit since the rest of the subtracks have been set to the same limits. + } + } + +// set same common graphLimits across all subtracks. +for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next) + { + if (isSubtrackVisible(subtrack)) + { + // set same common graphLimits across all windows. + for(w=windows,tgs=subtrack; w; w=w->next,tgs=tgs->nextWindow) + { + struct wigCartOptions *wigCart = tgs->wigCartData; + wigCart->minY = graphUpperLimit; + wigCart->maxY = graphLowerLimit; + struct preDrawContainer *pre = tgs->preDrawContainer; + if (pre != NULL) // pre maybe null if the load fails + { + pre->graphUpperLimit = graphUpperLimit; + pre->graphLowerLimit = graphLowerLimit; + } + tgs->graphUpperLimit = graphUpperLimit; + tgs->graphLowerLimit = graphLowerLimit; + } + } + } +} + +static void multiWigDraw(struct track *tg, int seqStart, int seqEnd, + struct hvGfx *hvg, int xOff, int yOff, int width, + MgFont *font, Color color, enum trackVisibility vis) +/* Draw items in multiWig container. */ +{ +struct track *subtrack; +boolean errMsgShown = FALSE; +int y = yOff; +boolean errMsgFound = FALSE; +// determine if any subtracks had errors and count them up +for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next) + { + if (isSubtrackVisible(subtrack) ) + { + if (subtrack->networkErrMsg) + errMsgFound = TRUE; + } + } + +if (errMsgFound) + { + Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor); + hvGfxBox(hvg, xOff, yOff, width, tg->height, yellow); + } + +struct wigCartOptions *wigCart = tg->wigCartData; +struct wigGraphOutput *wgo = tg->wigGraphOutput; int numTrack = 0; for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next) { if (isSubtrackVisible(subtrack)) { if (!subtrack->networkErrMsg || !errMsgShown) { if (subtrack->networkErrMsg) errMsgShown = TRUE; wgo->numTrack = numTrack++; subtrack->wigGraphOutput = wgo; int height = subtrack->totalHeight(subtrack, vis); hvGfxSetClip(hvg, xOff, y, width, height); if (wigCart->aggregateFunction != wiggleAggregateNone) @@ -485,18 +559,20 @@ { containerLoadItems(track); struct track *subtrack; for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next) { subtrack->mapsSelf = FALSE; /* Round about way to tell wig not to do own mapping. */ } } void multiWigContainerMethods(struct track *track) /* Override general container methods for multiWig. */ { track->syncChildVisToSelf = TRUE; track->loadItems = multiWigLoadItems; track->totalHeight = multiWigTotalHeight; +track->preDrawItems = multiWigPreDraw; +track->preDrawMultiRegion = multiWigMultiRegionGraphLimits; track->drawItems = multiWigDraw; track->drawLeftLabels = multiWigLeftLabels; }