08ec019f344fc52bd83ea3a98bedccd0048d732c angie Mon May 24 00:04:08 2021 -0700 Let the user upload a file containing names or IDs of sequences already in the selected tree; run matUtils extract to get subtrees that include those sequences. protobufs.tab gets a new optional column to specify a file that maps alias to tree name/ID (e.g. for mapping EPI_ISL to public names/IDs). diff --git src/hg/hgPhyloPlace/hgPhyloPlace.c src/hg/hgPhyloPlace/hgPhyloPlace.c index 2b40aaf..dd8661e 100644 --- src/hg/hgPhyloPlace/hgPhyloPlace.c +++ src/hg/hgPhyloPlace/hgPhyloPlace.c @@ -138,62 +138,62 @@ // Container for bootstrap grid layout puts( "<div class='container-fluid'>\n"); } static void newPageEndStuff() { puts( "</div>"); jsIncludeFile("utils.js", NULL); webIncludeFile("inc/gbFooter.html"); webEndJWest(); } -#define CHECK_FILE_INPUT_JS "{ var $fileInput = $('input[name="seqFileVar"]'); " \ +#define CHECK_FILE_INPUT_JS(varName) "{ var $fileInput = $('input[name="varName"]'); " \ "if ($fileInput && $fileInput[0] && $fileInput[0].files && !$fileInput[0].files.length) {" \ " alert('Please choose a file first, then click the upload button.');" \ " return false; " \ "} else { loadingImage.run(); return true; } }" static void inputForm() /* Ask the user for FASTA or VCF. */ { printf("<form action='%s' name='mainForm' method=POST enctype='multipart/form-data'>\n\n", "hgPhyloPlace"); cartSaveSession(cart); char *db = "wuhCor1"; cgiMakeHiddenVar("db", db); puts(" <div class='gbControl col-md-12'>"); puts("<div class='readableWidth'>"); puts("<p>Upload your SARS-CoV-2 sequence (FASTA or VCF file) to find the most similar\n" "complete, high-coverage samples from \n" "<a href='https://www.gisaid.org/' target='_blank'>GISAID</a>\n" "or from public sequence databases (" "<a href='https://www.ncbi.nlm.nih.gov/labs/virus/vssi/#/virus?SeqType_s=Nucleotide&VirusLineage_ss=SARS-CoV-2,%20taxid:2697049' " "target=_blank>NCBI Virus / GenBank</a>,\n" "<a href='https://www.cogconsortium.uk/data/' target=_blank>COG-UK</a> and the\n" "<a href='https://bigd.big.ac.cn/ncov/release_genome' " "target=_blank>China National Center for Bioinformation</a>), " "and your sequence's placement in the phylogenetic tree generated by the\n" "<a href='https://github.com/roblanf/sarscov2phylo' target='_blank'>sarscov2phylo</a>\n" "pipeline.\n" "Placement is performed by\n" "<a href='https://github.com/yatisht/usher' target=_blank>" "Ultrafast Sample placement on Existing tRee (UShER)</a> " - "(<a href='https://www.biorxiv.org/content/10.1101/2020.09.26.314971v1' target=_blank>" + "(<a href='https://www.nature.com/articles/s41588-021-00862-7' target=_blank>" "Turakhia <em>et al.</em></a>). UShER also generates local subtrees to show samples " "in the context of the most closely related sequences. The subtrees can be visualized " "as Genome Browser custom tracks and/or using " "<a href='https://nextstrain.org' target=_blank>Nextstrain</a>'s interactive display " "which supports " "<a href='"NEXTSTRAIN_DRAG_DROP_DOC"' " "target=_blank>drag-and-drop</a> of local metadata that remains on your computer.</p>\n"); puts("</div>"); puts("</div>"); puts("<div class='readableWidth'>"); puts("<div class='gbControl col-md-12'>\n" "<div style='float:left; margin-right: 10px;'>" "<iframe width='267' height='150' src='https://www.youtube.com/embed/humQ1NyZOUM' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen></iframe>\n" "</div><p>" "The <a href='https://www.cdc.gov/amd/training/covid-19-gen-epi-toolkit.html' target=_blank>" @@ -215,51 +215,50 @@ "<p>We do not store your information " "(aside from the information necessary to display results)\n" "and will not share it with others unless you choose to share your Genome Browser view.</p>\n" "<p>In order to enable rapid progress in SARS-CoV-2 research and genomic contact tracing,\n" "please share your SARS-CoV-2 sequences by submitting them to an " "<a href='https://ncbiinsights.ncbi.nlm.nih.gov/2020/08/17/insdc-covid-data-sharing/' " "target=_blank>INSDC</a> member institution\n" "(<a href='https://submit.ncbi.nlm.nih.gov/sarscov2/' target=_blank>NCBI</a>,\n" "<a href='https://www.covid19dataportal.org/submit-data' target=_blank>EMBL-EBI</a>\n" "or <a href='https://www.ddbj.nig.ac.jp/ddbj/websub.html' target=_blank>DDBJ</a>)\n" "and <a href='https://www.gisaid.org/' target=_blank>GISAID</a>.\n" "</p>\n"); puts("</div>"); puts(" </div>"); puts(" <div class='gbControl col-md-12'>"); -printf("<p>Select your FASTA or VCF file: "); -printf("<input type='file' id='%s' name='%s' " - "accept='.fa, .fasta, .vcf, .vcf.gz, .fa.gz, .fasta.gz'>", +printf("<p>Select your FASTA, VCF or list of sequence names/IDs: "); +printf("<input type='file' id='%s' name='%s'>", seqFileVar, seqFileVar); struct treeChoices *treeChoices = loadTreeChoices(db); if (treeChoices) { puts("</p><p>"); printf("Phylogenetic tree version: "); char *phyloPlaceTree = cartOptionalString(cart, "phyloPlaceTree"); cgiMakeDropListWithVals("phyloPlaceTree", treeChoices->descriptions, treeChoices->protobufFiles, treeChoices->count, phyloPlaceTree); } puts("</p><p>"); printf("Number of samples per subtree showing sample placement: "); int subtreeSize = cartUsualInt(cart, "subtreeSize", 50); cgiMakeIntVarWithLimits("subtreeSize", subtreeSize, "Number of samples in subtree showing neighborhood of placement", - 5, 10, 2000); + 5, 10, 5000); puts("</p><p>"); -cgiMakeOnClickSubmitButton(CHECK_FILE_INPUT_JS, "submit", "upload"); +cgiMakeOnClickSubmitButton(CHECK_FILE_INPUT_JS(seqFileVar), "submit", "upload"); puts("</p>"); // Add a loading image to reassure people that we're working on it when they upload a big file printf("<div><img id='loadingImg' src='../images/loading.gif' />\n"); printf("<span id='loadingMsg'></span></div>\n"); jsInline("$(document).ready(function() {\n" " loadingImage.init($('#loadingImg'), $('#loadingMsg'), " "'<p style=\"color: red; font-style: italic;\">Uploading and processing your sequences " "may take some time. Please leave this window open while we work on your sequences.</p>');" "});\n"); puts(" </div>"); puts("</form>"); } static void exampleForm() @@ -361,43 +360,45 @@ // Form submits subtree custom tracks to hgTracks printf("<form action='%s' name='resultsForm' method=%s>\n\n", hgTracksName(), cartUsualString(cart, "formMethod", "POST")); cartSaveSession(cart); puts(" <div class='gbControl col-md-12'>"); fflush(stdout); if (lf != NULL) { // Use trackLayout to get hgTracks parameters relevant to displaying trees: struct trackLayout tl; trackLayoutInit(&tl, cart); // Do our best to place the user's samples, make custom tracks if successful: char *phyloPlaceTree = cartOptionalString(cart, "phyloPlaceTree"); int subtreeSize = cartUsualInt(cart, "subtreeSize", 50); + boolean success = FALSE; char *ctFile = phyloPlaceSamples(lf, db, phyloPlaceTree, measureTiming, subtreeSize, - tl.fontHeight); + tl.fontHeight, &success); if (ctFile) { cgiMakeHiddenVar(CT_CUSTOM_TEXT_VAR, ctFile); if (tl.leftLabelWidthChars < 0 || tl.leftLabelWidthChars == leftLabelWidthDefaultChars) cgiMakeHiddenVar(leftLabelWidthVar, leftLabelWidthForLongNames); cgiMakeButton("submit", "view in Genome Browser"); puts(" </div>"); puts("</form>"); } - else + else if (! success) { + puts("<p></p>"); puts(" </div>"); puts("</form>"); // Let the user upload something else and try again: inputForm(); } } else { warn("Unable to read your uploaded data - please choose a file and try again, or click the " ""try example" button."); // Let the user try again: puts(" </div>"); puts("</form>"); inputForm(); exampleForm();