d4ea24a2fedb651ffefbab4095c25eb9d1be8db3 kent Tue Feb 2 17:52:52 2021 -0800 I think I got it working in a way that combines best of the proportional and non-proportional ways, and it even seems to work in multi-region! diff --git src/hg/hgTracks/barChartTrack.c src/hg/hgTracks/barChartTrack.c index 1dee878..41166c4 100644 --- src/hg/hgTracks/barChartTrack.c +++ src/hg/hgTracks/barChartTrack.c @@ -333,42 +333,81 @@ return itemInfo->height; } int topGraphHeight = chartHeight(tg, itemInfo); topGraphHeight = max(topGraphHeight, tl.fontHeight); int bottomGraphHeight = 0; height = topGraphHeight + bottomGraphHeight + extras->margin + extras->modelHeight; return height; } static int barChartItemHeight(struct track *tg, void *item) { int height = chartItemHeightOptionalMax(tg, item, FALSE); return height; } +static int chartStandardWidth(struct track *tg, struct barChartItem *itemInfo) +/* How wide is chart if we go by standard bar chart size? */ +{ +struct barChartTrack *extras = (struct barChartTrack *)tg->extraUiData; +int count = filteredCategoryCount(extras); +return (extras->barWidth * count) + (extras->padding * (count-1)) + 2; +} + +int windowsTotalIntersection(struct window *list, char *chrom, int chromStart, int chromEnd) +/* Return total size all bits of region that intersects windows list */ +{ +if (list == NULL || list->next == NULL) + return (double)insideWidth * (chromEnd - chromStart) / (winEnd - winStart); +long long totalGenoSize = 0; +int totalPixelSize = 0; +struct window *w; +int totalIntersect = 0; +for (w = list; w != NULL; w = w->next) + { + totalPixelSize += w->insideWidth;; + totalGenoSize += w->winEnd - w->winStart; + + if (sameString(w->chromName, chrom)) + { + int single = rangeIntersection(w->winStart, w->winEnd, chromStart, chromEnd); + if (single > 0) + totalIntersect += single; + } + } +if (totalIntersect == 0) + return 0; +else + { + return totalPixelSize * (double)totalIntersect / totalGenoSize; + } +} + static int chartWidth(struct track *tg, struct barChartItem *itemInfo) +/* How wide is the chart? */ { +struct bed *bed = itemInfo->bed; struct barChartTrack *extras = (struct barChartTrack *)tg->extraUiData; +int geneSize = windowsTotalIntersection(windows, bed->chrom, bed->chromStart, bed->chromEnd); if (extras->fitToGene) { - struct bed *bed = itemInfo->bed; - return scaleForWindow(bed->chromEnd - bed->chromStart, winStart, winEnd); + return geneSize; } else { - int count = filteredCategoryCount(extras); - return (extras->barWidth * count) + (extras->padding * (count-1)) + 2; + int standardSize = chartStandardWidth(tg, itemInfo); + return max(standardSize, geneSize); } } static void barChartLoadItems(struct track *tg) /* Load method for track items */ { /* Initialize colors for visibilities that don't display actual barchart */ if (tg->visibility == tvSquish || tg->limitedVis == tvSquish) tg->itemColor = barChartItemColor; tg->colorShades = shadesOfGray; /* Get track UI info */ struct barChartTrack *extras; if (!tg->extraUiData) { @@ -519,41 +558,42 @@ slAddHead(&list, itemInfo); bed = bed->next; itemInfo->bed->next = NULL; itemInfo->height = barChartItemHeight(tg, itemInfo); } slReverse(&list); tg->items = list; } /***********************************************/ /* Draw */ static int barChartX(struct bed *bed) /* Locate chart on X, relative to viewport. */ { -int start = max(bed->chromStart, winStart); // Consider making this simply bed->chromStart -jk +// int start = max(bed->chromStart, winStart); // Consider making this simply bed->chromStart -jk +int start = bed->chromStart; double scale = scaleForWindow(insideWidth, winStart, winEnd); int x1 = round((start - winStart) * scale); return x1; } static void drawGraphBox(struct track *tg, struct barChartItem *itemInfo, struct hvGfx *hvg, int x, int y) /* Draw white background for graph */ { -Color lighterGray = MAKECOLOR_32(0xF3, 0xF3, 0xF3); +Color lighterGray = MAKECOLOR_32(0xE8, 0xE8, 0xE8); int width = chartWidth(tg, itemInfo); int height = chartHeight(tg, itemInfo); hvGfxOutlinedBox(hvg, x, y-height, width, height, MG_WHITE, lighterGray); } static void drawGraphBase(struct track *tg, struct barChartItem *itemInfo, struct hvGfx *hvg, int x, int y) /* Draw faint line under graph to delineate extent when bars are missing (category w/ 0 value) */ { Color lightGray = MAKECOLOR_32(0xD1, 0xD1, 0xD1); int graphWidth = chartWidth(tg, itemInfo); hvGfxBox(hvg, x, y, graphWidth, 1, lightGray); } static void barChartDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) @@ -588,79 +628,103 @@ tg->heightPer = extras->modelHeight; int height = extras->boxModelHeight; drawScaledBox(hvg, bed->chromStart, bed->chromEnd, scale, xOff, yGene+1, height, MG_GRAY); tg->heightPer = heightPer; } static int barChartNonPropPixelWidth(struct track *tg, void *item) /* Return end chromosome coordinate of item, including graph */ { struct barChartItem *itemInfo = (struct barChartItem *)item; int graphWidth = chartWidth(tg, itemInfo); return graphWidth; } +static void findBarPosX(int chromStart, int chromEnd, double scale, int barIx, int barCount, int *pStart, int *pEnd) +/* Figure out start/end position of our bar's region */ +{ +int baseWidth = chromEnd - chromStart; +double scaledSize = baseWidth *scale; +double oneWidth = scaledSize/barCount; +double barThinner = 1.0; +if (oneWidth >= 5.0) + { + if (oneWidth > 7.0) + barThinner = 0.8; + else + barThinner = 0.75; + } + +int iStart = baseWidth*barIx/barCount; +int iEnd = baseWidth*(barIx+1)/barCount; +int iWidth = iEnd - iStart; +int start = *pStart = iStart + chromStart; +*pEnd = start + iWidth*barThinner; +} + static void barChartNonPropDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) { if (vis != tvFull && vis != tvPack) return; struct barChartTrack *extras = (struct barChartTrack *)tg->extraUiData; struct barChartItem *itemInfo = (struct barChartItem *)item; struct bed *bed = itemInfo->bed; int topGraphHeight = chartHeight(tg, itemInfo); int graphWidth = chartWidth(tg, itemInfo); +#ifdef OLD +#endif /* OLD */ topGraphHeight = max(topGraphHeight, tl.fontHeight); int yZero = topGraphHeight + y - 1; // yZero is bottom of graph int graphX = barChartX(bed); -int x1 = xOff + graphX; // x1 is at left of graph -int keepX = x1; -drawGraphBase(tg, itemInfo, hvg, keepX, yZero+1); +int x0 = xOff + graphX; // x0 is at left of graph +int x1 = x0; +drawGraphBase(tg, itemInfo, hvg, x0, yZero+1); if (!extras->noWhiteout) - drawGraphBox(tg, itemInfo, hvg, keepX, yZero+1); + drawGraphBox(tg, itemInfo, hvg, x0, yZero+1); struct rgbColor lineColor = {.r=0}; int lineColorIx = hvGfxFindColorIx(hvg, lineColor.r, lineColor.g, lineColor.b); int barWidth = extras->barWidth; char *colorScheme = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, BAR_CHART_COLORS, BAR_CHART_COLORS_DEFAULT); Color clipColor = MG_MAGENTA; // draw bar graph int i; int expCount = bed->expCount; struct barChartCategory *categ; int barCount = filteredCategoryCount(extras), barsDrawn = 0; double invCount = 1.0/barCount; -int x0 = x1; for (i=0, categ=extras->categories; inext) { if (!filterCategory(extras, categ->name)) continue; struct rgbColor fillColor = extras->colors[i]; int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b); double expScore = bed->expScores[i]; int height = valToClippedHeight(expScore, extras->maxMedian, extras->maxViewLimit, extras->maxHeight, extras->doLogTransform); if (extras->padding == 0 || sameString(colorScheme, BAR_CHART_COLORS_USER)) { - int x1 = barsDrawn * graphWidth * invCount; + int cStart = barsDrawn * graphWidth * invCount; + int cEnd = (barsDrawn+1) * graphWidth * invCount; + hvGfxBox(hvg, cStart + x0, yZero-height+1, cEnd-cStart - extras->padding, height, fillColorIx); barsDrawn += 1; - hvGfxBox(hvg, x1 + x0, yZero-height+1, max(1,barWidth), height, fillColorIx); } else { hvGfxOutlinedBox(hvg, x1, yZero-height+1, barWidth, height, fillColorIx, lineColorIx); x1 = x1 + barWidth + extras->padding; } // mark clipped bar with magenta tip if (!extras->doLogTransform && expScore > extras->maxViewLimit) hvGfxBox(hvg, x1, yZero-height+1, barWidth, 2, clipColor); } } static char *chartMapText(struct track *tg, struct barChartCategory *categ, double expScore) /* Construct mouseover text for a chart bar */ { @@ -690,52 +754,30 @@ } static void getItemX(int start, int end, int *x1, int *x2) /* Return startX, endX based on item coordinates and current window */ // Residual (largely replaced by drawScaledBox -- still used by gene model bmap box { int s = max(start, winStart); int e = min(end, winEnd); double scale = scaleForWindow(insideWidth, winStart, winEnd); assert(x1); *x1 = round((double)((int)s-winStart)*scale + insideX); assert(x2); *x2 = round((double)((int)e-winStart)*scale + insideX); } -static void findBarPosX(int chromStart, int chromEnd, double scale, int barIx, int barCount, int *pStart, int *pEnd) -/* Figure out start/end position of our bar's region */ -{ -int baseWidth = chromEnd - chromStart; -double scaledSize = baseWidth *scale; -double oneWidth = scaledSize/barCount; -double barThinner = 1.0; -if (oneWidth >= 5.0) - { - if (oneWidth > 7.0) - barThinner = 0.8; - else - barThinner = 0.75; - } - -int iStart = baseWidth*barIx/barCount; -int iEnd = baseWidth*(barIx+1)/barCount; -int iWidth = iEnd - iStart; -int start = *pStart = iStart + chromStart; -*pEnd = start + iWidth*barThinner; -} - static void barChartMapItem(struct track *tg, struct hvGfx *hvg, void *item, char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) /* Create a map box on item and label, and one for each category (bar in the graph) in * pack or full mode. Just single map for squish/dense modes */ { if (tg->limitedVis == tvDense) { genericMapItem(tg, hvg, item, itemName, itemName, start, end, x, y, width, height); return; } struct barChartTrack *extras = (struct barChartTrack *)tg->extraUiData; struct barChartItem *itemInfo = (struct barChartItem *)item; struct bed *bed = itemInfo->bed; int itemStart = bed->chromStart; int itemEnd = bed->chromEnd;