582e9ba06d359ee167ca2a60b495cd6d4fe9d69f
angie
Wed Feb 12 10:56:52 2014 -0800
In snp125+ track controls, don't show options for class and validationcodes that don't appear in the table. For example, validation codes
by-hapmap and by-1000genomes are not applicable for non-human genomes;
and only a subset of the class codes are used, sometimes a small subset.
refs #12490
diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index fb77ce3..6e09033 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -230,82 +230,183 @@
safef(cartVar, sizeof(cartVar), "%s.include_%s", track, attributeVar);
jsMakeCheckboxGroupSetClearButton(cartVar, TRUE);
puts(" ");
jsMakeCheckboxGroupSetClearButton(cartVar, FALSE);
printf("\n
\n");
boolean foundInCart = FALSE;
struct slName *selectedAttributes = snp125FilterFromCart(cart, track, attributeVar, &foundInCart);
// Include all by default:
if (! foundInCart)
selectedAttributes = slNameListFromStringArray(values, menuSize);
cgiMakeCheckboxGroupWithVals(cartVar, labels, values, menuSize, selectedAttributes,
SNP125_FILTER_COLUMNS);
printf(" |
\n");
}
-static char *commaSepFromSqlSetTypeDecl(struct sqlFieldInfo *fi, char *table)
-/* Destructively prepare fi->type for chopCommas: strip initial "set(" and final ")",
- * informatively errAborting if not found, and strip the single-quote characters
- * that mysql puts around each field. */
+static char *commaSepFromSqlEnumOrSetTypeDecl(struct sqlFieldInfo *fi, char *type, char *table)
+/* Destructively prepare fi->type for chopCommas. type is either "enum" or "set".
+ * Strip the initial "set(" or "enum(" and final ")", informatively errAborting if not found,
+ * and strip the single-quote characters that mysql puts around each field. */
+{
+if (sameString(type, "enum"))
+ {
+ if (!startsWith("enum(", fi->type))
+ errAbort("Expected %s.%s's type to begin with 'enum(' but got '%s'",
+ table, fi->field, fi->type);
+ }
+else if (sameString(type, "set"))
{
if (!startsWith("set(", fi->type))
errAbort("Expected %s.%s's type to begin with 'set(' but got '%s'",
table, fi->field, fi->type);
-char *vals = fi->type + strlen("set(");
+ }
+char *vals = fi->type + strlen(type) + 1;
char *rightParen = strrchr(vals, ')');
if (rightParen == NULL || rightParen[1] != '\0')
errAbort("Expected %s.%s's type to end with ')' but got '%s'",
table, fi->field, fi->type);
else
*rightParen = '\0';
stripChar(vals, '\'');
return vals;
}
+static struct slName *snp125FixClassGlobals(struct trackDb *tdb)
+/* Fix snp125Class* global variables to contain only the classes that are present
+ * in the SQL enum type definition. Return a list of classes that are not present. */
+{
+struct sqlConnection *conn = hAllocConn(database);
+struct sqlFieldInfo *fi, *fiList = sqlFieldInfoGet(conn, tdb->table);
+hFreeConn(&conn);
+struct slName *unusedList = NULL;
+boolean foundClass = FALSE;
+for (fi = fiList; fi != NULL; fi = fi->next)
+ {
+ if (sameString(fi->field, "class"))
+ {
+ foundClass = TRUE;
+ char *vals = commaSepFromSqlEnumOrSetTypeDecl(fi, "enum", tdb->table);
+ char *values[64]; // max 11 in older tables
+ int valCount = chopCommas(vals, values);
+ char *labels[valCount];
+ char *defaults[valCount];
+ char *oldVars[valCount];
+ // Use labels from old static array
+ int i;
+ for (i = 0; i < valCount; i++)
+ {
+ int oldIx = stringArrayIx(values[i], snp125ClassDataName, snp125ClassArraySize);
+ labels[i] = snp125ClassLabels[oldIx];
+ defaults[i] = snp125ClassDefault[oldIx];
+ oldVars[i] = snp125ClassOldColorVars[oldIx];
+ }
+ // Make a list of unused values;
+ for (i = 0; i < snp125ClassArraySize; i++)
+ {
+ if (stringArrayIx(snp125ClassDataName[i], values, valCount) < 0)
+ slAddHead(&unusedList, slNameNew(snp125ClassDataName[i]));
+ }
+ // Now overwrite old globals with the correct contents.
+ snp125ClassArraySize = valCount;
+ for (i = 0; i < valCount; i++)
+ {
+ snp125ClassDataName[i] = cloneString(values[i]);
+ snp125ClassLabels[i] = cloneString(labels[i]);
+ snp125ClassDefault[i] = cloneString(defaults[i]);
+ snp125ClassOldColorVars[i] = cloneString(oldVars[i]);
+ }
+ }
+ }
+if (! foundClass)
+ errAbort("Didn't find definition of func field in %s", tdb->table);
+return unusedList;
+}
+
+static void snp125MakeHiddenInputsForUnused(char *cartVar, struct slName *unusedList)
+/* If this db's snpNNN table uses only a small subset of the global arrays, but some
+ * other db's snpNNN table uses a larger subset, we don't want to have the effect of
+ * turning off the checkboxes that aren't used in this db's snpNNN. So make hidden
+ * inputs to pretend that all unused values' checkboxes are checked. */
+{
+struct slName *unused;
+for (unused = unusedList; unused != NULL; unused = unused->next)
+ cgiMakeHiddenVar(cartVar, unused->name);
+}
+
static void snp137PrintFunctionFilterControls(struct trackDb *tdb)
/* As of snp137, show func filter choices based on sql field set
* values and Sequence Ontology (SO) terms so we won't have to
* hardcode menus as new functional categories are added. */
{
struct sqlConnection *conn = hAllocConn(database);
struct sqlFieldInfo *fi, *fiList = sqlFieldInfoGet(conn, tdb->table);
hFreeConn(&conn);
for (fi = fiList; fi != NULL; fi = fi->next)
{
if (sameString(fi->field, "func"))
{
- char *vals = commaSepFromSqlSetTypeDecl(fi, tdb->table);
+ char *vals = commaSepFromSqlEnumOrSetTypeDecl(fi, "set", tdb->table);
char *values[128]; // 22 values as of snp137
int valCount = chopCommas(vals, values);
char *labels[valCount];
int i;
for (i = 0; i < valCount; i++)
{
if (sameString(values[i], "unknown"))
labels[i] = "Unknown";
else
labels[i] = snpMisoLinkFromFunc(values[i]);
}
snp125PrintFilterControls(tdb->track, "Function", "func", labels, values, valCount);
- return;;
+ return;
}
}
errAbort("Didn't find definition of func field in %s", tdb->table);
}
+int snp125ValidArraySize(int version)
+/* Figure out how many validation options are applicable to this database and version. */
+{
+// Cache result since it costs a mysql query and won't change
+static int size = 0;
+if (size == 0)
+ {
+ size = snp125ValidArraySizeNonHuman;
+ if (sameString(hOrganism(database), "Human"))
+ {
+ size = snp125ValidArraySizeHuman;
+ if (version < 130)
+ size--; // no by-1000genomes
+ }
+ }
+return size;
+}
+
+static void snp125MakeHiddenInputsForValid(char *cartVar, int version)
+/* Non-human dbs' snpNNN tables use only a subset of the validation codes, but human dbs'
+ * snpNNN tables use all of them. When making options for non-human dbs, we don't want
+ * to have the effect of turning off the checkboxes that aren't used (but would be for human).
+ * So make hidden inputs to pretend that all unused values' checkboxes are checked. */
+{
+int i;
+for (i = snp125ValidArraySize(version); i < snp125ValidArraySizeHuman; i++)
+ cgiMakeHiddenVar(cartVar, snp125ValidDataName[i]);
+}
+
static void snp125PrintFilterControlSection(struct trackDb *tdb, int version,
- boolean molTypeHasMito)
+ boolean molTypeHasMito,
+ struct slName *snp125UnusedClasses)
/* Print a collapsible section of filtering controls on SNP properties, first numeric
* and then enum/set. */
{
char cartVar[512];
printf(" |
\n");
jsBeginCollapsibleSection(cart, tdb->track, "filterByAttribute", "Filtering Options", FALSE);
printf("
\n");
safef(cartVar, sizeof(cartVar), "%s.minAvHet", tdb->track);
double minAvHet = cartUsualDouble(cart, cartVar,
// Check old cart var name:
cartUsualDouble(cart, "snp125AvHetCutoff", SNP125_DEFAULT_MIN_AVHET));
printf("Minimum Average Heterozygosity: ");
cgiMakeDoubleVar(cartVar, minAvHet, 6);
printf("
\n");
@@ -350,32 +451,36 @@
printf("Filter by attribute:
\n");
printf("Check the boxes below to include SNPs with those attributes. "
"In order to be displayed, a SNP must pass the filter for each "
"category. \n"
"Some assemblies may not contain any SNPs that have some of the "
"listed attributes.\n"
"
\n");
printf("\n");
if (version <= 127)
snp125PrintFilterControls(tdb->track, "Location Type", "locType", snp125LocTypeLabels,
snp125LocTypeDataName, snp125LocTypeArraySize);
snp125PrintFilterControls(tdb->track, "Class", "class", snp125ClassLabels,
snp125ClassDataName, snp125ClassArraySize);
+safef(cartVar, sizeof(cartVar), "%s.include_%s", tdb->track, "class");
+snp125MakeHiddenInputsForUnused(cartVar, snp125UnusedClasses);
snp125PrintFilterControls(tdb->track, "Validation", "valid", snp125ValidLabels,
- snp125ValidDataName, snp125ValidArraySize);
+ snp125ValidDataName, snp125ValidArraySize(version));
+safef(cartVar, sizeof(cartVar), "%s.include_%s", tdb->track, "valid");
+snp125MakeHiddenInputsForValid(cartVar, version);
if (version < 137)
{
int funcArraySize = (version < 130) ? snp125FuncArraySize : (snp125FuncArraySize - 1);
snp125PrintFilterControls(tdb->track, "Function", "func", snp125FuncLabels,
snp125FuncDataName, funcArraySize);
}
else
snp137PrintFunctionFilterControls(tdb);
int molTypeArraySize = snp125MolTypeArraySize;
if (! molTypeHasMito)
molTypeArraySize--;
snp125PrintFilterControls(tdb->track, "Molecule Type", "molType", snp125MolTypeLabels,
snp125MolTypeDataName, molTypeArraySize);
if (version >= 132)
{
@@ -443,31 +548,31 @@
static void snp125ResetColorVarsIfNecessary(struct trackDb *tdb, char *buttonVar, int version)
/* If the 'Set defaults' button has been clicked, remove all color-control cart variables. */
{
// Note we use CGI, not cart, to detect a click:
if (isNotEmpty(cgiOptionalString(buttonVar)))
{
char cartVar[512];
safef(cartVar, sizeof(cartVar), "%s.colorSource", tdb->track);
cartRemove(cart, cartVar);
cartRemove(cart, snp125ColorSourceOldVar);
snp125RemoveColorVars(cart, snp125LocTypeOldColorVars, TRUE, snp125LocTypeArraySize,
tdb->track, "locType");
snp125RemoveColorVars(cart, snp125ClassOldColorVars, TRUE, snp125ClassArraySize,
tdb->track, "class");
- snp125RemoveColorVars(cart, snp125ValidOldColorVars, TRUE, snp125ValidArraySize,
+ snp125RemoveColorVars(cart, snp125ValidOldColorVars, TRUE, snp125ValidArraySizeHuman,
tdb->track, "valid");
int funcArraySize = (version < 130) ? snp125FuncArraySize : (snp125FuncArraySize - 1);
snp125RemoveColorVars(cart, snp125FuncOldColorVars, TRUE, funcArraySize,
tdb->track, "func");
snp125RemoveColorVars(cart, snp125MolTypeOldColorVars, TRUE, snp125MolTypeArraySize,
tdb->track, "molType");
snp125RemoveColorVars(cart, snp132ExceptionVarName, FALSE, snp132ExceptionArraySize,
tdb->track, "exceptions");
snp125RemoveColorVars(cart, snp132BitfieldVarName, FALSE, snp132BitfieldArraySize,
tdb->track, "bitfields");
}
}
void snp125PrintColorControlSection(struct trackDb *tdb, int version, boolean molTypeHasMito)
/* Print a collapsible section of color controls: user selects an attribute to color by,
@@ -523,35 +628,37 @@
"options for the feature selected above will be used to color items;\n"
"color options for other features will not be shown.\n");
if (version > 127 && colorSourceCart == snp125ColorSourceLocType)
colorSourceCart = SNP125_DEFAULT_COLOR_SOURCE;
switch (colorSourceCart)
{
int funcArraySize, excArraySize, molTypeArraySize;
case snp125ColorSourceLocType:
snp125PrintColorSpec(tdb->track, "locType", snp125LocTypeOldColorVars, TRUE,
snp125LocTypeLabels, snp125LocTypeDefault,
snp125LocTypeArraySize);
break;
case snp125ColorSourceClass:
snp125PrintColorSpec(tdb->track, "class", snp125ClassOldColorVars, TRUE,
- snp125ClassLabels, snp125ClassDefault, snp125ClassArraySize);
+ snp125ClassLabels, snp125ClassDefault,
+ snp125ClassArraySize);
break;
case snp125ColorSourceValid:
snp125PrintColorSpec(tdb->track, "valid", snp125ValidOldColorVars, TRUE,
- snp125ValidLabels, snp125ValidDefault, snp125ValidArraySize);
+ snp125ValidLabels, snp125ValidDefault,
+ snp125ValidArraySize(version));
break;
case snp125ColorSourceFunc:
funcArraySize = (version < 130) ? snp125FuncArraySize : (snp125FuncArraySize - 1);
snp125PrintColorSpec(tdb->track, "func", snp125FuncOldColorVars, TRUE,
snp125FuncLabels, snp125FuncDefault, funcArraySize);
break;
case snp125ColorSourceMolType:
molTypeArraySize = snp125MolTypeArraySize;
if (! molTypeHasMito)
molTypeArraySize--;
snp125PrintColorSpec(tdb->track, "molType", snp125MolTypeOldColorVars, TRUE,
snp125MolTypeLabels, snp125MolTypeDefault, molTypeArraySize);
break;
case snp125ColorSourceExceptions:
excArraySize = snp132ExceptionArraySize;
@@ -589,57 +696,55 @@
if (sameString(*enumVals, "mito"))
gotMito = TRUE;
enumVals++;
}
hFreeConn(&conn);
return gotMito;
}
void snp125Ui(struct trackDb *tdb)
/* UI for dbSNP version 125 and later. */
{
char *orthoTable = snp125OrthoTable(tdb, NULL);
int version = snpVersion(tdb->track);
char cartVar[512];
jsInit();
-
-if (version < 130)
- snp125ValidArraySize--; // no by-1000genomes
+struct slName *snp125UnusedClasses = snp125FixClassGlobals(tdb);
if (isNotEmpty(orthoTable) && hTableExists(database, orthoTable))
{
printf("
Include Chimp state and observed human alleles in name: ");
safef(cartVar, sizeof(cartVar), "%s.extendedNames", tdb->track);
snp125ExtendedNames = cartUsualBoolean(cart, cartVar,
// Check old cart var name for backwards compatibility w/ old sessions:
cartUsualBoolean(cart, "snp125ExtendedNames", FALSE));
cgiMakeCheckBox(cartVar, snp125ExtendedNames);
printf("
(If enabled, chimp allele is displayed first, then '>', then human alleles).");
printf("
\n");
}
else
puts("
");
// Make wrapper table for collapsible sections:
puts("");
snp125OfferGeneTracksForFunction(tdb);
boolean molTypeHasMito = snp125CheckMolTypeForMito(tdb);
puts("
|
");
-snp125PrintFilterControlSection(tdb, version, molTypeHasMito);
+snp125PrintFilterControlSection(tdb, version, molTypeHasMito, snp125UnusedClasses);
puts("
|
");
snp125PrintColorControlSection(tdb, version, molTypeHasMito);
// End wrapper table for collapsible sections:
puts("
");
}
void snpUi(struct trackDb *tdb)
/* Put up UI snp data. */
{
int snpSource = 0;
int snpMolType = 0;
int snpClass = 0;
int snpValid = 0;
int snpFunc = 0;