038e590eac583c4253e53b234b365a4e842586c5
kent
  Sat Jan 30 09:02:52 2021 -0800
Initial implementation of barChartFacet feature in click display.

diff --git src/hg/hgc/barChartClick.c src/hg/hgc/barChartClick.c
index 9999970..73323f8 100644
--- src/hg/hgc/barChartClick.c
+++ src/hg/hgc/barChartClick.c
@@ -11,30 +11,31 @@
 #include "hCommon.h"
 #include "hui.h"
 #include "asParse.h"
 #include "hgc.h"
 #include "trackHub.h"
 #include "memgfx.h"
 #include "hgColors.h"
 #include "fieldedTable.h"
 
 #include "barChartBed.h"
 #include "barChartCategory.h"
 #include "barChartData.h"
 #include "barChartSample.h"
 #include "barChartUi.h"
 #include "hgConfig.h"
+#include "facetedBar.h"
 
 #define EXTRA_FIELDS_SIZE 256
 
 struct barChartItemData
 /* Measured value for a sample and the sample category at a locus.
  * Used for barChart track details (boxplot) */
     {
     struct barChartItemData *next;  /* Next in singly linked list. */
     char *sample;	/* Sample identifier */
     char *category;     /* Sample category (from barChartSample table  or barChartSampleUrl file) */
     double value;	/* Measured value (e.g. expression level) */
     };
 
 static struct hash *getTrackCategories(struct trackDb *tdb)
 /* Get list of categories from trackDb.  This may be a subset of those in matrix. 
@@ -387,64 +388,63 @@
 
 static double longestLabelSize(struct barChartCategory *categList)
 /* Get estimate of longest label in pixels */
 {
 int longest = 0;
 struct barChartCategory *categ;
 for (categ = categList; categ != NULL; categ = categ->next)
     {
     int size = estimateStringWidth(categ->label);
     if (size > longest)
         longest = size;
     }
 return longest * 1.02;
 }
 
-void deunderbarColumn(struct fieldedTable *ft, char *field)
+void deunderbarColumn(struct fieldedTable *ft, int fieldIx)
 /* Ununderbar all of a column inside table because space/underbar gets
  * so confusing */
 {
-int fieldIx = fieldedTableFindFieldIx(ft, field);
 struct fieldedRow *row;
 for (row = ft->rowList; row != NULL; row = row->next)
     replaceChar(row->row[fieldIx], '_', ' ');
 }
 
-static void printBarChart(struct barChartBed *chart, struct trackDb *tdb, double maxVal, char *metric)
+static void svgBarChart(struct barChartBed *chart, struct trackDb *tdb, double maxVal, char *metric)
 /* Plot bar chart without quartiles or anything fancy just using SVG */
 {
 /* Load up input labels, color, and data */
 struct barChartCategory *categs = barChartUiGetCategories(database, tdb);
 int categCount = slCount(categs);
 if (categCount != chart->expCount)
     {
     warn("Problem in %s barchart track. There are %d categories in trackDb and %d in data",
 	tdb->track, categCount, chart->expCount);
     return;
     }
 
 char *statsFile = trackDbSetting(tdb, "barChartStatsUrl");
 struct hash *statsHash = NULL;
 int countStatIx = 0;
 double statsSize = 0.0;
 if (statsFile != NULL)
     {
-    char *required[] = {"cluster", "count", "total"};
+    char *required[] = { "count", "total"};
     struct fieldedTable *ft = fieldedTableFromTabFile(
 	statsFile, statsFile, required, ArraySize(required));
-    deunderbarColumn(ft, "cluster");
-    statsHash = fieldedTableIndex(ft, "cluster");
+    deunderbarColumn(ft, 0);
+    statsHash = fieldedTableIndex(ft, ft->fields[0]);
     countStatIx = fieldedTableFindFieldIx(ft, "count");
     statsSize = 8*(fieldedTableMaxColChars(ft, countStatIx)+1);
     }
 
 /* Some constants that control layout */
 double heightPer=18.0;
 double totalWidth=1250.0;
 double borderSize = 1.0;
 
 double headerHeight = heightPer + 2*borderSize;
 double innerHeight=heightPer-borderSize;
 double labelWidth = longestLabelSize(categs) + 9;  // Add some because size is just estimate
 if (labelWidth > totalWidth/2) labelWidth = totalWidth/2;  // Don't let labels take up more than half
 double patchWidth = heightPer;
 double labelOffset = patchWidth + 2*borderSize;
@@ -496,30 +496,42 @@
 	{
 	struct fieldedRow *fr = hashFindVal(statsHash, deunder);
 	if (fr != NULL)
 	    {
 	    printf("<text x=\"%g\" y=\"%g\" font-size=\"%g\" text-anchor=\"end\">%s</text>\n", 
 		statsRightOffset, yPos+innerHeight-1, innerHeight-1, fr->row[countStatIx]);
 	    }
 	}
     printf("<text x=\"%g\" y=\"%g\" font-size=\"%g\">%5.3f</text>\n", 
 	barOffset+barWidth+2, yPos+innerHeight-1, innerHeight-1, score);
     }
 printf("</svg>");
 }
 
 
+static void printBarChart(char *item, struct barChartBed *chart, struct trackDb *tdb, 
+    double maxVal, char *metric)
+/* Plot bar chart without expressionMatrix or R plots*/
+{
+char *statsFile = trackDbSetting(tdb, "barChartStatsUrl");
+char *facets = trackDbSetting(tdb, "barChartFacets");
+if (facets != NULL && statsFile != NULL)
+    facetedBarChart(item, chart, tdb, maxVal, statsFile, facets, metric);
+else
+    svgBarChart(chart, tdb, maxVal, metric);
+}
+
 struct asColumn *asFindColByIx(struct asObject *as, int ix)
 /* Find AS column by index */
 {
 struct asColumn *asCol;
 int i;
 for (i=0, asCol = as->columnList; asCol != NULL && i<ix; asCol = asCol->next, i++);
     return asCol;
 }
 
 void doBarChartDetails(struct trackDb *tdb, char *item)
 /* Details of barChart item */
 {
 int start = cartInt(cart, "o");
 int end = cartInt(cart, "t");
 struct asObject *as = NULL;
@@ -534,69 +546,70 @@
 
 // get name and name2 from trackDb, .as file, or use defaults
 struct asColumn *nameCol = NULL, *name2Col = NULL;
 //struct asColumn *name2Col;
 char *nameLabel = NULL, *name2Label = NULL;
 if (as != NULL)
     {
     numColumns = slCount(as->columnList);
     nameCol = asFindColByIx(as, BARCHART_NAME_COLUMN_IX);
     name2Col = asFindColByIx(as, BARCHART_NAME2_COLUMN_IX);
     }
 nameLabel = trackDbSettingClosestToHomeOrDefault(tdb, "bedNameLabel", nameCol ? nameCol->comment : "Item");
 if (trackDbSettingClosestToHomeOrDefault(tdb, "url", NULL) != NULL)
     printCustomUrl(tdb, item, TRUE);
 else
-    printf("<b>%s: </b>%s<br>\n", nameLabel, chartItem->name);
+    printf("<b>%s: </b>%s ", nameLabel, chartItem->name);
 name2Label = name2Col ? name2Col->comment : "Alternative name";
 if (differentString(chartItem->name2, "")) 
     {
     if (trackDbSettingClosestToHomeOrDefault(tdb, "url2", NULL) != NULL)
         printOtherCustomUrl(tdb, chartItem->name2, "url2", TRUE);
     else
-        printf("<b>%s: </b> %s<br>\n", name2Label, chartItem->name2);
+        printf("(%s: %s)<br>\n", name2Label, chartItem->name2);
     }
+else
+    printf("<br>\n");
 
 int categId;
 float highLevel = barChartMaxValue(chartItem, &categId);
 char *units = trackDbSettingClosestToHomeOrDefault(tdb, BAR_CHART_UNIT, "units");
 char *metric = trackDbSettingClosestToHomeOrDefault(tdb, BAR_CHART_METRIC, "");
-printf("<b>Total all %s values: </b> %0.2f %s<br>\n", metric, barChartTotalValue(chartItem), units);
 printf("<b>Maximum %s value: </b> %0.2f %s in %s<br>\n", 
                 metric, highLevel, units, barChartUiGetCategoryLabelById(categId, database, tdb));
-printf("<b>Score: </b> %d<br>\n", chartItem->score); 
 printf("<b>Genomic position: "
                 "</b>%s <a href='%s&db=%s&position=%s%%3A%d-%d'>%s:%d-%d</a><br>\n", 
                     database, hgTracksPathAndSettings(), database, 
                     chartItem->chrom, chartItem->chromStart+1, chartItem->chromEnd,
                     chartItem->chrom, chartItem->chromStart+1, chartItem->chromEnd);
-printf("<b>Strand: </b> %s\n", chartItem->strand); 
 
 // print any remaining extra fields
 if (numColumns > 0)
     {
     extraFieldsPrint(tdb, NULL, extraFields, extraFieldCount);
     }
 
 char *matrixUrl = NULL, *sampleUrl = NULL;
 struct barChartItemData *vals = getSampleVals(tdb, chartItem, &matrixUrl, &sampleUrl);
 puts("<p>");
 if (vals != NULL)
     {
     // Print boxplot
     char *df = makeDataFrame(tdb->table, vals);
     char *colorFile = makeColorFile(tdb);
     printBoxplot(df, item, chartItem->name2, units, colorFile);
     printf("<br><a href='%s'>View all data points for %s%s%s%s</a>\n", df, 
                         chartItem->name, 
                         chartItem->name2 ? " (" : "",
                         chartItem->name2 ? chartItem->name2 : "",
                         chartItem->name2 ? ")" : "");
     }
 else
     {
     if (cfgOptionBooleanDefault("svgBarChart", FALSE))
-	printBarChart(chartItem, tdb, highLevel, metric);
+	{
+	printBarChart(item, chartItem, tdb, highLevel, metric);
+	}
     }
 puts("<br>");
 }