da3772f3615ae3aa407af6aa2215a1b2ff480183 angie Mon Apr 29 13:40:41 2024 -0700 If configured, use nextclade to align sequences (better for more diverged viruses like influenza). Also fix some buttons that the last change broke. diff --git src/hg/hgPhyloPlace/phyloPlace.c src/hg/hgPhyloPlace/phyloPlace.c index 28189b4..b3c2da1 100644 --- src/hg/hgPhyloPlace/phyloPlace.c +++ src/hg/hgPhyloPlace/phyloPlace.c @@ -295,31 +295,31 @@ errAbort("Missing usher executable (expected to be at %s)", usherPath); return NULL; } char *getMatUtilsPath(boolean abortIfNotFound) /* Return hgPhyloPlaceData/matUtils if it exists, else NULL. Do not free the returned value. */ { char *matUtilsPath = PHYLOPLACE_DATA_DIR "/matUtils"; if (fileExists(matUtilsPath)) return matUtilsPath; else if (abortIfNotFound) errAbort("Missing matUtils executable (expected to be at %s)", matUtilsPath); return NULL; } -static char *getNextcladePath() +char *getNextcladePath() /* Return hgPhyloPlaceData/nextclade if it exists, else errAbort. Do not free the returned value. */ { char *nextcladePath = PHYLOPLACE_DATA_DIR "/nextclade"; if (fileExists(nextcladePath)) return nextcladePath; else errAbort("Missing nextclade executable (expected to be at %s)", nextcladePath); return NULL; } //#*** This needs to go in a lib so CGIs know whether to include it in the menu. needs better name. boolean hgPhyloPlaceEnabled() /* Return TRUE if hgPhyloPlace is enabled in hg.conf and db wuhCor1 exists. */ { char *cfgSetting = cfgOption("hgPhyloPlaceEnabled"); @@ -1477,65 +1477,69 @@ struct dyString *dy = dyStringCreate("%s/MicrobeTrace/?url=", microbeTraceHost()); return dyStringCannibalize(&dy); } static char *microbeTraceUrlFromTn(struct tempName *jsonTn) /* Return a link to MicrobeTrace to view an annotated subtree. */ { char *jsonUrl = urlFromTn(jsonTn); char *urlBase = microbeTraceUrlBase(); struct dyString *dy = dyStringCreate("%s%s", urlBase, jsonUrl); freeMem(jsonUrl); freeMem(urlBase); return dyStringCannibalize(&dy); } -static void makeSubtreeDropdown(char *subtreeDropdownName, struct subtreeInfo *subtreeInfoList, - struct tempName **jsonTns) +static char *makeSubtreeDropdown(struct subtreeInfo *subtreeInfoList, struct tempName **jsonTns) /* Let user choose subtree to view */ { +static int serial = 0; +char subtreeDropdownName[128]; +safef(subtreeDropdownName, sizeof subtreeDropdownName, "subtreeSelect%d", serial++); int count = slCount(subtreeInfoList); char *labels[count]; char *values[count]; struct subtreeInfo *ti; int ix; for (ix = 0, ti = subtreeInfoList; ti != NULL; ti = ti->next, ix++) { struct dyString *dy = dyStringCreate("subtree %d", ix+1); labels[ix] = dyStringCannibalize(&dy); values[ix] = urlFromTn(jsonTns[ix]); } cgiMakeDropListWithVals(subtreeDropdownName, labels, values, count, NULL); for (ix = 0; ix < count; ix++) { freeMem(labels[ix]); } +return cloneString(subtreeDropdownName); } static void makeSubtreeJumpButton(char *subtreeDropdownName, char *dest, char *destUrlBase, char *destUrlParams, boolean skipProtocol) /* Make a button with javascript to get a JSON filename from a dropdown element, format a link * to dest, and jump to that dest when clicked. */ { +static int serial = 0; char *mouseover = "view selected subtree with your sequences and other sequences from the " "full phylogenetic tree for context"; struct dyString *js = dyStringCreate("jsonUrl = document.querySelector('select[name=\"%s\"]').value;" "if (%d) { ix = jsonUrl.indexOf('://');" " if (ix >= 0) { jsonUrl = jsonUrl.substr(ix+3); } }" "window.open('%s' + jsonUrl + '%s');", subtreeDropdownName, skipProtocol, destUrlBase, destUrlParams); -struct dyString *id = dyStringCreate("jumpTo%s", dest); +struct dyString *id = dyStringCreate("jumpTo%s_%d", dest, serial++); printf("<input type='button' id='%s' value='%s' title='%s' class='fullwidth'>", id->string, dest, mouseover); jsOnEventById("click", id->string, js->string); dyStringFree(&js); dyStringFree(&id); } static void makeButtonRow(struct tempName *singleSubtreeJsonTn, struct tempName *jsonTns[], struct subtreeInfo *subtreeInfoList, int subtreeSize, boolean isFasta, boolean offerCustomTrack) /* Russ's suggestion: row of buttons at the top to view results in GB, Nextstrain, Nextclade. */ { puts("<p>"); puts("<table class='invisalign'><tbody><tr>"); if (offerCustomTrack) @@ -1547,32 +1551,31 @@ puts("</td>"); } // SingleSubtree -- only for Nextstrain, not really applicable to MicrobeTrace if (nextstrainHost()) { puts("<td>"); makeNsSingleTreeButton(singleSubtreeJsonTn); puts("</td>"); } // If both Nextstrain and MicrobeTrace are configured then make a subtree dropdown and buttons // to view in Nextstrain or MicrobeTrace if (nextstrainHost() && microbeTraceHost()) { puts("<td>View subtree</td><td>"); - char *subtreeDropdownName = "subtreeSelect"; - makeSubtreeDropdown(subtreeDropdownName, subtreeInfoList, jsonTns); + char *subtreeDropdownName = makeSubtreeDropdown(subtreeInfoList, jsonTns); puts("</td><td>in</td><td>"); makeSubtreeJumpButton(subtreeDropdownName, "Nextstrain", nextstrainUrlBase(), NEXTSTRAIN_URL_PARAMS, TRUE); puts("<br>"); if (subtreeSize <= MAX_MICROBETRACE_SUBTREE_SIZE) { makeSubtreeJumpButton(subtreeDropdownName, "MicrobeTrace", microbeTraceUrlBase(), MICROBETRACE_URL_PARAMS, FALSE); } else { cgiMakeOptionalButton("disabledMTButton", "MicrobeTrace", TRUE); printf(" (%d samples is too many to view in MicrobeTrace; maximum is %d)", subtreeSize, MAX_MICROBETRACE_SUBTREE_SIZE); } @@ -3378,30 +3381,35 @@ } struct tempName *singleSubtreeJsonTn; AllocVar(singleSubtreeJsonTn); trashDirFile(singleSubtreeJsonTn, "ct", "singleSubtreeAuspice", ".json"); treeToAuspiceJson(results->singleSubtreeInfo, org, refName, geneInfoList, gSeqWin, sampleMetadata, sampleUrls, results->samplePlacements, singleSubtreeJsonTn->forCgi, source); reportTiming(&startTime, "make Auspice JSON"); struct subtreeInfo *subtreeInfoForButtons = results->subtreeInfoList; if (subtreeCount > MAX_SUBTREE_BUTTONS) subtreeInfoForButtons = NULL; char *dbSetting = phyloPlaceRefSetting(org, refName, "db"); if (dbSetting) db = connectIfHub(cart, dbSetting); boolean canDoCustomTracks = (!subtreesOnly && (sameString(db, refName) || isNotEmpty(dbSetting))); + if (canDoCustomTracks) + // Form submits subtree custom tracks to hgTracks + printf("<form action='%s' name='resultsForm_%s' method=%s>\n\n", + hgTracksName(), db, cartUsualString(cart, "formMethod", "POST")); + makeButtonRow(singleSubtreeJsonTn, jsonTns, subtreeInfoForButtons, subtreeSize, isFasta, canDoCustomTracks); printf("<p>If you have metadata you wish to display, click a 'view subtree in " "Nextstrain' button, and then you can drag on a CSV file to " "<a href='"NEXTSTRAIN_DRAG_DROP_DOC"' target=_blank>add it to the tree view</a>." "</p>\n"); puts("<p><em>Note: " "The Nextstrain subtree views, and Download files below, are temporary files and will " "expire within two days. " "Please download the Nextstrain subtree JSON files if you will want to view them " "again in the future. The JSON files can be drag-dropped onto " "<a href='https://auspice.us/' target=_blank>https://auspice.us/</a>." "</em></p>"); struct tempName *tsvTn = NULL, *sTsvTn = NULL; @@ -3517,33 +3525,30 @@ printf(", %s", sln->name); } puts(" (JSON file)</a>"); } puts("</ul>"); if (ctTn != NULL) { // Notify in opposite order of custom track creation. puts("<h3>Custom tracks for viewing in the Genome Browser</h3>"); printf("<p>Added custom track of uploaded samples.</p>\n"); if (subtreeCount > 0 && subtreeCount <= MAX_SUBTREE_CTS) printf("<p>Added %d subtree custom track%s.</p>\n", subtreeCount, (subtreeCount > 1 ? "s" : "")); ctFile = urlFromTn(ctTn); - // Form submits subtree custom tracks to hgTracks - printf("<form action='%s' name='resultsForm_%s' method=%s>\n\n", - hgTracksName(), db, cartUsualString(cart, "formMethod", "POST")); cartSaveSession(cart); cgiMakeHiddenVar("db", db); cgiMakeHiddenVar(CT_CUSTOM_TEXT_VAR, ctFile); if (tl->leftLabelWidthChars < 0 || tl->leftLabelWidthChars == leftLabelWidthDefaultChars) cgiMakeHiddenVar(leftLabelWidthVar, leftLabelWidthForLongNames); cgiMakeButton("submit", "view in Genome Browser"); puts("</form>"); } } } static char *dumpLfToTrashFile(struct lineFile *lf) /* Dump the contents of lf to a trash file (for passing to an executable). Return trash file name. */ { struct tempName tmp;