eeac40956b3dd6611f58aeb847ff5c404d3ce883 angie Fri Dec 1 09:05:41 2023 -0800 Support trees whose reference/root is not from a db or hub, but rather a custom .2bit file. This means that the selected pathogen may or may not also be a db/hub, so the selection interacts with the db cart variable but does not always match it. Also, in phyloPlace.c, update RSV metadata column headers (RGCC lineages replace Ramaekers 2020 clades). diff --git src/hg/hgPhyloPlace/hgPhyloPlace.c src/hg/hgPhyloPlace/hgPhyloPlace.c index 4dc7bca..ec9739c 100644 --- src/hg/hgPhyloPlace/hgPhyloPlace.c +++ src/hg/hgPhyloPlace/hgPhyloPlace.c @@ -67,105 +67,114 @@ else if (isNotEmpty(fileBinaryCoords)) { fprintf(stderr, "%s=%s fileBinaryCoords=%s\n", cartVar, fileName, fileBinaryCoords); char *binInfo = cloneString(fileBinaryCoords); char *words[2]; char *mem; unsigned long size; chopByWhite(binInfo, words, ArraySize(words)); mem = (char *)sqlUnsignedLong(words[0]); size = sqlUnsignedLong(words[1]); lf = lineFileDecompressMem(TRUE, mem, size); } return lf; } -static char *labelForDb(char *db) -/* The assembly hub name is just the accession; make a special label for hMPXV. Otherwise just - * return hGenome(db). */ +static char *labelForDb(char *db, boolean addDescription) +/* If config defines a user-friendly name then return that; otherwise return hGenome(db). + * If addDescription is set and config defines a description then tack that on. */ { char *label = phyloPlaceDbSetting(db, "name"); if (isEmpty(label)) label = hGenome(db); +if (addDescription) + { + char *desc = phyloPlaceDbSetting(db, "description"); + if (isNotEmpty(desc)) + { + struct dyString *dy = dyStringCreate("%s %s", label, desc); + label = dyStringCannibalize(&dy); + } + } return label; } static int labelCmp(const void *va, const void *vb) /* Compare two slPairs on their string values -- but treat SARS-CoV-2 as more important. */ { const struct slPair *a = *((struct slPair **)va); const struct slPair *b = *((struct slPair **)vb); if (sameString((char *)(a->val), "SARS-CoV-2")) return -1; else if (sameString((char *)(b->val), "SARS-CoV-2")) return 1; return strcmp((char *)(a->val), (char *)(b->val)); } static struct slName *sortByLabel(struct slName *dbList) /* Return a newly allocated version of dbList, sorted by labelForDb value -- but favor SARS-CoV-2. */ { struct slPair *dbLabelList = NULL; struct slName *sln; for (sln = dbList; sln != NULL; sln = sln->next) - slPairAdd(&dbLabelList, sln->name, cloneString(labelForDb(sln->name))); + slPairAdd(&dbLabelList, sln->name, cloneString(labelForDb(sln->name, TRUE))); slSort(&dbLabelList, labelCmp); struct slName *newList = NULL; struct slPair *slp; for (slp = dbLabelList; slp != NULL; slp = slp->next) slAddHead(&newList, slNameNew(slp->name)); slReverse(&newList); slPairFreeValsAndList(&dbLabelList); return newList; } static void selectDb(char **pDb, char **pLabel) /* Search for assembly config.ra files in hgPhyloPlaceData. If there is more than one * supported assembly, then make a menu / select input for supported assemblies; * reload the page on change. */ { struct slName *supportedDbs = sortByLabel(phyloPlaceDbList(cart)); if (supportedDbs == NULL) errAbort("Sorry, this server is not configured to perform phylogenetic placement."); if (!slNameInList(supportedDbs, *pDb)) { *pDb = cloneString(supportedDbs->name); } -*pLabel = labelForDb(*pDb); +*pLabel = labelForDb(*pDb, FALSE); +char *selectVar = "hpp_ref"; int supportedDbCount = slCount(supportedDbs); if (supportedDbCount > 1) { char *labels[supportedDbCount]; char *values[supportedDbCount]; struct slName *sDb; int i; for (sDb = supportedDbs, i = 0; i < supportedDbCount; sDb = sDb->next, i++) { values[i] = sDb->name; - labels[i] = labelForDb(values[i]); + labels[i] = labelForDb(values[i], TRUE); } - char *selectVar = "db"; struct dyString *dy = jsOnChangeStart(); jsDropDownCarryOver(dy, selectVar); char *js = jsOnChangeEnd(&dy); puts("<p>Choose your pathogen: "); cgiMakeDropListFull(selectVar, labels, values, supportedDbCount, *pDb, "change", js); puts("</p>"); } else - cgiMakeHiddenVar("db", *pDb); + cgiMakeHiddenVar(selectVar, *pDb); slNameFreeList(&supportedDbs); } static void newPageStartStuff() { // Copied these from hgGtexTrackSettings.c which says "// NOTE: This will likely go to web.c". puts("<link rel='stylesheet' href='../style/gb.css'>"); puts("<link rel='stylesheet' href='../style/hgGtexTrackSettings.css'>"); //#*** TODO: move this out to a CSS (hardcoding for now because we're doing a standalone push //#*** independent of the release cycle). puts("<style>\n" "#warnBox {\n" " border: 3px ridge DarkRed;\n" " width:640px;\n" @@ -441,98 +450,110 @@ ); puts("</div>"); puts("</div>"); puts("</form>"); } static void mainPage(char *db) { // Start web page with new-style header webStartGbNoBanner(cart, db, "UShER: Upload"); jsInit(); jsIncludeFile("jquery.js", NULL); jsIncludeFile("ajax.js", NULL); newPageStartStuff(); -// Hidden form for reloading page when db select is changed -static char *saveVars[] = { "db" }; +// Hidden form for reloading page when hpp_ref select is changed +static char *saveVars[] = { "hpp_ref" }; jsCreateHiddenForm(cart, cgiScriptName(), saveVars, ArraySize(saveVars)); puts("<div class='row'>" " <div class='row gbSectionBannerLarge'>\n" " <div class='col-md-11'>UShER: Ultrafast Sample placement on Existing tRee</div>\n" " <div class='col-md-1'></div>\n" " </div>\n" "</div>\n" "<div class='row'>\n"); if (hgPhyloPlaceEnabled()) { inputForm(db); } else { puts(" <div class='gbControl col-md-12'>"); puts(" Sorry, this server is not configured to perform phylogenetic placement."); puts(" </div>"); } puts("</div>\n"); newPageEndStuff(); } -static void resultsPage(char *db, struct lineFile *lf) +static void resultsPage(char *db, char *refName, struct lineFile *lf) /* QC the user's uploaded sequence(s) or VCF; if input looks valid then run usher * and display results. */ { +// If refName is a real database or hub then set db to refName. +if (hDbExists(refName)) + db = refName; +else + { + // Not a db -- see if it's a hub that is already connected: + struct trackHubGenome *hubGenome = trackHubGetGenomeUndecorated(db); + if (hubGenome != NULL) + db = refName; + // Otherwise we're counting on the config to specify a .2bit file and we won't make CTs. + } webStartGbNoBanner(cart, db, "UShER: Results"); jsIncludeFile("jquery.js", NULL); jsIncludeFile("ajax.js", NULL); newPageStartStuff(); if (issueBotWarning) { char *ip = getenv("REMOTE_ADDR"); botDelayMessage(ip, botDelayMillis); } // Allow 10 minutes for big sets of sequences lazarusLives(15 * 60); puts("<div class='row'>" " <div class='row gbSectionBannerLarge'>\n" " <div class='col-md-11'>UShER: Ultrafast Sample placement on Existing tRee</div>\n" " <div class='col-md-1'></div>\n" " </div>\n" "</div>\n" "<div class='row'>\n"); // Form submits subtree custom tracks to hgTracks printf("<form action='%s' name='resultsForm' method=%s>\n\n", hgTracksName(), cartUsualString(cart, "formMethod", "POST")); cartSaveSession(cart); +cgiMakeHiddenVar("db", db); 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, + char *ctFile = phyloPlaceSamples(lf, db, refName, phyloPlaceTree, measureTiming, subtreeSize, 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 if (! success) { puts("<p></p>"); puts(" </div>"); puts("</form>"); @@ -683,70 +704,74 @@ errAbort("Usher server mode not configured for db=%s", db); } else errAbort("Bad request"); popWarnHandler(); popAbortHandler(); } static void doMiddle(struct cart *theCart) /* Set up globals and make web page */ { cart = theCart; char *db = NULL, *genome = NULL; // Get the current db from the cart getDbAndGenome(cart, &db, &genome, oldVars); +// The currently selected pathogen reference sequence may or may not be a db/hub. +char *refName = cartOptionalString(cart, "hpp_ref"); +if (isEmpty(refName)) + refName = cloneString(db); int timeout = cartUsualInt(cart, "udcTimeout", 300); if (udcCacheTimeout() < timeout) udcSetCacheTimeout(timeout); knetUdcInstall(); measureTiming = cartUsualBoolean(cart, "measureTiming", measureTiming); char *submitLabel = cgiOptionalString("submit"); char *newExampleButton = cgiOptionalString("exampleButton"); if ((submitLabel && sameString(submitLabel, "try example")) || (newExampleButton && sameString(newExampleButton, "Upload Example File"))) { - char *exampleFile = phyloPlaceDbSettingPath(db, "exampleFile"); + char *exampleFile = phyloPlaceDbSettingPath(refName, "exampleFile"); struct lineFile *lf = lineFileOpen(exampleFile, TRUE); - resultsPage(db, lf); + resultsPage(db, refName, lf); } else if (cgiOptionalString(remoteFileVar)) { char *url = cgiString(remoteFileVar); struct lineFile *lf = netLineFileOpen(url); - resultsPage(db, lf); + resultsPage(db, refName, lf); } else if (isNotEmpty(trimSpaces(cgiOptionalString(pastedIdVar)))) { char *pastedIds = cgiString(pastedIdVar); struct lineFile *lf = lineFileOnString("pasted names/IDs", TRUE, pastedIds); - resultsPage(db, lf); + resultsPage(db, refName, lf); } else if (cgiOptionalString(seqFileVar) || cgiOptionalString(seqFileVar "__filename")) { struct lineFile *lf = lineFileFromFileInput(cart, seqFileVar); - resultsPage(db, lf); + resultsPage(db, refName, lf); } else if (isNotEmpty(cgiOptionalString(serverCommandVar))) { - sendServerCommand(db); + sendServerCommand(refName); } else - mainPage(db); + mainPage(refName); } #define LD_LIBRARY_PATH "LD_LIBRARY_PATH" static void addLdLibraryPath() /* usher requires a tbb lib that is not in the yum package tbb-devel, so for now * I'm adding the .so files to hgPhyloPlaceData. Set environment variable LD_LIBRARY_PATH * to pick them up from there. */ { char *oldValue = getenv(LD_LIBRARY_PATH); struct dyString *dy = dyStringNew(0); if (startsWith("/", PHYLOPLACE_DATA_DIR)) dyStringAppend(dy, PHYLOPLACE_DATA_DIR); else {