dbff2df65c339ba878154eda07fd5ce60a2383c3 braney Fri Dec 5 17:07:07 2014 -0800 add the ability to get coverage (wiggle) plots for bed type tracks #952 diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c index 89db338..fb1a156 100644 --- src/hg/hgTracks/simpleTracks.c +++ src/hg/hgTracks/simpleTracks.c @@ -297,30 +297,42 @@ /* Temporary function until all composite tracks point to their own children */ { return (tdbIsComposite(track->tdb) && track->subtracks != NULL); } Color slightlyLighterColor(struct hvGfx *hvg, Color color) /* Get slightly lighter shade of a color - closer to gray actually */ { struct rgbColor rgbColor = hvGfxColorIxToRgb(hvg, color); rgbColor.r = (rgbColor.r+128)/2; rgbColor.g = (rgbColor.g+128)/2; rgbColor.b = (rgbColor.b+128)/2; return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b); } +void checkIfWiggling(struct cart *cart, struct track *tg) +/* check to see if a linkedFeatures track should be drawing as a wiggle */ +{ +char *doWiggle = cartOrTdbString(cart, tg->tdb, "doWiggle" , "0"); +if (sameString(doWiggle, "1")) + { + tg->drawLeftLabels = wigLeftLabels; + tg->colorShades = shadesOfGray; + tg->mapsSelf = TRUE; + } +} + int packCountRowsOverflow(struct track *tg, int maxCount, boolean withLabels, boolean allowOverflow) /* Return packed height. */ { struct spaceSaver *ss; struct slList *item; MgFont *font = tl.font; int extraWidth = tl.mWidth * 2; long long start, end; double scale = (double)insideWidth/(winEnd - winStart); spaceSaverFree(&tg->ss); ss = tg->ss = spaceSaverNew(0, insideWidth, maxCount); for (item = tg->items; item != NULL; item = item->next) { int baseStart = tg->itemStart(tg, item); @@ -398,30 +410,42 @@ /* Return the maximum number of items to allow overflow indication. */ { int answer = maxItemsToUseOverflowDefault; char *maxItemsString = trackDbSetting(tg->tdb, "maxItemsToOverflow"); if (maxItemsString != NULL) answer = sqlUnsigned(maxItemsString); return answer; } int tgFixedTotalHeightOptionalOverflow(struct track *tg, enum trackVisibility vis, int lineHeight, int heightPer, boolean allowOverflow) /* Most fixed height track groups will use this to figure out the height * they use. */ { +char *doWiggle = cartOrTdbString(cart, tg->tdb, "doWiggle" , "0"); +if (sameString(doWiggle, "1")) + { + struct wigCartOptions *wigCart = tg->wigCartData; + if (tg->wigCartData == NULL) + { + wigCart = wigCartOptionsNew(cart, tg->tdb, 0, NULL ); + tg->wigCartData = (void *) wigCart; + } + return wigTotalHeight(tg, vis); + } + int rows; double maxHeight = maximumTrackHeight(tg); int itemCount = slCount(tg->items); int maxItemsToUseOverflow = maxItemsToOverflow(tg); tg->heightPer = heightPer; tg->lineHeight = lineHeight; /* Note that the maxCount variable passed to packCountRowsOverflow() is tied to the maximum height allowed for a track and influences decisions about when to squish, dense, or overflow a track. If doing overflow try to pack all the items into the maxHeight area or put all the overflow into the last row. If not doing overflow allow the track enough rows to go over the maxHeight (thus if the spaceSaver fills up the total height will be more than maxHeight). @@ -3147,30 +3171,191 @@ if (w > 0) { if (nextItemCompatible(tg)) genericDrawNextItemStuff(tg, hvg, vis, item, x2, textX, y, tg->heightPer, FALSE, color); else { tg->mapItem(tg, hvg, item, tg->itemName(tg, item), tg->mapItemName(tg, item), s, e, textX, y, w, tg->heightPer); } } } withIndividualLabels = TRUE; /* reset in case done with pgSnp */ } +static int normalizeCount(struct preDrawElement *el, double countFactor, + double minVal, double maxVal, double sumData, double sumSquares) +/* normalize statistics to be based on an integer number of valid bases + * Integer value is the smallest integer not less than countFactor */ +{ +bits32 validCount = ceil(countFactor); +double normFactor = (double)validCount/countFactor; + +el->count = validCount; +el->min = minVal; +el->max = maxVal; +el->sumData = sumData * normFactor; +el->sumSquares = sumSquares * normFactor; + +return validCount; +} + +static unsigned *countOverlaps(struct track *track) +/* count up overlap of linked features */ +{ +int ii; +struct slList *items = track->items; +struct slList *item; +unsigned size = winEnd - winStart; +unsigned *counts = needHugeZeroedMem(size * sizeof(unsigned)); + +for (item = items; item; item = item->next) + { + unsigned start = track->itemStart(track, item); + unsigned end = track->itemEnd(track, item); + if ((start >= winEnd) || (end < winStart)) + continue; + + int x1 = start - winStart; + if (x1 < 0) + x1 = 0; + int x2 = end - winStart; + if (x2 > size) + x2 = size; + + for(ii=x1; ii < x2; ii++) + counts[ii]++; + } + +return counts; +} + +static void countsToPixelsUp(unsigned *counts, struct preDrawContainer *pre) +/* up sample counts into pixels */ +{ +int preDrawZero = pre->preDrawZero; +unsigned size = winEnd - winStart; +double countsPerPixel = size / (double) insideWidth; +int pixel; + +for (pixel=0; pixelpreDraw[pixel + preDrawZero]; + unsigned index = pixel * countsPerPixel; + pe->count = 1; + pe->min = counts[index]; + pe->max = counts[index]; + pe->sumData = counts[index] ; + pe->sumSquares = counts[index] * counts[index]; + } +} + +static void countsToPixelsDown(unsigned *counts, struct preDrawContainer *pre) +/* down sample counts into pixels */ +{ +int preDrawZero = pre->preDrawZero; +unsigned size = winEnd - winStart; +double countsPerPixel = size / (double) insideWidth; +int pixel; + +for (pixel=0; pixelpreDraw[pixel + preDrawZero]; + double startReal = pixel * countsPerPixel; + double endReal = (pixel + 1) * countsPerPixel; + unsigned startUns = startReal; + unsigned endUns = endReal; + double realCount, realSum, realSumSquares, max, min; + + realCount = realSum = realSumSquares = 0.0; + max = min = counts[startUns]; + + assert(startUns != endUns); + unsigned ceilUns = ceil(startReal); + + if (ceilUns != startUns) + { + /* need a fraction of the first count */ + double frac = (double)ceilUns - startReal; + realCount = frac; + realSum = frac * counts[startUns]; + realSumSquares = realSum * realSum; + startUns++; + } + + // add in all the counts that are totally in this pixel + for(; startUns < endUns; startUns++) + { + realCount += 1.0; + realSum += counts[startUns]; + realSumSquares += counts[startUns] * counts[startUns]; + if (max < counts[startUns]) + max = counts[startUns]; + if (min > counts[startUns]) + min = counts[startUns]; + } + + // add any fraction of the count that's only partially in this pixel + double lastFrac = endReal - endUns; + double lastSum = lastFrac * counts[endUns]; + if (lastFrac > 0.0) + { + if (max < counts[endUns]) + max = counts[endUns]; + if (min > counts[endUns]) + min = counts[endUns]; + realCount += lastFrac; + realSum += lastSum; + realSumSquares += lastSum * lastSum; + } + + pe->count = normalizeCount(pe, realCount, min, max, realSum, realSumSquares); + } +} + +static void countsToPixels(unsigned *counts, struct preDrawContainer *pre) +/* sample counts into pixels */ +{ +unsigned size = winEnd - winStart; +double countsPerPixel = size / (double) insideWidth; + +if (countsPerPixel <= 1.0) + countsToPixelsUp(counts, pre); +else + countsToPixelsDown(counts, pre); +} + +static void genericDrawItemsWiggle(struct track *tg, int seqStart, int seqEnd, + struct hvGfx *hvg, int xOff, int yOff, int width, + MgFont *font, Color color, enum trackVisibility vis) +/* draw a list of linked features into a wiggle */ +{ +struct preDrawContainer *pre = tg->preDrawContainer = initPreDrawContainer(insideWidth); +unsigned *counts = countOverlaps(tg); + +countsToPixels(counts, pre); +freez(&counts); + +hvGfxSetClip(hvg, insideX, yOff, insideWidth, tg->height); +tg->mapsSelf = FALSE; // some magic to turn off the link out +wigDrawPredraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis, + tg->preDrawContainer, tg->preDrawContainer->preDrawZero, tg->preDrawContainer->preDrawSize, &tg->graphUpperLimit, &tg->graphLowerLimit); +tg->mapsSelf = TRUE; +hvGfxUnclip(hvg); +} + static void genericDrawItemsPackSquish(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* genericDrawItems logic for pack and squish modes */ { double scale = scaleForWindow(width, seqStart, seqEnd); int lineHeight = tg->lineHeight; struct spaceNode *sn; int maxHeight = maximumTrackHeight(tg); int overflowRow = (maxHeight - tl.fontHeight +1) / lineHeight; boolean firstOverflow = TRUE; hvGfxSetClip(hvg, insideX, yOff, insideWidth, tg->height); assert(tg->ss); @@ -3242,31 +3427,37 @@ y += tg->lineHeight; } } } void genericDrawItems(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw generic item list. Features must be fixed height * and tg->drawItemAt has to be filled in. */ { if (tg->mapItem == NULL) tg->mapItem = genericMapItem; if (vis != tvDense && (! bedItemRgb(tg->tdb)) && baseColorCanDraw(tg)) baseColorInitTrack(hvg, tg); -if (vis == tvPack || vis == tvSquish) +char *doWiggle = cartOrTdbString(cart, tg->tdb, "doWiggle" , "0"); +if (sameString(doWiggle, "1")) + { + genericDrawItemsWiggle(tg, seqStart, seqEnd, hvg, xOff, yOff, width, + font, color, vis); + } +else if (vis == tvPack || vis == tvSquish) { genericDrawItemsPackSquish(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); } else genericDrawItemsFullDense(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); } void linkedFeaturesSeriesDraw(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw linked features items. */ { clearColorBin(); @@ -12322,30 +12513,31 @@ static void compositeLoad(struct track *track) /* Load all subtracks */ { struct track *subtrack; long thisTime = 0, lastTime = 0; for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next) { if (isSubtrackVisible(subtrack) && ( limitedVisFromComposite(subtrack) != tvHide)) { if (!subtrack->parallelLoading) { lastTime = clock1000(); if (!subtrack->loadItems) // This could happen if track type has no handler (eg, for new types) errAbort("Error: No loadItems() handler for subtrack (%s) of composite track (%s) (is this a new track 'type'?)\n", subtrack->track, track->track); + checkIfWiggling(cart, subtrack); subtrack->loadItems(subtrack); if (measureTiming) { thisTime = clock1000(); subtrack->loadTime = thisTime - lastTime; lastTime = thisTime; } } } else { subtrack->limitedVis = tvHide; subtrack->limitedVisSet = TRUE; } }