3d0cfdfcc3d36bb37899de639d21a1211ba52680 angie Thu Mar 4 17:49:44 2021 -0800 Change 'comprehensive subtree' to 'single subtree' and add mouseovers to 'view in *' buttons. Thx Russ. diff --git src/hg/hgPhyloPlace/phyloPlace.c src/hg/hgPhyloPlace/phyloPlace.c index ea6177b..d547550 100644 --- src/hg/hgPhyloPlace/phyloPlace.c +++ src/hg/hgPhyloPlace/phyloPlace.c @@ -1080,72 +1080,84 @@ { return cfgOption("nextstrainHost"); } static char *nextstrainUrlFromTn(struct tempName *jsonTn) /* Return a link to Nextstrain to view an annotated subtree. */ { char *jsonUrlForNextstrain = urlFromTn(jsonTn); char *protocol = strstr(jsonUrlForNextstrain, "://"); if (protocol) jsonUrlForNextstrain = protocol + strlen("://"); struct dyString *dy = dyStringCreate("%s/fetch/%s", nextstrainHost(), jsonUrlForNextstrain); return dyStringCannibalize(&dy); } -static void makeNextstrainButton(char *id, struct tempName *tn, char *label) +static void makeNextstrainButton(char *id, struct tempName *tn, char *label, char *mouseover) /* Make a button to view an auspice JSON file in Nextstrain. */ { char *nextstrainUrl = nextstrainUrlFromTn(tn); struct dyString *js = dyStringCreate("window.open('%s');", nextstrainUrl); -cgiMakeOnClickButton(id, js->string, label); +cgiMakeOnClickButtonWithMsg(id, js->string, label, mouseover); dyStringFree(&js); freeMem(nextstrainUrl); } -static void makeNextstrainButtonN(char *idBase, int ix, struct tempName *jsonTns[]) +static void makeNextstrainButtonN(char *idBase, int ix, int userSampleCount, int subtreeSize, + struct tempName *jsonTns[]) /* Make a button to view one subtree in Nextstrain. idBase is a short string and * ix is 0-based subtree number. */ { char buttonId[256]; safef(buttonId, sizeof buttonId, "%s%d", idBase, ix+1); char buttonLabel[256]; safef(buttonLabel, sizeof buttonLabel, "view subtree %d in Nextstrain", ix+1); -makeNextstrainButton(buttonId, jsonTns[ix], buttonLabel); +struct dyString *dyMo = dyStringCreate("view subtree %d with %d of your sequences and %d other " + "sequences from the phylogenetic tree for context", + ix+1, userSampleCount, subtreeSize - userSampleCount); +makeNextstrainButton(buttonId, jsonTns[ix], buttonLabel, dyMo->string); +dyStringFree(&dyMo); } static void makeNsSingleTreeButton(struct tempName *tn) /* Make a button to view single subtree (with all uploaded samples) in Nextstrain. */ { -makeNextstrainButton("viewNextstrainSingleSubtree", tn, "view comprehensive subtree in Nextstrain"); +makeNextstrainButton("viewNextstrainSingleSubtree", tn, "view single subtree in Nextstrain", + "view one subtree that includes all of your uploaded sequences plus " + SINGLE_SUBTREE_SIZE" randomly selected sequences from the phylogenetic " + "tree for context"); } static void makeButtonRow(struct tempName *singleSubtreeJsonTn, struct tempName *jsonTns[], - int subtreeCount, boolean isFasta) + struct subtreeInfo *subtreeInfoList, int subtreeSize, boolean isFasta) /* Russ's suggestion: row of buttons at the top to view results in GB, Nextstrain, Nextclade. */ { puts("<p>"); -cgiMakeButton("submit", "view in Genome Browser"); +cgiMakeButtonWithMsg("submit", "view in Genome Browser", + "view your uploaded sequences, their phylogenetic relationship and their " + "mutations along with many other datasets available in the Genome Browser"); if (nextstrainHost()) { printf(" "); makeNsSingleTreeButton(singleSubtreeJsonTn); + struct subtreeInfo *ti; int ix; - for (ix = 0; ix < subtreeCount; ix++) + for (ix = 0, ti = subtreeInfoList; ti != NULL; ti = ti->next, ix++) { + int userSampleCount = slCount(ti->subtreeUserSampleIds); printf(" "); - makeNextstrainButtonN("viewNextstrainTopRow", ix, jsonTns); + makeNextstrainButtonN("viewNextstrainTopRow", ix, userSampleCount, subtreeSize, jsonTns); } } if (0 && isFasta) { printf(" "); struct dyString *js = dyStringCreate("window.open('https://master.clades.nextstrain.org/" "?input-fasta=%s');", "needATn"); //#*** TODO: save FASTA to file cgiMakeOnClickButton("viewNextclade", js->string, "view sequences in Nextclade"); } puts("</p>"); } #define TOOLTIP(text) " <div class='tooltip'>(?)<span class='tooltiptext'>" text "</span></div>" @@ -2187,34 +2199,34 @@ treeToAuspiceJson(results->singleSubtreeInfo, db, geneInfoList, gSeqWin, sampleMetadata, singleSubtreeJsonTn->forCgi, source); struct tempName *jsonTns[subtreeCount]; struct subtreeInfo *ti; int ix; for (ix = 0, ti = results->subtreeInfoList; ti != NULL; ti = ti->next, ix++) { AllocVar(jsonTns[ix]); char subtreeName[512]; safef(subtreeName, sizeof(subtreeName), "subtreeAuspice%d", ix+1); trashDirFile(jsonTns[ix], "ct", subtreeName, ".json"); treeToAuspiceJson(ti, db, geneInfoList, gSeqWin, sampleMetadata, jsonTns[ix]->forCgi, source); } puts("<p></p>"); - int subtreeButtonCount = subtreeCount; + struct subtreeInfo *subtreeInfoForButtons = results->subtreeInfoList; if (seqCount > MAX_SEQ_DETAILS || subtreeCount > MAX_SUBTREE_BUTTONS) - subtreeButtonCount = 0; - makeButtonRow(singleSubtreeJsonTn, jsonTns, subtreeButtonCount, isFasta); + subtreeInfoForButtons = NULL; + makeButtonRow(singleSubtreeJsonTn, jsonTns, subtreeInfoForButtons, subtreeSize, isFasta); 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"); // Make custom tracks for uploaded samples and subtree(s). struct phyloTree *sampleTree = NULL; struct tempName *ctTn = writeCustomTracks(vcfTn, results, sampleIds, bigTree->tree, source, fontHeight, &sampleTree, &startTime); // Make a sample summary TSV file and accumulate S gene changes struct hash *spikeChanges = hashNew(0); struct tempName *tsvTn = writeTsvSummary(results, sampleTree, sampleIds, seqInfoList, geneInfoList, gSeqWin, spikeChanges, &startTime); struct tempName *sTsvTn = writeSpikeChangeSummary(spikeChanges, slCount(sampleIds)); @@ -2225,31 +2237,32 @@ if (seqCount <= MAX_SEQ_DETAILS) { summarizeSequences(seqInfoList, isFasta, results, jsonTns, sampleMetadata, bigTree, refGenome); reportTiming(&startTime, "write summary table (including reading in lineages)"); for (ix = 0, ti = results->subtreeInfoList; ti != NULL; ti = ti->next, ix++) { int subtreeUserSampleCount = slCount(ti->subtreeUserSampleIds); printf("<h3>Subtree %d: ", ix+1); if (subtreeUserSampleCount > 1) printf("%d related samples", subtreeUserSampleCount); else if (subtreeCount > 1) printf("Unrelated sample"); printf("</h3>\n"); - makeNextstrainButtonN("viewNextstrainSub", ix, jsonTns); + makeNextstrainButtonN("viewNextstrainSub", ix, subtreeUserSampleCount, subtreeSize, + jsonTns); puts("<br>"); // Make a sub-subtree with only user samples for display: struct phyloTree *subtree = phyloOpenTree(ti->subtreeTn->forCgi); subtree = phyloPruneToIds(subtree, ti->subtreeUserSampleIds); describeSamplePlacements(ti->subtreeUserSampleIds, results->samplePlacements, subtree, sampleMetadata, bigTree, source); } reportTiming(&startTime, "describe placements"); } else printf("<p>(Skipping details and subtrees; " "you uploaded %d sequences, and details/subtrees are shown only when " "you upload at most %d sequences.)</p>\n", seqCount, MAX_SEQ_DETAILS);