bf1d058d73bdb153279eb4e530d1257d2ccc5675 angie Mon Jun 23 10:43:04 2014 -0700 Added ENCODE Regulatory summary tracks for clustered DNase and TFBS,with support for filtering based on BED5 score and factor/cellType/treatment. refs #11461 diff --git src/hg/hgVai/hgVai.c src/hg/hgVai/hgVai.c index da8ee5e..884a60a 100644 --- src/hg/hgVai/hgVai.c +++ src/hg/hgVai/hgVai.c @@ -70,30 +70,36 @@ " padding-top: 8px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px }\n" ".sectionLiteHeader { font-weight: bold; font-size:larger; color:#000000;" " text-align:left; vertical-align:bottom; white-space:nowrap; }\n" "div.sectionLiteHeader.noReorderRemove { padding-bottom:5px; }\n" "div.sourceFilter { padding-top: 5px; padding-bottom: 5px }\n" "\n"); } INLINE void startCollapsibleSection(char *sectionSuffix, char *title, boolean onByDefault) // Wrap shared args to jsBeginCollapsibleSectionFontSize { jsBeginCollapsibleSectionFontSize(cart, "hgva", sectionSuffix, title, onByDefault, "1.1em"); } +INLINE void startSmallCollapsibleSection(char *sectionSuffix, char *title, boolean onByDefault) +// Wrap shared args to jsBeginCollapsibleSectionFontSize +{ +jsBeginCollapsibleSectionFontSize(cart, "hgva", sectionSuffix, title, onByDefault, "0.9em"); +} + #define endCollapsibleSection jsEndCollapsibleSection static struct dyString *onChangeStart() /* Start up a javascript onChange command */ { struct dyString *dy = jsOnChangeStart(); jsTextCarryOver(dy, hgvaRegionType); jsTextCarryOver(dy, hgvaRange); return dy; } static char *onChangeClade() /* Return javascript executed when they change clade. */ { @@ -240,30 +246,138 @@ printf("
"); jsReloadOnBackButton(cart); webNewSection("Using the Variant Annotation Integrator"); webIncludeHelpFile("hgVaiHelpText", FALSE); +jsIncludeFile("jquery-ui.js", NULL); +jsIncludeFile("hgVarAnnogrator.js", NULL); +jsIncludeFile("ui.dropdownchecklist.js", NULL); +jsIncludeFile("ddcl.js", NULL); } void doUi() /* Set up globals and make web page */ { cartWebStart(cart, database, "Variant Annotation Integrator"); doMainPage(); cartWebEnd(); /* Save variables. */ cartCheckout(&cart); } void checkVariantTrack(struct trackDb *tdb) /* variantTrack should be either pgSnp or VCF. */ { @@ -1014,153 +1169,262 @@ return tableName; } char *tagFromTableName(char *tableName, char *suffix) /* Generate a tag for VEP's extras column or VCF's info column. */ { char *p = strstr(tableName, "dbNsfp"); if (p != NULL) tableName = p + strlen("dbNsfp"); int suffixLen = (suffix == NULL) ? 0 : strlen(suffix); int tagSize = strlen(tableName) + suffixLen + 1; char *tag = cloneStringZ(tableName, tagSize); if (isNotEmpty(suffix)) safecat(tag, tagSize, suffix); touppers(tag); +// Some custom shortenings, to avoid very long tag names: +(void)strSwapStrs(tag, tagSize, "POLYPHEN", "PP"); +(void)strSwapStrs(tag, tagSize, "MUTATION", "MUT"); +(void)strSwapStrs(tag, tagSize, "PHYLOP", "PHP"); +(void)strSwapStrs(tag, tagSize, "PHASTCONS", "PHC"); +(void)strSwapStrs(tag, tagSize, "ELEMENTS", "EL"); +(void)strSwapStrs(tag, tagSize, "PRIMATES", "PRIM"); +(void)strSwapStrs(tag, tagSize, "PLACENTAL", "PLAC"); +if (regexMatch(tag, "^PH.*[0-9]WAY")) + (void)strSwapStrs(tag, tagSize, "WAY", "W"); +(void)strSwapStrs(tag, tagSize, "WGENCODEREGDNASECLUSTERED", "DNASE"); +(void)strSwapStrs(tag, tagSize, "WGENCODEREGTFBSCLUSTERED", "TFBS"); return tag; } enum PolyPhen2Subset stripSubsetFromTrackName(char *trackName) /* trackName may have a _suffix for a subset of PolyPhen2; convert that to enum * and zero out the suffix so we have the real trackName. */ { enum PolyPhen2Subset subset = noSubset; char *p = strchr(trackName, ':'); if (p != NULL) { if (sameString(p+1, "HDIV")) subset = HDIV; else if (sameString(p+1, "HVAR")) subset = HVAR; else errAbort("unrecognized suffix in track_suffix '%s'", trackName); *p = '\0'; } return subset; } void updateGratorListAndVepExtra(struct annoGrator *grator, struct annoGrator **pGratorList, struct annoFormatter *vepOut, enum PolyPhen2Subset subset, - char *column, char *description) + char *column, char *description, boolean isReg) /* If grator is non-NULL, add it to gratorList and vepOut's list of items for EXTRAs column. */ { if (grator == NULL) return; slAddHead(pGratorList, grator); if (vepOut != NULL) { char *tableName = tableNameFromSourceName(grator->streamer.name); char *suffix = NULL; if (subset == HDIV) suffix = "HDIV"; else if (subset == HVAR) suffix = "HVAR"; char *tag = tagFromTableName(tableName, suffix); if (isEmpty(description)) description = grator->streamer.name; + if (isReg) + annoFormatVepAddRegulatory(vepOut, (struct annoStreamer *)grator, tag, description, column); + else annoFormatVepAddExtraItem(vepOut, (struct annoStreamer *)grator, tag, description, column); } } INLINE void updateGratorList(struct annoGrator *grator, struct annoGrator **pGratorList) /* If grator is non-NULL, add it to gratorList. */ { -updateGratorListAndVepExtra(grator, pGratorList, NULL, 0, NULL, NULL); +updateGratorListAndVepExtra(grator, pGratorList, NULL, 0, NULL, NULL, FALSE); } void addDbNsfpSeqChange(char *trackName, struct annoAssembly *assembly, struct hash *gratorsByName, struct annoGrator **pGratorList) // If the user has selected dbNsfp* data, we also need the underlying dbNsfpSeqChange // data, so annoFormatVep can tell whether the variant and gpFx are consistent with the // variant and transcript that dbNsfp used to calculate scores. { //#*** Yet another place where we need metadata: char *seqChangeTable = "dbNsfpSeqChange"; if (hashFindVal(gratorsByName, seqChangeTable) == NULL) { char *fileName = fileNameFromTable(seqChangeTable); if (fileName == NULL) errAbort("'%s' requested, but I can't find fileName for %s", trackName, seqChangeTable); struct annoGrator *grator = gratorFromBigDataFileOrUrl(fileName, assembly, NO_MAXROWS, agoNoConstraint); updateGratorList(grator, pGratorList); hashAdd(gratorsByName, seqChangeTable, grator); } } +static struct dyString *dyInfo = NULL; + +struct hash *getTrackFilterVars(char *track) +/* Return a hash of filter variable names (cart variable suffixes) to slName lists of values. */ +{ +char filterPrefix[512]; +safef(filterPrefix, sizeof(filterPrefix), "hgva_filter_%s_", track); +struct slPair *filterVars = cartVarsWithPrefix(cart, filterPrefix), *var; +int prefixLen = strlen(filterPrefix); +struct hash *varHash = hashNew(0); +for (var = filterVars; var != NULL; var = var->next) + { + char *varName = var->name+prefixLen; + char *val = var->val; + struct hashEl *hel = hashLookup(varHash, varName); + if (hel != NULL) + slNameAddHead((struct slName **)(&hel->val), val); + else + hashAdd(varHash, varName, slNameNew(val)); + } +return varHash; +} + +INLINE boolean isNotAll(struct slName *valList) +/* Return TRUE unless valList has one element with name "All" (for multiselects). */ +{ +if (slCount(valList) == 1 && sameString(valList->name, "All")) + return FALSE; +return TRUE; +} + +void factorSourceGratorAddFilter(struct annoGrator *grator, char *name, struct slName *valList) +/* Add filter to factorSource grator. */ +//#*** Do these smarts belong here in hgVai? Probably not -- should be an hg/lib module with +//#*** UI/metadata smarts. +{ +struct annoStreamer *gStreamer = (struct annoStreamer *)grator; +struct annoFilter *filter = NULL; +if (sameString(name, "name") || sameString(name, "cellType") || sameString(name, "treatment")) + { + if (valList && isNotAll(valList)) + filter = annoFilterFromAsColumn(gStreamer->asObj, name, afMatch, valList); + } +else if (sameString(name, "score")) + filter = annoFilterFromAsColumn(gStreamer->asObj, name, afGTE, valList); +else + errAbort("Unrecognized filter name '%s' for %s, type=factorSource", name, gStreamer->name); +if (filter) + gStreamer->addFilters(gStreamer, filter); +} + +void bed5AddFilter(struct annoGrator *grator, char *name, struct slName *valList) +/* Add filter to bed 5 grator. */ +{ +struct annoStreamer *gStreamer = (struct annoStreamer *)grator; +struct annoFilter *filter = NULL; +if (sameString(name, "name")) + { + if (valList && isNotAll(valList)) + filter = annoFilterFromAsColumn(gStreamer->asObj, name, afMatch, valList); + } +else if (sameString(name, "score")) + filter = annoFilterFromAsColumn(gStreamer->asObj, name, afGTE, valList); +else + errAbort("Unrecognized filter name '%s' for %s, type=bed 5", name, gStreamer->name); +if (filter) + gStreamer->addFilters(gStreamer, filter); +} + +void addFiltersToGrator(struct annoGrator *grator, struct trackDb *tdb) +/* Look for filter variables in the cart and add filters to grator accordingly. */ +{ +struct hash *varHash = getTrackFilterVars(tdb->track); +struct hashEl *hel, *helList = hashElListHash(varHash); +for (hel = helList; hel != NULL; hel = hel->next) + { + char *filterName = hel->name; + struct slName *valList = hel->val; +//#*** Need a much better way to dispatch... + if (sameString("factorSource", tdb->type)) + factorSourceGratorAddFilter(grator, filterName, valList); + else if (startsWith("bed 5", tdb->type)) + bed5AddFilter(grator, filterName, valList); + else + dyStringPrintf(dyInfo, "Ignoring %s filter %s\n", tdb->track, filterName); + } +hashFree(&varHash); +} + void addOutputTracks(struct annoGrator **pGratorList, struct hash *gratorsByName, struct annoFormatter *vepOut, struct annoAssembly *assembly, char *chrom, boolean doHtml) // Construct grators for tracks selected to appear in EXTRAS column { char trackPrefix[128]; safef(trackPrefix, sizeof(trackPrefix), "hgva_track_%s_", database); int trackPrefixLen = strlen(trackPrefix); struct slPair *trackVar, *trackVars = cartVarsWithPrefix(cart, trackPrefix); for (trackVar = trackVars; trackVar != NULL; trackVar = trackVar->next) { char *val = trackVar->val; if (! (sameWord(val, "on") || atoi(val) > 0)) continue; char *trackName = trackVar->name + trackPrefixLen; if (sameString(trackName, "dbNsfpPolyPhen2")) // PolyPhen2 must have a suffix now -- skip obsolete cartVar from existing carts continue; struct annoGrator *grator = hashFindVal(gratorsByName, trackName); if (grator != NULL) // We already have this as a grator: continue; enum PolyPhen2Subset subset = noSubset; char *description = NULL; char *column = NULL; + boolean isReg = FALSE; if (startsWith("dbNsfp", trackName)) { // trackName for PolyPhen2 has a suffix for subset -- strip it if we find it: subset = stripSubsetFromTrackName(trackName); description = dbNsfpDescFromTableName(trackName, subset, doHtml); addDbNsfpSeqChange(trackName, assembly, gratorsByName, pGratorList); char *fileName = fileNameFromTable(trackName); if (fileName != NULL) grator = gratorFromBigDataFileOrUrl(fileName, assembly, NO_MAXROWS, agoNoConstraint); } else { struct trackDb *tdb = tdbForTrack(database, trackName, &fullTrackList); if (tdb != NULL) { grator = gratorFromTrackDb(assembly, tdb->table, tdb, chrom, NO_MAXROWS, NULL, agoNoConstraint); if (grator != NULL) + { //#*** Need something more sophisticated but this works for our //#*** limited selection of extra tracks: if (asColumnFind(grator->streamer.asObj, "name") != NULL) column = "name"; + addFiltersToGrator(grator, tdb); + } description = tdb->longLabel; + isReg = isRegulatoryTrack(tdb, NULL); } } - updateGratorListAndVepExtra(grator, pGratorList, vepOut, subset, column, description); + updateGratorListAndVepExtra(grator, pGratorList, vepOut, subset, column, description, isReg); if (grator != NULL) hashAdd(gratorsByName, trackName, grator); } } void addFilterTracks(struct annoGrator **pGratorList, struct hash *gratorsByName, struct annoAssembly *assembly, char *chrom) // Add grators for filters (not added to vepOut): { if (!cartUsualBoolean(cart, "hgva_include_snpCommon", TRUE)) { struct annoGrator *grator = gratorForSnpBed4(gratorsByName, "Common", assembly, chrom, agoMustNotOverlap, NULL); updateGratorList(grator, pGratorList); } @@ -1818,30 +2082,31 @@ if (varTdb == NULL) { if (isHubTrack(variantTrack)) warn("Can't find hub track '%s'", variantTrack); else warn("Can't find tdb for variant track '%s'", variantTrack); } else checkVariantTrack(varTdb); return varTdb; } void doQuery() /* Translate simple form inputs into anno* components and execute query. */ { +dyInfo = dyStringNew(0); char *chrom = NULL; uint start = 0, end = 0; if (sameString(regionType, hgvaRegionTypeRange)) getCartPosOrDie(&chrom, &start, &end); struct annoAssembly *assembly = getAnnoAssembly(database); char *geneTrack = cartString(cart, "hgva_geneTrack"); struct trackDb *geneTdb = tdbForTrack(database, geneTrack, &fullTrackList); if (geneTdb == NULL) { warn("Can't find tdb for gene track %s", geneTrack); doUi(); return; } @@ -1897,48 +2162,50 @@ struct annoGrator *gratorList = NULL; slAddHead(&gratorList, gpVarGrator); if (snpGrator != NULL) slAddHead(&gratorList, snpGrator); // Text or HTML output? char *outFormat = cartUsualString(cart, "hgva_outFormat", "vepTab"); boolean doHtml = sameString(outFormat, "vepHtml"); // Initialize VEP formatter: struct annoFormatter *vepOut = annoFormatVepNew("stdout", doHtml, primary, primaryLongLabel, (struct annoStreamer *)gpVarGrator, geneTdb->longLabel, (struct annoStreamer *)snpGrator, - snpDesc); + snpDesc, assembly); addOutputTracks(&gratorList, gratorsByName, vepOut, assembly, chrom, doHtml); addFilterTracks(&gratorList, gratorsByName, assembly, chrom); slReverse(&gratorList); if (doHtml) { webStart(cart, database, "Annotated Variants in VEP/HTML format"); } else { // Undo the htmlPushEarlyHandlers() because after this point they make ugly text: popWarnHandler(); popAbortHandler(); textOpen(); webStartText(); } +if (isNotEmpty(dyInfo->string)) + puts(dyInfo->string); struct annoGratorQuery *query = annoGratorQueryNew(assembly, primary, gratorList, vepOut); struct slName *comment; for (comment = commentList; comment != NULL; comment = comment->next) vepOut->comment(vepOut, comment->name); if (chrom != NULL) annoGratorQuerySetRegion(query, chrom, start, end); annoGratorQueryExecute(query); annoGratorQueryFree(&query); if (doHtml) webEnd(); else textOutClose(&compressPipeline); }