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 (if any) "
"associated with each transcript.
");
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);
char *desc = hTableExists(database, "knownToTag") ?
"based on
"
"APPRIS status or inclusion in "
"
GENCODE Basic subset: "
"principal > alternative > basic > longest isoform" :
"generally the longest isoform of a gene";
printf("Indicate whether each transcript is 'canonical' (%s).
\n", desc);
puts("
");
}
if (hTableExists(database, "refGene") && genbankTableExists(database, refSeqStatusTable))
{
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();
}
static boolean canDoHgvsOut(char *geneTrack)
/* Return TRUE if we're able to make HGVS output terms for transcripts in geneTrack. */
{
return sameString(geneTrack, "refGene") || startsWith("ncbiRefSeq", geneTrack);
}
static void selectHgvsOut(char *geneTrack)
/* Offer HGVS output choices if RefSeq Genes are selected */
{
startCollapsibleSection("hgvsOut", "HGVS variant nomenclature", TRUE);
printf("The Human Genome Variation Society (HGVS) "
"has established a "
"sequence variant nomenclature, "
"an international standard used to report variation in "
"genomic, transcript and protein sequences.
\n");
boolean hgvsOk = canDoHgvsOut(geneTrack);
printf("", hgvsOk ? "block" : "none");
cartMakeCheckBox(cart, "hgva_hgvsG", FALSE);
printf("Include HGVS genomic (g.) terms in output
\n");
cartMakeCheckBox(cart, "hgva_hgvsCN", FALSE);
printf("Include HGVS coding (c.) terms if applicable, otherwise noncoding (n.) terms, in output"
"
\n");
cartMakeCheckBox(cart, "hgva_hgvsP", FALSE);
printf("Include HGVS protein (p.) terms (if applicable) in output
\n");
cartMakeCheckBox(cart, "hgva_hgvsPAddParens", FALSE);
printf("When including HGVS protein (p.) terms, add parentheses around changes to emphasize "
"that they are predictions
\n");
cartMakeCheckBox(cart, "hgva_hgvsBreakDelIns", FALSE);
printf("For variants that involve both a deletion and insertion, "
"including multi-nucleotide variants, "
"include the deleted sequence (e.g. show \"delAGinsTT\" instead of only \"delinsTT\")"
"
\n");
puts("
");
printf("",
hgvsOk ? "none" : "block");
printf("Select RefSeq Genes in the \"Select Genes\" section above "
"in order to make options appear.\n");
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(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 && !hasTxStat)
return;
puts("
");
printf("\n");
// Make wrapper table for collapsible sections:
puts("");
selectDbNsfp(dbNsfpTables);
selectTxStatus(hasTxStat, geneTrack);
selectHgvsOut(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");
cartMakeCheckBox(cart, "hgva_include_noVariation", TRUE);
printf("\"variants\" for which no alternate allele has been observed
\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;
cgiMakeOnEventRadioButtonWithClass("hgva_require_consEl_track", tdb->track,
sameString(tdb->track, selected),
NULL, "click", "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("subDisclmAgrd","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);
jsInlineF(
"$(document).ready(function() { hgva.disclaimer.init(%s, hgva.userClickedAgree); });\n"
, alreadyAgreed ? "true" : "false");
addSomeCss();
printAssemblySection();
puts("
");
// Make wrapper table for collapsible sections:
selectVariants();
char *geneTrack = selectGenes();
if (geneTrack != NULL)
{
selectRegulatory();
selectAnnotations(geneTrack);
selectFilters();
selectOutput();
submitAndDisclaimer();
}
printf("