141deaec9ba7a2912faedaf2a62fa189108b4c43 braney Thu Apr 13 12:15:01 2023 -0700 some final clean-up on logoMaf: allow the user to turn it off, and scale by the amount of the data within the clipping rectangle diff --git src/hg/hgTracks/wigTrack.c src/hg/hgTracks/wigTrack.c index 367c06f..d8acb83 100644 --- src/hg/hgTracks/wigTrack.c +++ src/hg/hgTracks/wigTrack.c @@ -37,34 +37,35 @@ int ix; /* Position in list. */ int height; /* Pixel height of item. */ unsigned span; /* each value spans this many bases */ unsigned count; /* number of values to use */ unsigned offset; /* offset in File to fetch data */ char *file; /* path name to data file, one byte per value */ double lowerLimit; /* lowest data value in this block */ double dataRange; /* lowerLimit + dataRange = upperLimit */ unsigned validCount; /* number of valid data values in this block */ double sumData; /* sum of the data points, for average and stddev calc */ double sumSquares; /* sum of data points squared, for stddev calc */ double graphUpperLimit; /* filled in by DrawItems */ double graphLowerLimit; /* filled in by DrawItems */ }; -static boolean doLogo(struct trackDb *tdb) +static boolean doLogo(struct track *tg) /* Are we going to draw a logo? */ { -return trackDbSettingOn(tdb, "logo") || (trackDbSetting(tdb, "logoMaf") != NULL); +struct wigCartOptions *wigCart = tg->wigCartData; +return trackDbSettingOn(tg->tdb, "logo") || ((trackDbSetting(tg->tdb, "logoMaf") != NULL) && wigCart->doSequenceLogo); } static void wigFillInColorLfArray(struct track *wigTrack, Color *colArray, int colSize, struct track *colorTrack) /* Fill in a color array with the linkedFeatures based colorTrack's color where it would normally have an exon. */ { struct linkedFeatures *lf = NULL, *lfList = colorTrack->items; struct simpleFeature *sf = NULL; double scale = scaleForPixels(colSize); int x1 = 0, x2 = 0; int i = 0; for(lf = lfList; lf != NULL; lf = lf->next) { for (sf = lf->components; sf != NULL; sf = sf->next) @@ -1222,32 +1223,30 @@ double graphRange, enum trackVisibility vis, struct wigCartOptions *wigCart, int seqStart, int seqEnd) { boolean baseCmpl = cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE); struct preDrawElement *preDraw = preDrawContainer->preDraw; struct wigGraphOutput *wgo = tg->wigGraphOutput; //struct wigMouseOver *mouseOverData = NULL; unsigned numBases = seqEnd - seqStart; struct dnaSeq *seq = hChromSeq(database, chromName, seqStart, seqEnd); if (baseCmpl) complement(seq->dna, seq->size); struct pixelCountBin *pixelBins = wgo->pixelBins; double *yOffsets = wgo->yOffsets; int numTrack = wgo->numTrack; Color clipColor = MG_MAGENTA; -WigVerticalLineVirtual vLine = wgo->vLine; -void *image = wgo->image; #define doLine(image, x, y, height, color) {vLine(image, x, y, height, color); } int h = tg->lineHeight; /* the height of our drawing window */ double scaleFactor = h/graphRange; struct wigMouseOver *mouseOverData = getMouseOverData(tg, preDraw, width, xOff, preDrawZero); struct mafBaseProbs *baseProbs = wigCart->baseProbs; if (baseProbs != NULL) { // initialize our nucleotide probability data structure probVals[0].next = &probVals[1]; probVals[1].next = &probVals[2]; probVals[2].next = &probVals[3]; boolean baseCmpl = cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE); @@ -1314,30 +1313,35 @@ * 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); } { + // since we're drawing a sequence logo, we want to scale by the part of the line within the clipping window + if (dataValue > graphUpperLimit) + dataValue = graphUpperLimit; + else if (dataValue < graphLowerLimit) + dataValue = graphLowerLimit; 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 @@ -1414,37 +1418,37 @@ } else { hvGfxTextInBox(hvg, x, yOff+boxTop, baseWidth - 1, boxHeight, color, font, string); } } } if (((boxTop+boxHeight) == 0) && !isnan(dataValue)) boxHeight += 1; } double stackValue = dataValue; if ((yOffsets != NULL) && (numTrack > 0)) stackValue += yOffsets[(numTrack-1) * width + x1]; - if (stackValue > graphUpperLimit) + if (stackValue >= graphUpperLimit) { - doLine(image, x, yOff, 2, clipColor); + hvGfxLine(hvg, x, yOff, x+baseWidth, yOff, clipColor); } - else if (stackValue < graphLowerLimit) + else if (stackValue <= graphLowerLimit) { - doLine(image, x, yOff + h - 1, 2, clipColor); + hvGfxLine(hvg, x, yOff + h - 1, x+baseWidth, yOff + h - 1, clipColor); } #undef scaleHeightToPixels /* No longer use this symbol */ } /* vis == tvFull || vis == tvPack */ } } /* for (x1 = 0; x1 < width; ++x1) */ return(mouseOverData); } struct wigMouseOver *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. */ { @@ -1698,31 +1702,31 @@ } /* 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, width, hvg); struct wigMouseOver *mouseOverData = NULL; -if (zoomedToCodonLevel && doLogo(tg->tdb) && vis != tvDense) +if (zoomedToCodonLevel && doLogo(tg) && vis != tvDense) mouseOverData = logoPreDrawContainer(preContainer, preDrawZero, width, tg, hvg, xOff, yOff, graphUpperLimit, graphLowerLimit, graphRange, vis, wigCart, seqStart, seqEnd); else mouseOverData = 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, @@ -1942,30 +1946,31 @@ freeMem(currentFile); } return pre; } static void wigPreDrawItems(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw wiggle items that resolve to doing a box for each pixel. */ { char *logoMaf = trackDbSetting(tg->tdb, "logoMaf"); if (logoMaf != NULL) { struct wigCartOptions *wigCart = tg->wigCartData; + if (wigCart->doSequenceLogo) wigCart->baseProbs = hgMafProbs(database, logoMaf, chromName, seqStart, seqEnd, '+'); } struct preDrawContainer *pre = wigLoadPreDraw(tg, seqStart, seqEnd, width); if (pre != NULL) { wigPreDrawPredraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis, pre, pre->preDrawZero, pre->preDrawSize, &tg->graphUpperLimit, &tg->graphLowerLimit); } } void wigMultiRegionGraphLimits(struct track *tg) /* Set common graphLimits across all windows */ { @@ -2167,30 +2172,31 @@ */ wigCart->lineBar = wigFetchGraphTypeWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->horizontalGrid = wigFetchHorizontalGridWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->autoScale = wigFetchAutoScaleWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->windowingFunction = wigFetchWindowingFunctionWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->smoothingWindow = wigFetchSmoothingWindowWithCart(cart,tdb,tdb->track, (char **) NULL); wigFetchMinMaxPixelsWithCart(cart,tdb,tdb->track, &minHeight, &maxHeight, &defaultHeight); wigFetchYLineMarkValueWithCart(cart,tdb,tdb->track, &yLineMark); wigCart->yLineMark = yLineMark; wigCart->yLineOnOff = wigFetchYLineMarkWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->alwaysZero = (enum wiggleAlwaysZeroEnum)wigFetchAlwaysZeroWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->transformFunc = (enum wiggleTransformFuncEnum)wigFetchTransformFuncWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->doNegative = wigFetchDoNegativeWithCart(cart,tdb,tdb->track, (char **) NULL); +wigCart->doSequenceLogo = wigFetchDoSequenceLogoWithCart(cart,tdb,tdb->track, (char **) NULL); wigCart->maxHeight = maxHeight; wigCart->defaultHeight = defaultHeight; wigCart->minHeight = minHeight; wigFetchMinMaxYWithCart(cart,tdb,tdb->track, &wigCart->minY, &wigCart->maxY, NULL, NULL, wordCount, words); wigCart->colorTrack = trackDbSetting(tdb, "wigColorBy"); char *containerType = trackDbSetting(tdb, "container"); if (containerType != NULL && sameString(containerType, "multiWig")) wigCart->isMultiWig = TRUE; wigCart->aggregateFunction = wigFetchAggregateFunctionWithCart(cart,tdb,tdb->track, (char **) NULL);