into buf. Return buf for convenience. */
+{
+safef(buf, bufSize, GENCODE_PREFIX"%s%s", suffix, version);
+return buf;
+}
+
+boolean refGeneHasGencodeTags(struct slName *gencodeVersionList)
+/* Return TRUE if this database has a wgEncodeGencodeRefSeq table as well as a ...Tag table. */
+{
+char *version = getLatestGencodeVersion(gencodeVersionList);
+char table[PATH_LEN];
+return hTableExists(database, gencodeTableName("RefSeq", version, table, sizeof(table)));
+}
+
+boolean startsWithGencodeGene(char *geneTrack)
+/* Return TRUE if geneTrack starts with wgEncodeGencode{Basic,Comp,PseudoGene}.
+ * (There are other GENCODE genepred tracks that don't have tags associated with them.) */
+{
+return (startsWith(GENCODE_PREFIX"Basic", geneTrack) ||
+ startsWith(GENCODE_PREFIX"Comp", geneTrack) ||
+ startsWith(GENCODE_PREFIX"PseudoGene", geneTrack));
+}
+
+boolean isGencodeWithVersion(char *geneTrack, struct slName *versionList)
+/* Return TRUE if geneTrack looks like a Gencode gene track for a supported version. */
+{
+if (! startsWithGencodeGene(geneTrack))
+ return FALSE;
+struct slName *v;
+for (v = versionList; v != NULL; v = v->next)
+ {
+ if (endsWith(geneTrack, v->name))
+ return TRUE;
+ }
+return FALSE;
+}
+
+void selectTxStatus(boolean hasTxStatus, char *geneTrack)
+/* Offer to include transcript status, e.g. whether it is in knownCanonical or has GENCODE tags.
+ * This makes one div per category of txStatus info; each div is visible only if its info is
+ * applicable to the selected gene track. If no divs are visible, display a message that
+ * there's nothing for the currently selected gene track. */
+{
+if (! hasTxStatus)
+ return;
+startCollapsibleSection("txStatus", "Transcript status", FALSE);
+boolean somethingIsVisible = FALSE;
+if (hasGencodeTags())
+ {
+ struct slName *versionList = getGencodeTagVersions();
+ char *maybeKnownGene = knownGeneHasGencodeTags() ? "knownGene" : "";
+ char *maybeRefGene = refGeneHasGencodeTags(versionList) ? "refGene" : "";
+ char *maybeEnsGene = "";
+ char *versions = "";
+ if (versionList != NULL)
+ {
+ if (hTableExists(database, "ensGene"))
+ maybeEnsGene = "ensGene";
+ versions = slNameListToString(versionList, ' ');
+ }
+ boolean isVisible = (sameString(geneTrack, maybeKnownGene) ||
+ sameString(geneTrack, maybeEnsGene) ||
+ sameString(geneTrack, maybeRefGene) ||
+ isGencodeWithVersion(geneTrack, versionList));
+ somethingIsVisible |= isVisible;
+ printf("",
+ maybeKnownGene, maybeRefGene, maybeEnsGene, versions,
+ isVisible ? "block" : "none");
+ cartMakeCheckBox(cart, "hgva_txStatus_gencode", FALSE);
+ puts("Include the
GENCODE tags for each transcript (if available).
");
+ puts("
");
+ }
+if (hTableExists(database, "knownGene") && hTableExists(database, "knownCanonical"))
+ {
+ boolean isVisible = sameString(geneTrack, "knownGene");
+ somethingIsVisible |= isVisible;
+ printf("",
+ isVisible ? "block" : "none");
+ cartMakeCheckBox(cart, "hgva_txStatus_knownCanonical", FALSE);
+ puts("Indicate whether each UCSC Genes transcript is 'canonical' (generally the longest "
+ "isoform of a gene).
");
+ puts("
");
+ }
+if (hTableExists(database, "refGene") && hTableExists(database, "refSeqStatus"))
+ {
+ boolean isVisible = sameString(geneTrack, "refGene");
+ somethingIsVisible |= isVisible;
+ printf("",
+ isVisible ? "block" : "none");
+ cartMakeCheckBox(cart, "hgva_txStatus_refSeqStatus", FALSE);
+ puts("Include the "
+ "
RefSeq status of each transcript.
");
+ puts("
");
+ }
+printf("",
+ somethingIsVisible ? "none" : "block");
+puts("No transcript status data are available for the selected gene track.");
+puts("
");
+puts("
");
+endCollapsibleSection();
+}
+
boolean isHg19RegulatoryTrack(struct trackDb *tdb, void *filterData)
/* For now, just look for a couple specific tracks by tableName. */
{
//#*** NEED METADATA
return (sameString("wgEncodeRegDnaseClusteredV3", tdb->table) ||
sameString("wgEncodeRegTfbsClusteredV3", tdb->table));
}
boolean isHg38RegulatoryTrack(struct trackDb *tdb, void *filterData)
/* For now, just look for a couple specific tracks by tableName. */
{
//#*** NEED METADATA
return (sameString("wgEncodeRegDnaseClustered", tdb->table) ||
sameString("wgEncodeRegTfbsClusteredV3", tdb->table));
}
struct slRef *findRegulatoryTracks()
/* Look for the very limited set of Regulation tracks that hgVai offers. */
{
struct slRef *regTrackRefList = NULL;
if (sameString(database, "hg19"))
tdbFilterGroupTrack(fullTrackList, fullGroupList, isHg19RegulatoryTrack,
NULL, NULL, ®TrackRefList);
else if (sameString(database, "hg38"))
tdbFilterGroupTrack(fullTrackList, fullGroupList, isHg38RegulatoryTrack,
NULL, NULL, ®TrackRefList);
return regTrackRefList;
}
void selectRegulatory()
/* If trackRefList is non-NULL, make a section with a checkbox for each track,
* labelled with longLabel, and optionally some filtering options. */
{
struct slRef *trackRefList = findRegulatoryTracks();
if (trackRefList != NULL)
{
puts("
");
printf("\n");
printf("The annotations in this section provide predicted regulatory regions "
"based on various experimental data. "
"When a variant overlaps an annotation selected here, the consequence term "
"regulatory_region_variant will be assigned. "
"Follow the links to description pages that explain how each dataset was "
"constructed. "
"Some datasets cover a significant portion of the genome and it may be "
"desirable to filter these annotations by cell type and/or score in order "
"to avoid an overabundance of hits. ");
// Use a table with checkboxes in one column and label/other stuff that depends on
// checkbox in other column.
puts("");
struct slRef *ref;
for (ref = trackRefList; ref != NULL; ref = ref->next)
{
struct trackDb *tdb = ref->val;
char cartVar[512];
safef(cartVar, sizeof(cartVar), "hgva_track_%s_%s", database, tdb->track);
puts("");
cartMakeCheckBox(cart, cartVar, FALSE);
puts(" | ");
struct trackDb *topTdb = trackDbTopLevelSelfOrParent(tdb);
printf("%s \n", hgTrackUiName(), cartSidUrlString(cart),
topTdb->track, tdb->longLabel);
printFilterOptions(tdb);
puts(" |
");
}
puts("
");
}
}
boolean isConsElTrack(struct trackDb *tdb, void *filterData)
/* This is a TdbFilterFunction to get "phastConsNwayElements" tracks. */
{
return (startsWith("phastCons", tdb->table) && stringIn("Elements", tdb->table));
}
boolean isConsScoreTrack(struct trackDb *tdb, void *filterData)
/* This is a TdbFilterFunction to get tracks that start with "phastCons" (no Elements)
* or "phyloP". */
{
return ((startsWith("phastCons", tdb->table) && !stringIn("Elements", tdb->table))
|| startsWith("phyloP", tdb->table));
}
void findCons(struct slRef **retElTrackRefList, struct slRef **retScoreTrackRefList)
/* See if this database has Conserved Elements and/or Conservation Scores */
{
tdbFilterGroupTrack(fullTrackList, fullGroupList, isConsElTrack,
NULL, NULL, retElTrackRefList);
tdbFilterGroupTrack(fullTrackList, fullGroupList, isConsScoreTrack,
NULL, NULL, retScoreTrackRefList);
}
boolean trackNameMatches(struct trackDb *tdb, void *filterData)
/* This is a TdbFilterFunction to get track(s) whose tdb->track matches name (filterData). */
{
char *name = filterData;
return sameString(tdb->track, name);
}
struct slRef *findTrackRefByName(char *name)
/* Return a reference to the named track, if found. */
{
struct slRef *trackRefList = NULL;
tdbFilterGroupTrack(fullTrackList, fullGroupList, trackNameMatches, name, NULL, &trackRefList);
return trackRefList;
}
void trackCheckBoxSection(char *sectionSuffix, char *title, struct slRef *trackRefList)
/* If trackRefList is non-NULL, make a collapsible section with a checkbox for each track,
* labelled with longLabel. */
{
if (trackRefList != NULL)
{
startCollapsibleSection(sectionSuffix, title, FALSE);
struct slRef *ref;
for (ref = trackRefList; ref != NULL; ref = ref->next)
{
struct trackDb *tdb = ref->val;
char cartVar[512];
safef(cartVar, sizeof(cartVar), "hgva_track_%s_%s", database, tdb->track);
cartMakeCheckBox(cart, cartVar, FALSE);
struct trackDb *topTdb = trackDbTopLevelSelfOrParent(tdb);
printf("%s
\n", hgTrackUiName(), cartSidUrlString(cart),
topTdb->track, tdb->longLabel);
}
puts("
");
endCollapsibleSection();
}
}
-void selectAnnotations()
+void selectAnnotations(char *geneTrack)
/* Beyond predictions of protein-coding effect, what other basic data can we integrate? */
{
struct slName *dbNsfpTables = findDbNsfpTables();
boolean gotSnp = findSnpBed4("", NULL, NULL);
struct slRef *elTrackRefList = NULL, *scoreTrackRefList = NULL;
findCons(&elTrackRefList, &scoreTrackRefList);
struct slRef *cosmicTrackRefList = findTrackRefByName("cosmic");
+boolean hasTxStat = hasTxStatus();
if (dbNsfpTables == NULL && !gotSnp && elTrackRefList == NULL && scoreTrackRefList == NULL &&
- cosmicTrackRefList == NULL)
+ cosmicTrackRefList == NULL && !hasTxStat)
return;
puts("
");
printf("\n");
// Make wrapper table for collapsible sections:
puts("");
selectDbNsfp(dbNsfpTables);
+selectTxStatus(hasTxStat, geneTrack);
selectDbSnp(gotSnp);
trackCheckBoxSection("Cosmic", "COSMIC", cosmicTrackRefList);
trackCheckBoxSection("ConsEl", "Conserved elements", elTrackRefList);
trackCheckBoxSection("ConsScore", "Conservation scores", scoreTrackRefList);
puts("
");
}
void selectFiltersFunc()
/* Options to restrict variants based on gene region/soTerm from gpFx */
{
startCollapsibleSection("filtersFunc", "Functional role", FALSE);
printf("Include variants annotated as
\n");
jsMakeSetClearContainer();
cartMakeCheckBox(cart, "hgva_include_intergenic", TRUE);
printf("intergenic
\n");
cartMakeCheckBox(cart, "hgva_include_upDownstream", TRUE);
printf("upstream/downstream of gene
\n");
cartMakeCheckBox(cart, "hgva_include_nmdTranscript", TRUE);
printf("in transcript already subject to nonsense-mediated decay (NMD)
\n");
cartMakeCheckBox(cart, "hgva_include_exonLoss", TRUE);
printf("exon loss caused by deletion
\n");
cartMakeCheckBox(cart, "hgva_include_utr", TRUE);
printf("5' or 3' UTR
\n");
cartMakeCheckBox(cart, "hgva_include_cdsSyn", TRUE);
printf("CDS - synonymous coding change
\n");
cartMakeCheckBox(cart, "hgva_include_cdsNonSyn", TRUE);
printf("CDS - non-synonymous (missense, stop gain/loss, frameshift etc)
\n");
cartMakeCheckBox(cart, "hgva_include_intron", TRUE);
printf("intron
\n");
cartMakeCheckBox(cart, "hgva_include_splice", TRUE);
printf("splice site or splice region
\n");
cartMakeCheckBox(cart, "hgva_include_nonCodingExon", TRUE);
printf("exon of non-coding gene
\n");
struct slRef *regTrackRefList = findRegulatoryTracks();
if (regTrackRefList != NULL)
{
cartMakeCheckBox(cart, "hgva_include_regulatory", TRUE);
printf("regulatory element (note: these are detected only if one or more tracks "
"are selected in Regulatory regions above)
\n");
}
jsEndContainer();
puts("
");
endCollapsibleSection();
}
void selectFiltersKnownVar()
/* Options to restrict output based on overlap with known variants. */
{
boolean gotCommon = findSnpBed4("Common", NULL, NULL);
boolean gotMult = findSnpBed4("Mult", NULL, NULL);
if (!gotCommon && !gotMult)
return;
startCollapsibleSection("filtersVar", "Known variation", FALSE);
if (gotMult)
{
cartMakeCheckBox(cart, "hgva_include_snpMult", TRUE);
printf("Include variants even if they are co-located with variants that have been mapped to "
"multiple genomic locations by dbSNP
\n");
}
if (gotCommon)
{
cartMakeCheckBox(cart, "hgva_include_snpCommon", TRUE);
printf("Include variants even if they are co-located with \"common\" variants "
"(uniquely mapped variants with global minor allele frequency (MAF) "
"of at least 1%% according to dbSNP)
\n");
}
puts("
");
endCollapsibleSection();
}
void selectFiltersCons()
/* Options to restrict output based on overlap with conserved elements. */
{
struct slRef *elTrackRefList = NULL;
tdbFilterGroupTrack(fullTrackList, fullGroupList, isConsElTrack, NULL, NULL, &elTrackRefList);
if (elTrackRefList == NULL)
return;
startCollapsibleSection("filtersCons", "Conservation", FALSE);
// Use a little table to indent radio buttons (if we do those) past checkbox:
puts("");
cartMakeCheckBox(cart, "hgva_require_consEl", FALSE);
printf(" | Include only the variants that overlap:");
if (slCount(elTrackRefList) == 1)
{
struct trackDb *tdb = elTrackRefList->val;
printf(" %s \n", tdb->longLabel);
cgiMakeHiddenVar("hgva_require_consEl_track", tdb->track);
puts(" |
");
}
else
{
puts("");
char *selected = cartUsualString(cart, "hgva_require_consEl_track", "");
struct slRef *ref;
for (ref = elTrackRefList; ref != NULL; ref = ref->next)
{
printf(" | ");
struct trackDb *tdb = ref->val;
cgiMakeOnClickRadioButton("hgva_require_consEl_track", tdb->track,
sameString(tdb->track, selected),
"onclick=\"setCheckboxList('hgva_require_consEl', true);\"");
printf("%s |
\n", tdb->longLabel);
}
puts("");
}
endCollapsibleSection();
}
void selectFilters()
/* Options to restrict output to variants with specific properties */
{
puts("
");
printf("\n");
puts("");
selectFiltersFunc();
selectFiltersKnownVar();
selectFiltersCons();
puts("
");
}
void selectOutput()
/* Just VEP text for now... should also have VEP HTML with limited # lines too.
* Next: custom track with same subset of info as we would stuff in VEP */
{
puts("
");
printf("\n");
printf("output format: ");
char *selected = cartUsualString(cart, "hgva_outFormat", "vepTab");
printf("
\n");
char *compressType = cartUsualString(cart, "hgva_compressType", textOutCompressNone);
char *fileName = cartUsualString(cart, "hgva_outFile", "");
printf("output file: ");
cgiMakeTextVar("hgva_outFile", fileName, 29);
printf(" (leave blank to keep output in browser)
\n");
printf("file type returned: ");
cgiMakeRadioButton("hgva_compressType", textOutCompressNone,
sameWord(textOutCompressNone, compressType));
printf(" plain text  ");
cgiMakeRadioButton("hgva_compressType", textOutCompressGzip,
sameWord(textOutCompressGzip, compressType));
printf(" gzip compressed (ignored if output file is blank)");
puts("
");
}
void submitAndDisclaimer()
{
puts("");
puts("This tool is for research use only. While this tool is open to the "
"public, users seeking information about a personal medical or genetic "
"condition are urged to consult with a qualified physician for "
"diagnosis and for answers to personal questions.");
puts("
");
printf("
\n");
printf("
\n");
cgiMakeOnClickButton("hgva.submitQueryIfDisclaimerAgreed();", "Get results");
puts("
");
}
/*
* When user clicks submit, we need to roll a JSON querySpec from form selections,
* and show data from a submission to hgAnnoGrator. redirect from this CGI?
* or have javascript submit directly?
* * primary: variants, from custom track
* * if there are genes, those w/annoGratorGpVar
* * if there are {dbSNP, dbNsfp, regulatory, cons} selections, grator for each of those
* * vep output config
*
* If we get bold & offer 1000Genomes VCF, will def. need handling of split chroms.
* Are we really going to offer genome-wide in hgVai?
* Up-front limit on #rows of input ?
*
* Eventually, we might want a FormatVep that produces structs that are passed
* forward to multiple output writers... I would want to send it lots of gratorData
* like a formatter, but it would produce rows like an annoGrator.
* Maybe annoGrators should accept a bunch of input rows like formatters?
* or would this grator wrap all the input grators inside?
*/
void doMainPage()
/* Print out initial HTML of control page. */
{
jsInit();
webIncludeResourceFile("jquery-ui.css");
webIncludeResourceFile("ui.dropdownchecklist.css");
boolean alreadyAgreed = cartUsualBoolean(cart, "hgva_agreedToDisclaimer", FALSE);
printf("\n", alreadyAgreed ? "true" : "false");
addSomeCss();
printAssemblySection();
/* Check for variant custom tracks. If there are none, tell user they need to
* upload at least one. */
struct slRef *varTrackList = NULL, *varGroupList = NULL;
tdbFilterGroupTrack(fullTrackList, fullGroupList, isVariantCustomTrack, NULL,
&varGroupList, &varTrackList);
puts("
");
// Make wrapper table for collapsible sections:
selectVariants(varGroupList, varTrackList);
-boolean gotGP = selectGenes();
-if (gotGP)
+char *geneTrack = selectGenes();
+if (geneTrack != NULL)
{
selectRegulatory();
- selectAnnotations();
+ selectAnnotations(geneTrack);
selectFilters();
selectOutput();
submitAndDisclaimer();
}
printf("