f7ae366edc0250eb4f61b52bc065ddbe6fa55cfd
kent
  Sat Jan 30 14:16:21 2021 -0800
Making proportional bars respect selected categories, and setting categories from facets, so what gets drawn reflects what facets are selected in faceted mode.

diff --git src/hg/hgTracks/barChartTrack.c src/hg/hgTracks/barChartTrack.c
index d783df8..c9a390b 100644
--- src/hg/hgTracks/barChartTrack.c
+++ src/hg/hgTracks/barChartTrack.c
@@ -1,26 +1,28 @@
 /* barGraph tracks - display a colored bargraph across each region in a file */
 
 /* Copyright (C) 2015 The Regents of the University of California 
  * See README in this or parent directory for licensing extrasrmation. */
 
 #include "common.h"
 #include "hgTracks.h"
 #include "bed.h"
 #include "hvGfx.h"
 #include "spaceSaver.h"
 #include "hubConnect.h"
+#include "fieldedTable.h"
+#include "facetedTable.h"
 #include "barChartBed.h"
 #include "barChartCategory.h"
 #include "barChartUi.h"
 
 // If a category contributes more than this percentage, its color is displayed in squish mode
 // Could be a trackDb setting
 
 struct barChartTrack
 /* Track extras */
     {
     boolean noWhiteout;         /* Suppress whiteout of graph background (allow highlight, blue lines) */
     double maxMedian;           /* Maximum median across all categories */
     boolean doLogTransform;     /* Log10(x+1) */
     boolean fitToGene;		/* Fit our width to gene */
     char *unit;                /* Units for category values (e.g. RPKM) */
@@ -137,39 +139,58 @@
         {
         extras->colors[i] = (struct rgbColor){.r=COLOR_32_BLUE(categ->color), .g=COLOR_32_GREEN(categ->color), .b=COLOR_32_RED(categ->color)};
         i++;
         }
     }
 return extras->colors;
 }
 
 static void filterCategories(struct track *tg)
 /* Check cart for category selection.  NULL out unselected categorys in category list */
 {
 struct barChartTrack *extras = (struct barChartTrack *)tg->extraUiData;
 struct barChartCategory *categ = NULL;
 extras->categories = getCategories(tg);
 extras->categoryFilter = hashNew(0);
-if (cartListVarExistsAnyLevel(cart, tg->tdb, FALSE, BAR_CHART_CATEGORY_SELECT))
+char *barChartFacets = trackDbSetting(tg->tdb, "barChartFacets");
+char *barChartStatsUrl = trackDbSetting(tg->tdb, "barChartStatsUrl");
+if (barChartFacets != NULL && barChartStatsUrl != NULL)
+    {
+    struct fieldedTable *table = fieldedTableFromTabFile(barChartStatsUrl,
+	barChartStatsUrl, NULL, 0);
+    struct facetedTable *facTab = facetedTableFromTable(table, tg->track, barChartFacets);
+    struct slInt *sel, *selList = facetedTableSelectOffsets(facTab, cart);
+    for (sel = selList; sel != NULL; sel = sel->next)
+        {
+	char numBuf[16];
+	safef(numBuf, sizeof(numBuf), "%d", sel->val);
+	char *numCopy = lmCloneString(extras->categoryFilter->lm, numBuf);
+	hashAdd(extras->categoryFilter, numCopy, numCopy);
+	}
+    return;
+    }
+else if (cartListVarExistsAnyLevel(cart, tg->tdb, FALSE, BAR_CHART_CATEGORY_SELECT))
     {
     struct slName *selectedValues = cartOptionalSlNameListClosestToHome(cart, tg->tdb, 
                                                         FALSE, BAR_CHART_CATEGORY_SELECT);
     if (selectedValues != NULL)
         {
         struct slName *name;
         for (name = selectedValues; name != NULL; name = name->next)
+	    {
             hashAdd(extras->categoryFilter, name->name, name->name);
+	    }
         return;
         }
     }
 /* no filter */
 for (categ = extras->categories; categ != NULL; categ = categ->next)
     hashAdd(extras->categoryFilter, categ->name, categ->name);
 }
 
 static int filteredCategoryCount(struct barChartTrack *extras)
 /* Count of categories to display */
 {
 return hashNumEntries(extras->categoryFilter);
 }
 
 static boolean filterCategory(struct barChartTrack *extras, char *name)
@@ -841,112 +862,136 @@
 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 + bed->chromStart;
 *pEnd = start + iWidth*barThinner;
 }
 
+static int countFilteredBars(struct track *tg)
+/* Count up number of bars that remain after filtering */
+{
+struct barChartTrack *extras = (struct barChartTrack *)tg->extraUiData;
+struct barChartCategory *categ;
+int count = 0;
+for (categ=extras->categories; categ != NULL; categ=categ->next)
+    {
+    if (filterCategory(extras, categ->name))
+	++count;
+    }
+return count;
+}
+
+
 static void barsToGeneDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, 
                 double scale, MgFont *font, Color color, enum trackVisibility vis)
 /* Draw bar chart over item in proportional to gene way*/
 {
 if (vis != tvFull && vis != tvPack)
     {
     barChartDrawAt(tg, item, hvg, xOff, y, scale, font, color, vis);
     return;
     }
 
 /* Fetch our item and the bed from it */
 struct barChartItem *itemInfo = (struct barChartItem *)item;
 struct bed *bed = itemInfo->bed;
 
 /* Figure out where to draw things in Y dimension */
 struct barChartTrack *extras = (struct barChartTrack *)tg->extraUiData;
 int topGraphHeight = chartHeight(tg, itemInfo);
 topGraphHeight = max(topGraphHeight, tl.fontHeight);
 int yZero = topGraphHeight + y - 1;  // yZero is bottom of graph
 int yGene = yZero + extras->margin;
 
 /* Figure out width between bars */
-int barCount = bed->expCount;
+int barCount = countFilteredBars(tg);
+int expCount = bed->expCount;
 
-// drawScaledBox(hvg, bed->chromStart, bed->chromEnd, scale, xOff, y, topGraphHeight, MG_YELLOW);  // ugly debug
 
 int i;
 Color clipColor = MG_MAGENTA;
-for (i=0; i<barCount; ++i)
+int outBarIx = 0;
+struct barChartCategory *categ;
+for (i=0, categ=extras->categories; i<expCount && categ != NULL; ++i, categ=categ->next)
     {
+    if (!filterCategory(extras, categ->name))
+        continue;
     struct rgbColor rgb = extras->colors[i];
     int color = hvGfxFindColorIx(hvg, rgb.r, rgb.g, rgb.b);
     int cStart, cEnd;
-    findBarPosX(bed, scale, i, barCount, &cStart, &cEnd);
+    findBarPosX(bed, scale, outBarIx, barCount, &cStart, &cEnd);
     double expScore = bed->expScores[i];
     int height = valToClippedHeight(expScore, extras->maxMedian, extras->maxViewLimit, 
                                         extras->maxHeight, extras->doLogTransform);
     drawScaledBox(hvg, cStart, cEnd, scale, xOff, y+topGraphHeight-height, height, color);
     if (!extras->doLogTransform && expScore > extras->maxViewLimit)
         drawScaledBox(hvg, cStart, cEnd, scale, xOff, yZero-height+1, 2, clipColor);
+    ++outBarIx;
     }
 
 
 // Draw the line our graph sits on top of
 drawScaledBox(hvg, bed->chromStart, bed->chromEnd, scale, xOff, yGene+1, extras->boxModelHeight, 
                 MG_GRAY);
 }
 
 static void barsToGeneMapItem(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) */
 {
 enum trackVisibility vis = trackVisAfterLimit(tg);
 if (vis != tvFull && vis != tvPack)
     {
     barChartMapItem(tg, hvg, item, itemName, mapItemName, start, end, x, y, width, height);
     return;
     }
-
 struct barChartTrack *extras = tg->extraUiData;
 struct barChartItem *itemInfo = item;
 struct bed *bed = itemInfo->bed;
-if (width > bed->expCount)	// When get down to less than a pixel suppress the bar-by-bar map boxes*/
+int barCount = countFilteredBars(tg);
+if (width > barCount)	// When get down to less than a pixel suppress the bar-by-bar map boxes*/
     {
     int i = 0;
+    int outBarIx = 0;
     struct barChartCategory *categs = getCategories(tg);
     struct barChartCategory *categ;
     int topGraphHeight = chartHeight(tg, itemInfo);
     double scale = scaleForWindow(insideWidth, winStart, winEnd);
     for (categ = categs; categ != NULL; categ = categ->next, i++)
 	{
+	if (!filterCategory(extras, categ->name))
+	    continue;
 	int cStart, cEnd;
-	findBarPosX(bed, scale, i, bed->expCount, &cStart, &cEnd);
+	findBarPosX(bed, scale, outBarIx, barCount, &cStart, &cEnd);
 	int x1,x2;
 	if (scaledBoxToPixelCoords(cStart, cEnd, scale, 0, &x1, &x2))
 	    {
 	    double expScore = bed->expScores[i];
 	    int height = valToClippedHeight(expScore, extras->maxMedian, extras->maxViewLimit, 
 						extras->maxHeight, extras->doLogTransform);
 	    mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1+insideX, y+topGraphHeight-height, x2-x1, height,
 				tg->track, mapItemName, chartMapText(tg, categ, expScore));
 	    }
+	++outBarIx;
 	}
     }
 mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x, y, width, height, tg->track, itemName, NULL);
 }
 
 void barChartMethods(struct track *tg)
 /* Bar Chart track type: draw fixed width chart of colored bars over a BED item */
 {
 tg->bedSize = 8;
 bedMethods(tg);
 tg->canPack = TRUE;
 tg->loadItems = barChartLoadItems;
 tg->itemName = barChartItemName;
 tg->mapItemName = barChartMapItemName;
 tg->itemHeight = barChartItemHeight;