b818160961573cd7b8902303ca4dc532d1366513
max
  Mon Apr 29 11:14:47 2024 -0700
adding name filter and color track options to hgTrackUi, refs #20460

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index 5d5bd77..9ed8cd6 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -1798,30 +1798,69 @@
     return GLYPH_INV_TRIANGLE;
 if (sameWordOk(glyphStr, GLYPH_STRING_SQUARE))
     return GLYPH_SQUARE;
 if (sameWordOk(glyphStr, GLYPH_STRING_DIAMOND))
     return GLYPH_DIAMOND;
 if (sameWordOk(glyphStr, GLYPH_STRING_OCTAGON))
     return GLYPH_OCTAGON;
 if (sameWordOk(glyphStr, GLYPH_STRING_STAR))
     return GLYPH_STAR;
 if (sameWordOk(glyphStr, GLYPH_STRING_PENTAGRAM))
     return GLYPH_PENTAGRAM;
 
 return GLYPH_CIRCLE;
 }
 
+void filterItemsOnNames(struct track *tg)
+/* Only keep items with a name in the .nameFilter cart var. 
+ * Not using filterItems(), because filterItems has no state at all. */
+{
+char varName[SMALLBUF];
+safef(varName, sizeof(varName), "%s.nameFilter", tg->tdb->track);
+char *nameFilterStr = cartNonemptyString(cart, varName);
+
+if (nameFilterStr==NULL)
+    return;
+
+struct slName *names = slNameListFromString(nameFilterStr, ',');
+struct hash *nameHash = hashFromSlNameList(names);
+
+struct slList *newList = NULL, *el, *next;
+for (el = tg->items; el != NULL; el = next)
+    {
+    next = el->next;
+    struct linkedFeatures *lf = (struct linkedFeatures*)el;
+    char *name = lf->name;
+    if (name && hashLookup(nameHash, name))
+	slAddHead(&newList, el);
+}
+tg->items = newList;
+
+char *suf = "";
+int nameCount = slCount(names);
+if (nameCount > 1)
+    suf = "s";
+
+char buf[SMALLBUF];
+safef(buf, sizeof(buf), " (manually filtered to show only %d accession%s)", nameCount, suf);
+char *oldLabel = tg->longLabel;
+tg->longLabel = catTwoStrings(tg->longLabel, buf);
+freez(&oldLabel);
+
+slFreeList(&names);
+hashFree(&nameHash);
+}
 
 void filterItems(struct track *tg, boolean (*filter)(struct track *tg, void *item),
                 char *filterType)
 /* Filter out items from track->itemList. */
 {
 struct slList *newList = NULL, *oldList = NULL, *el, *next;
 boolean exclude = FALSE;
 boolean color = FALSE;
 enum trackVisibility vis = tvHide;
 
 if (sameWord(filterType, "none"))
     return;
 
 if (sameWord(filterType, "include"))
     exclude = FALSE;
@@ -4137,45 +4176,48 @@
 /*if we are zoomed in far enough, look to see if we are coloring
   by codon, and setup if so.*/
 if (vis != tvDense)
     {
     drawOpt = baseColorDrawSetup(hvg, tg, lf, &qSeq, &qOffset, &psl);
     if (drawOpt > baseColorDrawOff)
 	exonArrows = FALSE;
     }
 if ((tg->tdb != NULL) && (vis != tvDense))
     intronGap = atoi(trackDbSettingOrDefault(tg->tdb, "intronGap", "0"));
 
 lfColors(tg, lf, hvg, &color, &bColor);
 if (vis == tvDense && trackDbSetting(tg->tdb, EXP_COLOR_DENSE))
     color = saveColor;
 
+color = colorFromCart(tg, color);
+
+struct genePred *gp = NULL;
+if (startsWith("genePred", tg->tdb->type) || startsWith("bigGenePred", tg->tdb->type))
+    gp = (struct genePred *)(lf->original);
+
 boolean baseColorNeedsCodons = (drawOpt == baseColorDrawItemCodons ||
 				drawOpt == baseColorDrawDiffCodons ||
 				drawOpt == baseColorDrawGenomicCodons);
 if (psl && baseColorNeedsCodons)
     {
     boolean isXeno = ((tg->subType == lfSubXeno) || (tg->subType == lfSubChain) ||
 		      startsWith("mrnaBla", tg->table));
     int sizeMul = pslIsProtein(psl) ? 3 : 1;
     lf->codons = baseColorCodonsFromPsl(lf, psl, sizeMul, isXeno, maxShade, drawOpt, tg);
     }
 else if (drawOpt > baseColorDrawOff)
     {
-    struct genePred *gp = NULL;
-    if (startsWith("genePred", tg->tdb->type) || startsWith("bigGenePred", tg->tdb->type))
-	gp = (struct genePred *)(lf->original);
     if (gp && gp->cdsStart != gp->cdsEnd)
         lf->codons = baseColorCodonsFromGenePred(lf, gp, (drawOpt != baseColorDrawDiffCodons), cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, CODON_NUMBERING_SUFFIX, TRUE));
     }
 if (psl && drawOpt == baseColorDrawCds && !zoomedToCdsColorLevel)
     baseColorSetCdsBounds(lf, psl, tg);
 
 tallStart = lf->tallStart;
 tallEnd = lf->tallEnd;
 if ((tallStart == 0 && tallEnd == 0) && lf->start != 0 && !sameWord(tg->table, "jaxQTL3"))
     {
     // sometimes a bed <8 will get passed off as a bed 8, tsk tsk
     tallStart = lf->start;
     tallEnd   = lf->end;
     }
 int ourStart = lf->start;
@@ -5228,30 +5270,32 @@
 	    }
 #endif//ndef IMAGEv2_SHORT_MAPITEMS
         y += tg->lineHeight;
         }
     }
 }
 
 void genericDrawItems(struct track *tg, int seqStart, int seqEnd,
                       struct hvGfx *hvg, int xOff, int yOff, int width,
                       MgFont *font, Color color, enum trackVisibility vis)
 /* Draw generic item list.  Features must be fixed height
  * and tg->drawItemAt has to be filled in. */
 {
 withIndividualLabels = TRUE;  // set this back to default just in case someone left it false (I'm looking at you pgSnp)
 
+color = colorFromCart(tg, color);
+
 if (tg->mapItem == NULL)
     tg->mapItem = genericMapItem;
 if (vis != tvDense && baseColorCanDraw(tg))
     baseColorInitTrack(hvg, tg);
 boolean doWiggle = checkIfWiggling(cart, tg);
 if (doWiggle)
     {
     genericDrawItemsWiggle(tg, seqStart, seqEnd, hvg, xOff, yOff, width,
 				   font, color, vis);
     }
 else if (vis == tvPack || vis == tvSquish || (vis == tvFull && isTypeBedLike(tg)))
     {
     genericDrawItemsPackSquish(tg, seqStart, seqEnd, hvg, xOff, yOff, width,
                                font, color, vis);
     }
@@ -5264,30 +5308,32 @@
                               struct hvGfx *hvg, int xOff, int yOff, int width,
                               MgFont *font, Color color, enum trackVisibility vis)
 /* Draw linked features items. */
 {
 if (vis == tvDense && tg->colorShades)
     slSort(&tg->items, cmpLfsWhiteToBlack);
 genericDrawItems(tg, seqStart, seqEnd, hvg, xOff, yOff, width,
 	font, color, vis);
 }
 
 void linkedFeaturesDraw(struct track *tg, int seqStart, int seqEnd,
                         struct hvGfx *hvg, int xOff, int yOff, int width,
                         MgFont *font, Color color, enum trackVisibility vis)
 /* Draw linked features items. */
 {
+color = colorFromCart(tg, color);
+
 if (tg->items == NULL && vis == tvDense && canDrawBigBedDense(tg))
     {
     bigBedDrawDense(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color);
     }
 else
     {
     if (vis == tvDense && tg->colorShades)
 	slSort(&tg->items, cmpLfWhiteToBlack);
     genericDrawItems(tg, seqStart, seqEnd, hvg, xOff, yOff, width,
 	    font, color, vis);
     }
 
 // put up the color key for the gnomAD pLI track
 if (startsWith("pliBy", tg->track))
     doPliColors = TRUE;
@@ -6899,30 +6945,32 @@
 char *bigGenePred = trackDbSetting(tdb, "bigGeneDataUrl");
 struct udcFile *file;
 boolean isBigGenePred = FALSE;
 
 if ((bigGenePred != NULL) && ((file = udcFileMayOpen(bigGenePred, udcDefaultDir())) != NULL))
     {
     isBigGenePred = TRUE;
     udcFileClose(&file);
     loadKnownBigGenePred(tg, isGencode);
     }
 else if (!isGencode)
     loadGenePredWithName2(tg);
 else
     loadKnownGencode(tg);
 
+filterItemsOnNames(tg);
+
 char varName[SMALLBUF];
 safef(varName, sizeof(varName), "%s.show.noncoding", tdb->track);
 boolean showNoncoding = cartUsualBoolean(cart, varName, TRUE);
 safef(varName, sizeof(varName), "%s.show.spliceVariants", tdb->track);
 boolean showSpliceVariants = cartUsualBoolean(cart, varName, TRUE);
 if (!showNoncoding)
     tg->items = stripShortLinkedFeatures(tg->items);
 if (!showSpliceVariants)
     {
     if (isBigGenePred)
         {
         tg->items = stripLinkedFeaturesWithoutBitInScore(tg->items,  BIT_CANON);
         }
     else
         {