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 "help" int count = slCount(filterBySet); if(count == 1) - puts("
"); + puts("
"); else - printf("
Filter items by: (select multiple categories and items - %s)
\n",FILTERBY_HELP_LINK); + printf("Filter items by: (select multiple categories and items - %s)
\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("
"); if(count == 1) - printf("Filter by %s (select multiple items - %s)
\n",filterBy->title,FILTERBY_HELP_LINK); + printf("Filter by %s (select multiple items - %s)",filterBy->title,FILTERBY_HELP_LINK); else - printf("%s
\n",filterBy->title); + printf("%s",filterBy->title); + if (onOneLine && count > 1) + printf("
\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 ""); *opened = TRUE; } printf("
%s:",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("to"); 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(" (%g to %g)",altLabel,minLimit, maxLimit); else if(minLimit != NO_VALUE) printf(" (minimum %g)",altLabel,minLimit); else if(maxLimit != NO_VALUE) printf(" (maximum %g)",altLabel,maxLimit); else printf("to"); + 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(" (%d to %d)",altLabel,minLimit, maxLimit); + else if(minLimit != NO_VALUE) + printf(" (minimum %d)",altLabel,minLimit); + else if(maxLimit != NO_VALUE) + printf(" (maximum %d)",altLabel,maxLimit); + else + printf(""); 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("
"); 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("
"); 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("
"); + 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(""); 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("

Filter out NMD targets."); 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("
"); + 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)