705420e703b067fbcad43ab67ed3e131552e7ac8 angie Wed Apr 24 14:23:03 2024 -0700 Pathogen drop-down choices can now be groups of references/trees, for example 'Dengue (types 1 - 4)' instead of a separate choice for each type. Instead of config.ra, each group has an organism.ra and subdirectories named after reference accessions that contain reference.ra files. nextclade sort is used to match the user's uploaded sequences against available references for the selected pathogen. SARS-CoV-2, M. tuberculosis and hMPXV still have only one reference and still use config.ra, but RSV, Dengue and Influenza will become groups. Presentation is still kinda rough, just a loop on the original results output. The server commands part needs testing and will not work yet for groups (currently used only for SARS-CoV-2). diff --git src/hg/hgPhyloPlace/hgPhyloPlace.c src/hg/hgPhyloPlace/hgPhyloPlace.c index ec9739c..4f96671 100644 --- src/hg/hgPhyloPlace/hgPhyloPlace.c +++ src/hg/hgPhyloPlace/hgPhyloPlace.c @@ -1,53 +1,53 @@ /* hgPhyloPlace - Upload SARS-CoV-2 or MPXV sequence for placement in phylo tree. */ -/* Copyright (C) 2020-2022 The Regents of the University of California */ +/* Copyright (C) 2020-2024 The Regents of the University of California */ #include "common.h" #include "botDelay.h" #include "cart.h" #include "cgiApoptosis.h" #include "cheapcgi.h" #include "hCommon.h" #include "hash.h" #include "hgConfig.h" #include "htmshell.h" #include "hui.h" #include "jsHelper.h" #include "knetUdc.h" #include "linefile.h" #include "md5.h" #include "net.h" #include "options.h" #include "phyloPlace.h" #include "portable.h" #include "trackLayout.h" #include "udc.h" #include "web.h" #include "wikiLink.h" /* Global Variables */ struct cart *cart = NULL; // CGI and other variables struct hash *oldVars = NULL; // Old contents of cart before it was updated by CGI boolean measureTiming = FALSE; // Print out how long things take -char *leftLabelWidthForLongNames = "55";// Leave plenty of room for tree and long virus strain names /* for botDelay call, 10 second for warning, 20 second for immediate exit */ #define delayFraction 0.25 static boolean issueBotWarning = FALSE; static long enteredMainTime = 0; +#define orgVar "hgpp_org" #define seqFileVar "sarsCoV2File" #define pastedIdVar "namesOrIds" #define remoteFileVar "remoteFile" #define serverCommandVar "hgpp_serverCommand" #define serverCommentVar "hgpp_serverComment" #define serverPlainVar "hgpp_serverPlain" #define serverSaltyVar "hgpp_serverSalty" static struct lineFile *lineFileFromFileInput(struct cart *cart, char *fileVar) /* Return a lineFile on data from an uploaded file with cart variable name fileVar. * If the file is binary, attempt to decompress it. Return NULL if no data are found * or if there is a problem decompressing binary data. If retFileName is not NULL */ { struct lineFile *lf = NULL; // Depending on whether the file is plain text or binary, different cart variables are present. @@ -67,115 +67,68 @@ 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, 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, 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; +static void selectOrg(char **pOrg, char **pLabel) +/* Search for config files in hgPhyloPlaceData. If there is more than one + * supported organism, then make a menu / select input for supported organisms; * reload the page on change. */ { -struct slName *supportedDbs = sortByLabel(phyloPlaceDbList(cart)); -if (supportedDbs == NULL) +struct slPair *orgLabelList = phyloPlaceOrgList(cart); +if (orgLabelList == NULL) errAbort("Sorry, this server is not configured to perform phylogenetic placement."); -if (!slNameInList(supportedDbs, *pDb)) +if (!slPairFind(orgLabelList, *pOrg)) { - *pDb = cloneString(supportedDbs->name); + *pOrg = cloneString(orgLabelList->name); } -*pLabel = labelForDb(*pDb, FALSE); -char *selectVar = "hpp_ref"; -int supportedDbCount = slCount(supportedDbs); -if (supportedDbCount > 1) +*pLabel = phyloPlaceOrgSetting(*pOrg, "name"); +if (isEmpty(*pLabel)) + *pLabel = *pOrg; +char *selectVar = orgVar; +int orgCount = slCount(orgLabelList); +if (orgCount > 1) { - char *labels[supportedDbCount]; - char *values[supportedDbCount]; - struct slName *sDb; + char *labels[orgCount]; + char *values[orgCount]; + struct slPair *orgLabel; int i; - for (sDb = supportedDbs, i = 0; i < supportedDbCount; sDb = sDb->next, i++) + for (orgLabel = orgLabelList, i = 0; i < orgCount; orgLabel = orgLabel->next, i++) { - values[i] = sDb->name; - labels[i] = labelForDb(values[i], TRUE); + values[i] = orgLabel->name; + labels[i] = orgLabel->val; } struct dyString *dy = jsOnChangeStart(); jsDropDownCarryOver(dy, selectVar); char *js = jsOnChangeEnd(&dy); puts("
Choose your pathogen: "); - cgiMakeDropListFull(selectVar, labels, values, supportedDbCount, *pDb, "change", js); + cgiMakeDropListFull(selectVar, labels, values, orgCount, *pOrg, "change", js); puts("
"); } else - cgiMakeHiddenVar(selectVar, *pDb); -slNameFreeList(&supportedDbs); + cgiMakeHiddenVar(selectVar, *pOrg); +slPairFreeList(&orgLabelList); } static void newPageStartStuff() { // Copied these from hgGtexTrackSettings.c which says "// NOTE: This will likely go to web.c". puts(""); puts(""); //#*** TODO: move this out to a CSS (hardcoding for now because we're doing a standalone push //#*** independent of the release cycle). puts("