b9d13eb62cfbe9db24ce1925de9efbd099354354
tdreszer
  Fri Feb 4 17:01:22 2011 -0800
Added support for '*Filter' generic score filter logic to beds
diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 2d79f11..68544f4 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -3459,57 +3459,61 @@
         if(notFirst)
             dyStringPrintf(dyClause, " AND ");
         dyStringAppend(dyClause, clause);
         freeMem(clause);
         notFirst = TRUE;
         }
     }
 if(dyStringLen(dyClause) == 0)
     {
     dyStringFree(&dyClause);
     return NULL;
     }
 return dyStringCannibalize(&dyClause);
 }
 
-void filterBySetCfgUi(struct trackDb *tdb, filterBy_t *filterBySet)
+void filterBySetCfgUi(struct trackDb *tdb, filterBy_t *filterBySet, boolean onOneLine)
 /* Does the UI for a list of filterBy structure */
 {
 if(filterBySet == NULL)
     return;
 
 #define FILTERBY_HELP_LINK  "<A HREF=\"../goldenPath/help/multiView.html\" TARGET=ucscHelp>help</A>"
 int count = slCount(filterBySet);
 if(count == 1)
-    puts("<BR><TABLE cellpadding=3><TR valign='top'>");
+    puts("<TABLE cellpadding=3><TR valign='top'>");
 else
-    printf("<BR><B>Filter items by:</B> (select multiple categories and items - %s)<TABLE cellpadding=3><TR valign='top'>\n",FILTERBY_HELP_LINK);
+    printf("<B>Filter items by:</B> (select multiple categories and items - %s)<TABLE cellpadding=3><TR valign='top'>\n",FILTERBY_HELP_LINK);
 
 filterBy_t *filterBy = NULL;
 jsIncludeFile("ui.core.js",NULL);
 jsIncludeFile("ui.dropdownchecklist.js",NULL);
 webIncludeResourceFile("ui.dropdownchecklist.css");
 
 int ix=0;
 for(filterBy = filterBySet;filterBy != NULL; filterBy = filterBy->next)
     {
     puts("<TD>");
     if(count == 1)
-        printf("<B>Filter by %s</B> (select multiple items - %s)<BR>\n",filterBy->title,FILTERBY_HELP_LINK);
+        printf("<B>Filter by %s</B> (select multiple items - %s)",filterBy->title,FILTERBY_HELP_LINK);
     else
-        printf("<B>%s</B><BR>\n",filterBy->title);
+        printf("<B>%s</B>",filterBy->title);
 
+    if (onOneLine && count > 1)
+        printf("<BR>\n");
+    else
+        printf(":\n");
     // TODO: Scroll long lists
     //#define FILTER_COMPOSITE_OPEN_SIZE 16
     // TODO: columnCount (Number of filterBoxes per row) should be configurable through tdb setting
     #define FILTER_BY_FORMAT "<SELECT id='fbc%d' name='%s.filterBy.%s' multiple style='display: none;' class='filterComp filterBy'><BR>\n"
     printf(FILTER_BY_FORMAT,ix,tdb->track,filterBy->column);
     ix++;
     printf("<OPTION%s>All</OPTION>\n",(filterBy->slChoices == NULL || slNameInList(filterBy->slChoices,"All")?" SELECTED":"") );
     struct slName *slValue;
     if(filterBy->useIndex)
         {
         int ix=1;
         for(slValue=filterBy->slValues;slValue!=NULL;slValue=slValue->next,ix++)
             {
             char varName[32];
             safef(varName, sizeof(varName), "%d",ix);
@@ -4677,34 +4681,35 @@
     }
 if(max)
     {
     safef(scoreLimitName, sizeof(scoreLimitName), "%s%s", scoreName, _MAX);
     deMax = cartOptionalStringClosestToHome(cart, tdb,FALSE,scoreLimitName);
     if(deMax != NULL)
         *max = atoi(deMax);
     }
 if(min)
     {
     safef(scoreLimitName, sizeof(scoreLimitName), "%s%s", scoreName, (max && deMax? _MIN:"")); // Warning: name changes if max!
     deMin = cartOptionalStringClosestToHome(cart, tdb,FALSE,scoreLimitName);
     if(deMin != NULL)
         *min = atoi(deMin);
     }
-if(min && limitMin && *min != NO_VALUE && *min < *limitMin) *min = *limitMin; // defaults within range
-if(min && limitMax && *min != NO_VALUE && *min > *limitMax) *min = *limitMax;
-if(max && limitMax && *max != NO_VALUE && *max > *limitMax) *max = *limitMax;
-if(max && limitMin && *max != NO_VALUE && *max < *limitMin) *max = *limitMin;
+// Defaulting min and max within limits.  Sorry for the horizontal ifs, but stacking the group makes them easier to follow
+if (min && limitMin && *limitMin != NO_VALUE && (*min == NO_VALUE || *min < *limitMin)) *min = *limitMin;
+if (min && limitMax && *limitMax != NO_VALUE &&                      *min > *limitMax)  *min = *limitMax;
+if (max && limitMax && *limitMax != NO_VALUE && (*max == NO_VALUE || *max > *limitMax)) *max = *limitMax;
+if (max && limitMin && *limitMin != NO_VALUE &&                      *max < *limitMin)  *max = *limitMin;
 }
 
 static void getScoreFloatRangeFromCart(struct cart *cart, struct trackDb *tdb, char *scoreName,
                                    double *limitMin,double *limitMax,double*min,double*max)
 /* gets an double score range from the cart, but the limits from trackDb
    for any of the pointers provided, will return a value found, if found, else it's contents
    are undisturbed (use NO_VALUE to recognize unavaliable values) */
 {
 char scoreLimitName[128];
 char *deMin=NULL,*deMax=NULL;
 if((limitMin || limitMax) && getScoreLimitsFromTdb(tdb,scoreName,NULL,&deMin,&deMax))
     {
     if(deMin != NULL && limitMin)
         *limitMin = strtod(deMin,NULL);
     if(deMax != NULL && limitMax)
@@ -4723,173 +4728,213 @@
     }
 if(max)
     {
     safef(scoreLimitName, sizeof(scoreLimitName), "%s%s", scoreName, _MAX);
     deMax = cartOptionalStringClosestToHome(cart, tdb,FALSE,scoreLimitName);
     if(deMax != NULL)
         *max = strtod(deMax,NULL);
     }
 if(min)
     {
     safef(scoreLimitName, sizeof(scoreLimitName), "%s%s", scoreName, _MIN); // name is always {filterName}Min
     deMin = cartOptionalStringClosestToHome(cart, tdb,FALSE,scoreLimitName);
     if(deMin != NULL)
         *min = strtod(deMin,NULL);
     }
-if(min && limitMin && (int)(*min) != NO_VALUE && *min < *limitMin) *min = *limitMin; // defaults within range
-if(min && limitMax && (int)(*min) != NO_VALUE && *min > *limitMax) *min = *limitMax;
-if(max && limitMax && (int)(*max) != NO_VALUE && *max > *limitMax) *max = *limitMax;
-if(max && limitMin && (int)(*max) != NO_VALUE && *max < *limitMin) *max = *limitMin;
+// Defaulting min and max within limits.  Sorry for the horizontal ifs, but stacking the group makes them easier to follow
+if (min && limitMin && (int)(*limitMin) != NO_VALUE && ((int)(*min) == NO_VALUE || *min < *limitMin)) *min = *limitMin;
+if (min && limitMax && (int)(*limitMax) != NO_VALUE &&                             *min > *limitMax)  *min = *limitMax;
+if (max && limitMax && (int)(*limitMax) != NO_VALUE && ((int)(*max) == NO_VALUE || *max > *limitMax)) *max = *limitMax;
+if (max && limitMin && (int)(*limitMin) != NO_VALUE &&                             *max < *limitMin)  *max = *limitMin;
 }
 
 static boolean showScoreFilter(struct cart *cart, struct trackDb *tdb, boolean *opened, boolean boxed,
                                boolean compositeLevel,char *name, char *title, char *label,
-                               char *scoreName,char *defaults,char *limitsDefault)
+                               char *scoreName, boolean isFloat)
 /* Shows a score filter control with minimum value and optional range */
 {
-char *setting = trackDbSettingClosestToHomeOrDefault(tdb, scoreName,defaults);//"0.0");
+char *setting = trackDbSetting(tdb, scoreName);
 if(setting)
     {
     if(*opened == FALSE)
         {
         boxed = cfgBeginBoxAndTitle(tdb, boxed, title);
         puts("<TABLE>");
         *opened = TRUE;
         }
     printf("<TR><TD align='right'><B>%s:</B><TD align='left'>",label);
     char varName[256];
     char altLabel[256];
     safef(varName, sizeof(varName), "%s%s", scoreName, _BY_RANGE);
     boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, varName);
+    // NOTE: could determine isFloat = (strchr(setting,'.') != NULL);  However, historical trackDb settings of pValueFilter did not always contain '.'
+    if (isFloat)
+        {
     double minLimit=NO_VALUE,maxLimit=NO_VALUE;
-    colonPairToDoubles(limitsDefault,&minLimit,&maxLimit);
     double minVal=minLimit,maxVal=maxLimit;
     colonPairToDoubles(setting,&minVal,&maxVal);
     getScoreFloatRangeFromCart(cart,tdb,scoreName,&minLimit,&maxLimit,&minVal,&maxVal);
     safef(varName, sizeof(varName), "%s.%s%s", name, scoreName, _MIN);
     safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Minimum ":""), label);
     cgiMakeDoubleVarWithLimits(varName,minVal, altLabel, 0,minLimit, maxLimit);
-    if(filterByRange) // TODO: Test this range stuff which is not yet used
+        if(filterByRange)
         {
         printf("<TD align='left'>to<TD align='left'>");
         safef(varName, sizeof(varName), "%s.%s%s", name, scoreName, _MAX);
         safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Maximum ":""), label);
         cgiMakeDoubleVarWithLimits(varName,maxVal, altLabel, 0,minLimit, maxLimit);
         }
     safef(altLabel, sizeof(altLabel), "%s", (filterByRange?"": "colspan=3"));
     if(minLimit != NO_VALUE && maxLimit != NO_VALUE)
         printf("<TD align='left'%s> (%g to %g)",altLabel,minLimit, maxLimit);
     else if(minLimit != NO_VALUE)
         printf("<TD align='left'%s> (minimum %g)",altLabel,minLimit);
     else if(maxLimit != NO_VALUE)
         printf("<TD align='left'%s> (maximum %g)",altLabel,maxLimit);
     else
         printf("<TD align='left'%s",altLabel);
+        }
+    else
+        {
+        int minLimit=NO_VALUE,maxLimit=NO_VALUE;
+        int minVal=minLimit,maxVal=maxLimit;
+        colonPairToInts(setting,&minVal,&maxVal);
+        getScoreIntRangeFromCart(cart,tdb,scoreName,&minLimit,&maxLimit,&minVal,&maxVal);
+        safef(varName, sizeof(varName), "%s.%s%s", name, scoreName, filterByRange ? _MIN:"");
+        safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Minimum ":""), label);
+        cgiMakeIntVarWithLimits(varName,minVal, altLabel, 0,minLimit, maxLimit);
+        if(filterByRange)
+            {
+            printf("<TD align='left'>to<TD align='left'>");
+            safef(varName, sizeof(varName), "%s.%s%s", name, scoreName, _MAX);
+            safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Maximum ":""), label);
+            cgiMakeIntVarWithLimits(varName,maxVal, altLabel, 0,minLimit, maxLimit);
+            }
+        safef(altLabel, sizeof(altLabel), "%s", (filterByRange?"": "colspan=3"));
+        if(minLimit != NO_VALUE && maxLimit != NO_VALUE)
+            printf("<TD align='left'%s> (%d to %d)",altLabel,minLimit, maxLimit);
+        else if(minLimit != NO_VALUE)
+            printf("<TD align='left'%s> (minimum %d)",altLabel,minLimit);
+        else if(maxLimit != NO_VALUE)
+            printf("<TD align='left'%s> (maximum %d)",altLabel,maxLimit);
+        else
+            printf("<TD align='left'%s",altLabel);
+        }
     puts("</TR>");
     return TRUE;
     }
 return FALSE;
 }
 
 
-//#define BED_SHOWALL_SCORE_FILTERS
-#ifdef BED_SHOWALL_SCORE_FILTERS
-static int scoreFiltersShowAll(struct cart *cart, struct trackDb *tdb, boolean *opened, boolean boxed,
+#ifdef ALL_SCORE_FILTERS_LOGIC
+static int numericFiltersShowAll(struct cart *cart, struct trackDb *tdb, boolean *opened, boolean boxed,
                                boolean compositeLevel,char *name, char *title)
 // Shows all *Filter style filters.  Note that these are in random order and have no graceful title
 {
 int count = 0;
 struct slName *filterSettings = trackDbSettingsWildMatch(tdb, "*Filter");
 if (filterSettings)
     {
     puts("<BR>");
     struct slName *filter = NULL;
+    struct slPair *extras = NULL;
+    char *extraFields = trackDbSetting(tdb, "extraFields");  // TODo: seems like there should be a cleaner way
+    if (extraFields != NULL)
+        extras = slPairFromString(extraFields);
+
     while ((filter = slPopHead(&filterSettings)) != NULL)
         {
-        if (differentString(filter->name,"noScoreFilter") && differentString(filter->name,"scoreFilter"))
+        if (differentString(filter->name,"noScoreFilter") && differentString(filter->name,"scoreFilter")) // TODO: scoreFilter could be included
             {
-            char label[128];
             char *field = cloneString(filter->name);
-            int ix = strlen(field) - strlen("filter");
+            int ix = strlen(field) - strlen("Filter");
             assert(ix > 0);
             field[ix] = '\0';
-            // Could lookup extraFields
-            char *extraFields = trackDbSetting(tdb, "extraFields");  // TODo: seems like there should be a cleaner way
-            if (extraFields)
+            // Could lookup extraFields  // TODO: Should we be using extra fields?  Could this be sorted by the order in extraFields?
+            if (extras != NULL)
                 {
-                char *extraField = NULL;
-                while ((extraField = nextWord(&extraFields)) != NULL)
-                    {
-                    if (startsWith(field,extraField))
-                        {
-                        // Found field so parse label
-                        extraField = cloneFirstWord(extraField);
-                        char *label = strchr(extraField,']');
-                        if (label == NULL)
-                            {
-                            label = strchr(extraField,'=');
-                            assert(label != NULL);
-                            }
+                char *foundLabel = slPairFindVal(extras, field);
+                if (foundLabel != NULL)
+                    { // Found label so replace field
                         freeMem(field);
-                        field = cloneString(label + 1);
-                        freeMem(extraField);
-                        break;
-                        }
+                    field = strchr(foundLabel,']');
+                    if (field == NULL)
+                        field = cloneString(foundLabel);
+                    else
+                        field = cloneString(field + 1);
+                    strSwapChar(field,'_',' ');
                     }
-
                 }
+            char label[128];
             safef(label,sizeof(label),"Minimum %s",field);
             freeMem(field);
-            showScoreFilter(cart,tdb,opened,boxed,compositeLevel,name,title,label,filter->name,NULL,NULL);//,"0.0",NULL);
+            // Determine floating point or integer
+            char *setting = trackDbSetting(tdb, filter->name);
+            boolean isFloat = (strchr(setting,'.') != NULL);
+            showScoreFilter(cart,tdb,opened,boxed,compositeLevel,name,title,label,filter->name,isFloat);
             count++;
             }
         slNameFree(&filter);
         }
     }
 if (count > 0)
     puts("</TABLE>");
 return count;
 }
-#endif///def BED_SHOWALL_SCORE_FILTERS
+#endif///def ALL_SCORE_FILTERS_LOGIC
 
 
 void scoreCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title,  int maxScore, boolean boxed)
 /* Put up UI for filtering bed track based on a score */
 {
 char option[256];
 boolean compositeLevel = isNameAtCompositeLevel(tdb,name);
+boolean skipScoreFilter = FALSE;
 filterBy_t *filterBySet = filterBySetGet(tdb,cart,name);
+
+#ifdef ALL_SCORE_FILTERS_LOGIC
+// Numeric filters are first
+boolean isBoxOpened = FALSE;
+if (numericFiltersShowAll(cart, tdb, &isBoxOpened, boxed, compositeLevel, name, title) > 0)
+    skipScoreFilter = TRUE;
+#endif///def ALL_SCORE_FILTERS_LOGIC
+
+// Add any multi-selects next
 if(filterBySet != NULL)
     {
-    if(!tdbIsComposite(tdb))
+    if(!tdbIsComposite(tdb) && cartOptionalString(cart, "ajax") == NULL)
         jsIncludeFile("hui.js",NULL);
 
-    filterBySetCfgUi(tdb,filterBySet);   // Note filterBy boxes don't need to be double "boxed"
+    if (!isBoxOpened)   // Note filterBy boxes are not double "boxed", if there are no other filters
+        printf("<BR>");
+    filterBySetCfgUi(tdb,filterBySet,TRUE);
     filterBySetFree(&filterBySet);
-    return; // Cannot have both 'filterBy' score and 'scoreFilter'
+    skipScoreFilter = TRUE;
     }
 
-#ifdef BED_SHOWALL_SCORE_FILTERS
-boolean isBoxOpened = FALSE;
-if (scoreFiltersShowAll(cart, tdb, &isBoxOpened, boxed, compositeLevel, name, title) > 0)
+// For no good reason scoreFilter is incompatible with filterBy and or numericFilters
+// FIXME scoreFilter should be implemented inside numericFilters and is currently specificly excluded to avoid unexpected changes
+if (skipScoreFilter)
     {
+    #ifdef ALL_SCORE_FILTERS_LOGIC
     if (isBoxOpened)
         cfgEndBox(boxed);
+    #endif///def ALL_SCORE_FILTERS_LOGIC
+
     return; // Cannot have both '*filter' and 'scoreFilter'
     }
-#endif///def BED_SHOWALL_SCORE_FILTERS
-
 
 boolean scoreFilterOk = (trackDbSettingClosestToHome(tdb, NO_SCORE_FILTER) == NULL);
 boolean glvlScoreMin = (trackDbSettingClosestToHome(tdb, GRAY_LEVEL_SCORE_MIN) != NULL);
 if (! (scoreFilterOk || glvlScoreMin))
     return;
 
 boxed = cfgBeginBoxAndTitle(tdb, boxed, title);
 
 if (scoreFilterOk)
     {
     int minLimit=0,maxLimit=maxScore,minVal=0,maxVal=maxScore;
     getScoreIntRangeFromCart(cart,tdb,SCORE_FILTER,&minLimit,&maxLimit,&minVal,&maxVal);
 
     boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, SCORE_FILTER _BY_RANGE);
     if (filterByRange)
@@ -5190,38 +5235,75 @@
         {
         if((int)max == NO_VALUE || ((int)maxLimit != NO_VALUE && maxLimit == max))
             dyStringPrintf(extraWhere, "%s(%s >= %g)", (*and?" and ":""),field,min);  // min only
         else if((int)min == NO_VALUE || ((int)minLimit != NO_VALUE && minLimit == min))
             dyStringPrintf(extraWhere, "%s(%s <= %g)", (*and?" and ":""),field,max);  // max only
         else
             dyStringPrintf(extraWhere, "%s(%s BETWEEN %g and %g)", (*and?" and ":""),field,min,max); // both min and max
 #endif//ndef FILTER_ASSUMES_RANGE_AT_LIMITS_IS_VALID_FILTER
         *and=TRUE;
         }
     }
     //if(dyStringLen(extraWhere)) warn("SELECT FROM %s WHERE %s",tdb->table,dyStringContents(extraWhere));
 return extraWhere;
 }
 
+#ifdef ALL_SCORE_FILTERS_LOGIC
+struct dyString *dyAddAllScoreFilters(struct cart *cart, struct trackDb *tdb, struct dyString *extraWhere,boolean *and)
+/* creates the where clause condition to gather together all random double filters
+   Filters are expected to follow
+        {fiterName}: trackDb min or min:max - default value(s);
+        {filterName}Min or {filterName}: min (user supplied) cart variable;
+        {filterName}Max: max (user supplied) cart variable;
+        {filterName}Limits: trackDb allowed range "0.0:10.0" Optional
+            uses:  defaultLimits: function param if no tdb limits settings found)
+   The 'and' param and dyString in/out allows stringing multiple where clauses together */
+{
+struct slName *filterSettings = trackDbSettingsWildMatch(tdb, "*Filter");
+if (filterSettings)
+    {
+    struct slName *filter = NULL;
+    while ((filter = slPopHead(&filterSettings)) != NULL)
+        {
+        if (differentString(filter->name,"noScoreFilter") && differentString(filter->name,"scoreFilter")) // TODO: scoreFilter could be included
+            {
+            char *field = cloneString(filter->name);
+            int ix = strlen(field) - strlen("filter");
+            assert(ix > 0);
+            field[ix] = '\0';
+            char *setting = trackDbSetting(tdb, filter->name);
+            // How to determine float or int ?  If actual tracDb setting has decimal places, then float!
+            if (strchr(setting,'.') == NULL)
+                extraWhere = dyAddFilterAsInt(cart,tdb,extraWhere,filter->name,"0:1000",field,and);
+            else
+                extraWhere = dyAddFilterAsDouble(cart,tdb,extraWhere,filter->name,NULL,field,and);
+            }
+        slNameFree(&filter);
+        }
+    }
+return extraWhere;
+}
+#endif///def ALL_SCORE_FILTERS_LOGIC
+
 void encodePeakCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed)
 /* Put up UI for filtering wgEnocde peaks based on score, Pval and Qval */
 {
 boolean compositeLevel = isNameAtCompositeLevel(tdb,name);
 boolean opened = FALSE;
-showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum Q-Value (-log 10)",QVALUE_FILTER,NULL,NULL);//,"0.0",NULL);
-showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum P-Value (-log 10)",PVALUE_FILTER,NULL,NULL);//,"0.0",NULL);
-showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum Signal value",     SIGNAL_FILTER,NULL,NULL);//,"0.0",NULL);
+showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum Q-Value (-log 10)",QVALUE_FILTER,TRUE);
+showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum P-Value (-log 10)",PVALUE_FILTER,TRUE);
+showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum Signal value",     SIGNAL_FILTER,TRUE);
 
 char *setting = trackDbSettingClosestToHomeOrDefault(tdb, SCORE_FILTER,NULL);//"0:1000");
 if(setting)
     {
     if(!opened)
         {
         boxed = cfgBeginBoxAndTitle(tdb, boxed, title);
         puts("<TABLE>");
         opened = TRUE;
         }
     char varName[256];
     int minLimit=0,maxLimit=1000,minVal=0,maxVal=NO_VALUE;
     colonPairToInts(setting,&minVal,&maxVal);
     getScoreIntRangeFromCart(cart,tdb,SCORE_FILTER,&minLimit,&maxLimit,&minVal,&maxVal);
     if(maxVal != NO_VALUE)
@@ -5294,31 +5376,32 @@
     nmdDefault = cartUsualBoolean(cart,varName, FALSE);  // TODO: var name (hgt prefix) needs changing before ClosesToHome can be used
     printf("<p><b>Filter out NMD targets.</b>");
     cgiMakeCheckBox(varName, nmdDefault);
     }
 
 if(!sameString(tdb->track, "tigrGeneIndex")
 && !sameString(tdb->track, "ensGeneNonCoding")
 && !sameString(tdb->track, "encodeGencodeRaceFrags"))
     baseColorDropLists(cart, tdb, name);
 
 if (cartOptionalString(cart, "ajax") == NULL)
     {
     filterBy_t *filterBySet = filterBySetGet(tdb,cart,name);
     if(filterBySet != NULL)
         {
-        filterBySetCfgUi(tdb,filterBySet);
+        printf("<BR>");
+        filterBySetCfgUi(tdb,filterBySet,FALSE);
         filterBySetFree(&filterBySet);
         }
     }
 cfgEndBox(boxed);
 }
 
 static boolean isSpeciesOn(struct cart *cart, struct trackDb *tdb, char *species, char *option, int optionSize, boolean defaultState)
 /* check the cart to see if species is turned off or on (default is defaultState) */
 {
 boolean ret = defaultState;
 safef(option, optionSize, "%s.%s", tdb->track, species);
 
 /* see if this is a simple multiz (not composite track) */
 char *s = cartOptionalString(cart, option);
 if (s != NULL)