5bfb32fdfc639f9bffb5435044cef164bdde0b28
kent
  Sun Dec 12 08:02:13 2021 -0800
Implementing barChartMerge trackDb option for faceted bar charts.

diff --git src/hg/lib/facetField.c src/hg/lib/facetField.c
index a2b3553..80c3940 100644
--- src/hg/lib/facetField.c
+++ src/hg/lib/facetField.c
@@ -61,30 +61,56 @@
 
 return newList;
 }
 
 
 static struct facetVal *facetValNew(char *val, int useCount)
 /* Create new facetVal structure */
 {
 struct facetVal *facetVal;
 AllocVar(facetVal);
 facetVal->val = val;
 facetVal->useCount = useCount;
 return facetVal;
 }
 
+int facetFieldCountSelected(struct facetField *facetField)
+/* Return number of facets in list that are selected */
+{
+if (facetField->allSelected)
+    return slCount(facetField->valList);
+else
+    {
+    int count = 0;
+    struct facetVal *facetVal;
+    for (facetVal = facetField->valList; facetVal != NULL; facetVal = facetVal->next)
+	if (facetVal->selected)
+	    ++count;
+    return count;
+    }
+}
+
+boolean facetFieldAnyMerged(struct facetField *list)
+/* Return TRUE if any facetField on list isMerged */
+{
+struct facetField *facetField;
+for (facetField = list; facetField != NULL; facetField = facetField->next)
+    if (facetField->isMerged)
+        return TRUE;
+return FALSE;
+}
+
 static void facetFieldAdd(struct facetField *facetField, char *tagVal, boolean selecting)
 /* Add information about tag to facetField */
 {
 if (!selecting)
     facetField->useCount += 1;
 struct facetVal *facetVal = hashFindVal(facetField->valHash, tagVal);
 if (facetVal == NULL)
     {
     AllocVar(facetVal);
     hashAddSaveName(facetField->valHash, tagVal, facetVal, &facetVal->val);
     slAddHead(&facetField->valList, facetVal);
     if (selecting)
 	{
 	facetVal->selected = TRUE;
 	facetField->allSelected = FALSE;
@@ -151,31 +177,31 @@
 	    // shown on GUI to guide choosing by user
 	}
     }
 return result;
 }
 
 #define facetValStringPunc '~'
 
 char *linearizeFacetVals(struct facetField *selectedList)
 /* Linearize selected fields vals into a string. fieldVal must be selected. */
 {
 struct dyString *dy = newDyString(1024);
 struct facetField *sff = NULL;
 for (sff = selectedList; sff; sff=sff->next)
     {
-    dyStringPrintf(dy, "%s %d ", sff->fieldName, sff->showAllValues);
+    dyStringPrintf(dy, "%s %d%d ", sff->fieldName, sff->showAllValues, sff->isMerged);
     boolean first = TRUE;
     struct facetVal *el;
     for (el=sff->valList; el; el=el->next)
 	{
 	if (el->selected)
 	    {
 	    if (first)
 		{
 		first = FALSE;
 		}
 	    else
 		dyStringAppendC(dy, ',');
 	    // TODO encode as csv val to support doubled internal quote value?
 	    dyStringPrintf(dy, "\"%s\"", el->val);  
 	    }
@@ -219,125 +245,131 @@
     {
     facetFieldAdd(sff, facetValue, TRUE);
     sff->currentVal->selected = FALSE;
     }
 else if (sameString(op, "showAllValues"))  // show all facet values
     {
     sff->showAllValues = TRUE;
     }
 else if (sameString(op, "showSomeValues"))  // show all facet values
     {
     sff->showAllValues = FALSE;
     }
 else if (sameString(op, "reset"))
     {
     sff->showAllValues = FALSE;
+    sff->isMerged = FALSE;
     struct facetVal *el;
     for (el=sff->valList; el; el=el->next)
 	{
 	el->selected = FALSE;
 	}
     }
+else if (sameString(op, "merge"))
+    {
+    sff->isMerged = TRUE;
+    }
+else if (sameString(op, "unmerge"))
+    {
+    sff->isMerged = FALSE;
+    }
 *pSelectedList = selectedList;
 }
 
 struct facetField *deLinearizeFacetValString(char *selectedFields)
 /* Turn linearized selected fields string back into facet structures */
 {
 struct facetField *ffList = NULL, *ff;
 boolean done = FALSE;
 while (!done)
     {
     if (sameString(selectedFields, ""))
 	break;
     char *end = strchr(selectedFields, facetValStringPunc);
     if (!end)
 	{
 	end = selectedFields + strlen(selectedFields);
 	done = TRUE;
 	}
     char saveEnd = *end;
     *end = 0;
     char *spc = strchr(selectedFields, ' ');
     if (!spc)
 	errAbort("expected space separating fieldname from showAllValues boolean");
     *spc = 0;
 
-    char *showAllValuesBoolean = spc+1;
-    char *spc2 = strchr(showAllValuesBoolean, ' ');
+    char *flagsBoolean = spc+1;
+    char *spc2 = strchr(flagsBoolean, ' ');
     if (!spc2)
 	errAbort("expected space separating showAllValues boolean from facet values list");
     *spc2 = 0;
 
     char *vals = spc2+1;
     struct slName *valList = NULL;
     if (*vals != 0)  // we have something
 	valList = csvParse(vals);
 
     ff = facetFieldNew(selectedFields);
-    ff->showAllValues = (*showAllValuesBoolean == '1');
+    ff->showAllValues = (flagsBoolean[0] == '1');
+    ff->isMerged = (flagsBoolean[1] == '1');
 
     slAddHead(&ffList, ff);
     struct slName *el;
     for (el=valList; el; el=el->next)
 	{
-	//uglyf("adding selected field %s val %s\n", selectedFields, el->name);
 	facetFieldAdd(ff, el->name, TRUE);
 	}
     
     *spc  = ' ';  // restore
     *spc2 = ' ';  // restore
     *end = saveEnd;
     selectedFields = end+1;
     }
 slReverse(&ffList);
 return ffList;
 }
 
 
 struct facetField *facetFieldsFromSqlTableInit(char *fields[], int fieldCount, char *selectedFields, struct facetField *ffArray[])
 /* Initialize ffList and ffArray and selected facet values */
 {
 /* Create facetField list and table. */
 struct facetField *ffList = NULL, *ff;
 int i;
 for (i=0; i<fieldCount; ++i)
     {
     ff = ffArray[i] = facetFieldNew(fields[i]);
     slAddHead(&ffList, ff);
     }
 slReverse(&ffList);
 
 /* Initialize selected facet values */
 if (selectedFields)
     {
-    //warn("facetFieldsFromSqlTableInit: selectedFields is NOT NULL [%s]\n", selectedFields);  // TODO REMOVE DEBUG
     struct facetField *selectedList = deLinearizeFacetValString(selectedFields);
     struct facetField *sff = NULL;
     for (sff = selectedList; sff; sff=sff->next)
 	{
-	//warn("facetFieldsFromSqlTableInit: looking for ff->fieldName [%s]\n", sff->fieldName);  // TODO REMOVE DEBUG
 	for (i=0; i<fieldCount; ++i)
 	    {
 	    if (sameString(ffArray[i]->fieldName, sff->fieldName))
 		{
-	        //warn("facetFieldsFromSqlTableInit: found ffArray[%d]->fieldName [%s]\n", i, ffArray[i]->fieldName);  // TODO REMOVE DEBUG
 		ffArray[i]->showAllValues = sff->showAllValues;
+		ffArray[i]->isMerged = sff->isMerged;
 		struct facetVal *el;
 		for (el=sff->valList; el; el=el->next)
 		    {
-		    //warn("adding selected field %s val %s\n", sff->fieldName, el->val);  // TODO REMOVE DEBUG
 		    facetFieldAdd(ffArray[i], el->val, TRUE);
 		    }
 		}
 	    }
         
 	}
     }
 return ffList;
 }
 
 void facetFieldsFromSqlTableFinish(struct facetField *ffList, int (*compare )(const void *elem1,  const void *elem2))
 /* Do final cleanup after passing over rows */
 {
 /* Sort lists */
 struct facetField *ff;
@@ -378,39 +410,40 @@
     if (perRowFacetFields(fieldCount, row, nullVal, ffArray))
 	++selectedRowCount;
     }
 
 facetFieldsFromSqlTableFinish(ffList, facetValCmpUseCountDesc);
 
 /* Clean up and go home */
 dyStringFree(&query);
 sqlFreeResult(&sr);
 
 if (pSelectedRowCount)
     *pSelectedRowCount = selectedRowCount;
 return ffList;
 }
 
-struct fieldedTable *facetFieldsFromFieldedTable(struct fieldedTable *ft, char *selectedFields,
+// struct fieldedTable *facetFieldsFromFieldedTable(struct fieldedTable *ft, char *selectionKey,
+struct fieldedTable *facetFieldSelectRows(struct fieldedTable *ft, char *selectionKey,
     struct facetField *ffArray[])
-/* Get a facetField list and initialize arrays based on selected fields from table 
- * ffArray must be big enough to hold all fields in table */
+/* Return a tables that is just rows of table ft that pass selection key.  ffArray should
+ * have same number of elements as ft->fieldCount */
 {
 int fieldCount = ft->fieldCount;
 struct fieldedTable *subTable = fieldedTableNew(ft->name, ft->fields, fieldCount);
 struct facetField *ffList = facetFieldsFromSqlTableInit(ft->fields, fieldCount, 
-    selectedFields, ffArray);
+    selectionKey, ffArray);
 struct fieldedRow *fr;
 for (fr = ft->rowList; fr != NULL; fr = fr->next)
     {
     if (perRowFacetFields(fieldCount, fr->row, "", ffArray))
 	{
 	fieldedTableAdd(subTable, fr->row, fieldCount, fr->id);
 	}
     }
 facetFieldsFromSqlTableFinish(ffList, facetValCmpUseCountDesc);
 return subTable;
 }
 
 struct facetVal *facetValMajorPlusOther(struct facetVal *list, double minRatio)
 /* Return a list of only the tags that are over minRatio of total tags.
  * If there are tags that have smaller amounts than this, lump them together