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; i<expCount && categ != NULL; i++, categ=categ->next)
     {
     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;