a981318c28445664c4fb9c6ef2b6918e2094da98
chmalee
  Fri Mar 4 14:38:29 2022 -0800
Changes from code review. Also restore original bar width calculation as it makes barChartStretchToItem work better, refs #29021

diff --git src/hg/hgTracks/barChartTrack.c src/hg/hgTracks/barChartTrack.c
index 9d7765d..0a9dce2 100644
--- src/hg/hgTracks/barChartTrack.c
+++ src/hg/hgTracks/barChartTrack.c
@@ -381,31 +381,31 @@
 /* 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;
 }
 
 static int windowsTotalIntersection(struct window *list, char *chrom, int chromStart, int chromEnd)
 /* Return total size all bits of region defined by chrom/start/end that intersects windows list */
 {
 if (list == NULL || list->next == NULL)
     {
     double scale = scaleForWindow(insideWidth, winStart, winEnd);
     int leftBlank = round(scale * (max(winStart, chromStart) - winStart));
     int rightBlank = round(scale * (winEnd - min(winEnd, chromEnd)));
-    return (double)insideWidth - leftBlank - rightBlank;
+    return insideWidth - leftBlank - rightBlank;
     }
 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;
@@ -542,32 +542,32 @@
 filterCategories(tg);
 
 /* Test that configuration matches data file */
 if (bedList != NULL)
     {
     int categCount = getCategoryCount(tg);
     int expCount = bedList->expCount;
     if (categCount != expCount)
         warn("Bar chart track: category count mismatch between trackDb (%d) and data file (%d)",
                             categCount, expCount);
     }
 
 int barCount = filteredCategoryCount(extras);
 
 // users can set minimum bar width and padding in trackDb
-char *userBarWidth = trackDbSetting(tdb, BAR_CHART_USER_BAR_WIDTH);
-char *userBarPadding = trackDbSetting(tdb, BAR_CHART_USER_BAR_PADDING);
+char *userSettingMinBarWidth = trackDbSetting(tdb, BAR_CHART_USER_BAR_MIN_WIDTH);
+char *userSettingMinBarPadding = trackDbSetting(tdb, BAR_CHART_USER_BAR_MIN_PADDING);
 
 /* Scaling here is pretty ad-hoc! */
 double scale = 1.0;
 if (barCount <= 20)
     scale = 2.5;
 else if (barCount <= 40)
     scale = 1.6;
 else if (barCount <= 60)
     scale = 1.0;
 else
     scale = 60.0/barCount;
 #ifdef OLD
 else if (barCount <= 120)
     scale = 0.8;
 else if (barCount <= 200)
@@ -608,54 +608,55 @@
     }
 else if (winSize < extras->winSmallGraph)
     {
     extras->boxModelHeight = SMALL_BAR_CHART_MODEL_HEIGHT;
     extras->barWidth = SMALL_BAR_WIDTH * scale;
     extras->padding = SMALL_GRAPH_PADDING * scale;
     extras->maxHeight = SMALL_GRAPH_HEIGHT;
     }
 else
     {
     extras->boxModelHeight = MIN_BAR_CHART_MODEL_HEIGHT;
     extras->barWidth = MIN_BAR_WIDTH * scale;
     extras->padding = MIN_GRAPH_PADDING * scale;
     extras->maxHeight = tl.fontHeight * 4;
     }
+
 if (extras->barWidth > 1)
     extras->barWidth = floor(extras->barWidth);
     
 if (extras->barWidth <= 1 && extras->padding == 1)
    {
    extras->barWidth = 2;
    extras->padding = 0;
    }
 if (extras->barWidth < 1)
     {
     extras->barWidth = 1;
     extras->padding = 0;
     }
 else
     extras->barWidth = round(extras->barWidth);
-if (userBarWidth)
+if (userSettingMinBarWidth)
     {
-    int barWidth = sqlUnsigned(userBarWidth);
-    extras->barWidth = barWidth > extras->barWidth ? barWidth : extras->barWidth;
+    int userMinBarWidth = sqlUnsigned(userSettingMinBarWidth);
+    extras->barWidth = max(userMinBarWidth, extras->barWidth);
     }
-if (userBarPadding)
+if (userSettingMinBarPadding)
     {
-    int barPadding = sqlUnsigned(userBarPadding);
-    extras->padding = barPadding > extras->padding ? barPadding : extras->padding;
+    int userMinBarPadding = sqlUnsigned(userSettingMinBarPadding);
+    extras->padding = max(userMinBarPadding, extras->padding);
     }
 
 extras->modelHeight =  extras->boxModelHeight + 3;
 extras->margin = 1;
 extras->squishHeight = tl.fontHeight - tl.fontHeight/2;
 extras->stretchToItem = trackDbSettingOn(tg->tdb, "barChartStretchToItem");
 
 struct bed *bed, *next;
 for (bed = bedList; bed != NULL; bed = next)
     {
     next = bed->next;
     bed->next = NULL;	/* Pop it off list */
     AllocVar(itemInfo);
     itemInfo->bed = (struct bed *)bed;
     slAddHead(&list, itemInfo);
@@ -762,51 +763,53 @@
     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;
-char *userBarWidth = trackDbSetting(tg->tdb, BAR_CHART_USER_BAR_WIDTH);
-if ((extras->padding == 0 || sameString(colorScheme, BAR_CHART_COLORS_USER))
-        && !userBarWidth)
-    {
-    // scale the barWidth on the graph size at this zoom level
-    barWidth = max(barWidth, graphWidth * invCount);
-    }
+char *userSettingMinBarWidth = trackDbSetting(tg->tdb, BAR_CHART_USER_BAR_MIN_WIDTH);
+int userMinBarWidth = 0;
+if (userSettingMinBarWidth)
+    userMinBarWidth = sqlUnsigned(userSettingMinBarWidth);
 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);
     boolean isClipped = (!extras->doLogTransform && expScore > extras->maxViewLimit);
     int barTop = yZero - height + 1;
     if (extras->padding == 0 || sameString(colorScheme, BAR_CHART_COLORS_USER))
         {
-        x1 = x0 + (barWidth * barsDrawn);
+        int cStart = barsDrawn * graphWidth * invCount;
+        int cEnd = (barsDrawn+1) * graphWidth * invCount;
+        x1 = cStart + x0;
+        barWidth = max(userMinBarWidth, cEnd - cStart - extras->padding);
+        if (x1 + barWidth > x0 + graphWidth)
+            break;
         hvGfxBox(hvg, x1, barTop, barWidth, height, fillColorIx);
         if (isClipped)
             hvGfxBox(hvg, x1, barTop, barWidth, 2, clipColor);
         barsDrawn += 1;
         }
     else
         {
         hvGfxOutlinedBox(hvg, x1, barTop, barWidth, height, fillColorIx, lineColorIx);
         // mark clipped bar with magenta tip
         if (isClipped)
             hvGfxBox(hvg, x1, barTop, barWidth, 2, clipColor);
         x1 = x1 + barWidth + extras->padding;
         }
     }
 }
@@ -891,47 +894,51 @@
 int labelWidth = mgFontStringWidth(tl.font, itemName);
 getItemX(start, end, &x1, &x2);
 if (x1-labelWidth <= insideX)
     labelWidth = 0;
 // map over label
 int itemHeight = itemInfo->height;
 mapBoxHc(hvg, itemStart, itemEnd, x1-labelWidth, y, labelWidth, itemHeight-3, 
                     tg->track, mapItemName, itemName);
 
 
 int graphX = barChartX(bed);
 int graphWidth = chartWidth(tg, itemInfo);
 int barCount = filteredCategoryCount(extras);
 
 char label[256];
+char *userSettingMinBarWidth= trackDbSetting(tg->tdb, BAR_CHART_USER_BAR_MIN_WIDTH);
+int userMinBarWidth = 0;
+if (userSettingMinBarWidth)
+    userMinBarWidth = sqlUnsigned(userSettingMinBarWidth);
 if (barCount <= graphWidth) // Don't create map boxes if less than one pixel per bar
     {
     // add maps to category bars
     struct barChartCategory *categs = getCategories(tg);
     struct barChartCategory *categ = NULL;
     int x0 = insideX + graphX;
     double invCount = 1.0/barCount;
     int i = 0, barsDrawn = 0;
     int extraAtTop = 4;
     for (categ = categs; categ != NULL; categ = categ->next, i++)
 	{
 	if (!filterCategory(extras, categ->name))
 	    continue;
 	x1 = barsDrawn * graphWidth * invCount;
 	barsDrawn += 1;
 	x2 = barsDrawn * graphWidth * invCount;
-	int width = max(1, x2-x1);
+	int width = max(userMinBarWidth, max(1, x2-x1));
 	double expScore = bed->expScores[i];
 	int height = valToClippedHeight(expScore, extras->maxMedian, extras->maxViewLimit,
 					    extras->maxHeight, extras->doLogTransform);
 	height = min(height+extraAtTop, extras->maxHeight);
 	mapBoxHc(hvg, itemStart, itemEnd, x0 + x1, yZero-height, width, height, 
 			    tg->track, mapItemName, chartMapText(tg, categ, expScore));
 	}
     safef(label, sizeof(label), 
 	"%s - click for faceted view or hover over a bar for sample values", 
 	itemName);
     }
 else
     safef(label, sizeof(label), 
 	    "%s - zoom in to resolve individual bars or click for details", 
 	    itemName);