7d992e15b156dca5c6601a989dc33a4bf229ce45
angie
  Thu Aug 20 10:14:08 2020 -0700
Added support for highlightIds setting in VCF+treeFile custom tracks.  refs #25943

diff --git src/hg/hgTracks/vcfTrack.c src/hg/hgTracks/vcfTrack.c
index 7362509..b7cb2e2 100644
--- src/hg/hgTracks/vcfTrack.c
+++ src/hg/hgTracks/vcfTrack.c
@@ -1912,127 +1912,175 @@
     }
 else
     {
     // Leaf (sample)
     double rankStart = leafOrderToHapOrderStart[leafIx];
     double rankEnd = leafOrderToHapOrderStart[leafIx];
     coords->rank = (rankStart + rankEnd) / 2.0;
     leafIx++;
     coords->depth = 0;
     }
 return leafIx;
 }
 
 static void rDrawPhyloTreeInLabelArea(struct phyloTree *node, struct hvGfx *hvg, int x,
                                       int yOff, double pxPerHap, MgFont *font,
-                                      boolean drawRectangle)
+                                      struct hash *highlightSamples)
 /* Recursively draw the tree in the left label area. */
 {
 const int branchW = 4;
 int labelEnd = leftLabelX + leftLabelWidth;
 // Misuse the branch length value as RGB color (if it's the typical small number, will still
 // draw as approximately black):
 unsigned int rgb = node->ident->length;
 Color color = MAKECOLOR_32( ((rgb>>16)&0xff), ((rgb>>8)&0xff), (rgb&0xff) );
 
 if (node->numEdges > 0)
     {
     // Draw each child and a horizontal line to child
     int minY = -1, maxY = 0;
     int ix;
     for (ix = 0;  ix < node->numEdges;  ix++)
         {
         struct phyloTree *child = node->edges[ix];
-        rDrawPhyloTreeInLabelArea(child, hvg, x+branchW, yOff, pxPerHap, font, drawRectangle);
+        rDrawPhyloTreeInLabelArea(child, hvg, x+branchW, yOff, pxPerHap, font, highlightSamples);
         struct nodeCoords *childCoords = child->priv;
         int childY = yOff + ((0.5 + childCoords->rank) * pxPerHap);
         hvGfxLine(hvg, x, childY, x+branchW, childY, color);
         if (minY < 0 || childY < minY)
             minY = childY;
         if (childY > maxY)
             maxY = childY;
         }
     // Draw a vertical line to connect the children
     hvGfxLine(hvg, x, minY, x, maxY, color);
     }
 else
     {
     // Leaf node -- draw a horizontal line, and label if there is space to right of tree
     struct nodeCoords *coords = node->priv;
-    int y = yOff + ((0.5 + coords->rank) * pxPerHap);
-    hvGfxLine(hvg, x, y, x+branchW, y, color);
+    int yLine = yOff + ((0.5 + coords->rank) * pxPerHap);
+    int yBox = yLine - pxPerHap / 2;
+    int yText = yLine - tl.fontHeight / 2;
+    // Dunno why but the default font seems to draw with the baseline at y while the other fonts
+    // draw with the mid line at y.
+    if (sameOk(tl.textSize, "8"))
+        yText += 2;
+    if (highlightSamples && node->ident->name && hashLookup(highlightSamples, node->ident->name))
+        hvGfxBox(hvg, leftLabelX, yBox, leftLabelWidth, pxPerHap,
+                 MAKECOLOR_32(170, 255, 255));
+    hvGfxLine(hvg, x, yLine, x+branchW, yLine, color);
     int textX = x + branchW + 3;
     if (pxPerHap >= tl.fontHeight+1 && textX < labelEnd)
-        hvGfxText(hvg, textX, y, MG_BLACK, font, node->ident->name);
+        hvGfxText(hvg, textX, yText, MG_BLACK, font, node->ident->name);
     }
 }
 
 static void drawPhyloTreeInLabelArea(struct phyloTree *tree, struct hvGfx *hvg, int yOff,
                                      int clipHeight, int gtHapCount,
-                                     MgFont *font, boolean drawRectangle,
-                                     unsigned int *leafOrderToHapOrderStart,
-                                     unsigned int *leafOrderToHapOrderEnd)
+                                     MgFont *font, struct hash *highlightSamples)
 {
 struct hvGfx *hvgLL = (hvgSide != NULL) ? hvgSide : hvg;
 int clipXBak, clipYBak, clipWidthBak, clipHeightBak;
 hvGfxGetClip(hvgLL, &clipXBak, &clipYBak, &clipWidthBak, &clipHeightBak);
 hvGfxUnclip(hvgLL);
 hvGfxSetClip(hvgLL, leftLabelX, yOff, leftLabelWidth, clipHeight);
-// Figure out rank (vertical position) and depth (horizontal position) of every node in tree:
-phyloTreeAddNodeCoords(tree, leafOrderToHapOrderStart, leafOrderToHapOrderEnd, 0);
 // Draw the tree:
 int x = leftLabelX;
 double pxPerHap = (double)clipHeight / gtHapCount;
-rDrawPhyloTreeInLabelArea(tree, hvgLL, x, yOff, pxPerHap, font, drawRectangle);
+rDrawPhyloTreeInLabelArea(tree, hvgLL, x, yOff, pxPerHap, font, highlightSamples);
 // Restore the prior clipping:
 hvGfxUnclip(hvgLL);
 hvGfxSetClip(hvgLL, clipXBak, clipYBak, clipWidthBak, clipHeightBak);
 }
 
+static void rHighlightSampleRows(struct phyloTree *node, struct hvGfx *hvg, int yOff,
+                                 double pxPerHap, struct hash *highlightSamples)
+/* For each leaf node, if it is in highlightSamples then draw a highlight box for it. */
+{
+if (node->numEdges > 0)
+    {
+    int ix;
+    for (ix = 0;  ix < node->numEdges;  ix++)
+        {
+        struct phyloTree *child = node->edges[ix];
+        rHighlightSampleRows(child, hvg, yOff, pxPerHap, highlightSamples);
+        }
+    }
+else
+    {
+    // leaf node; highlight if it's in highlightSamples
+    if (node->ident->name && hashLookup(highlightSamples, node->ident->name))
+        {
+        struct nodeCoords *coords = node->priv;
+        int y = yOff + (coords->rank * pxPerHap);
+        hvGfxBox(hvg, insideX, y, insideWidth, pxPerHap, MAKECOLOR_32(170, 255, 255));
+        }
+    }
+}
+
+struct hash *getHighlightSamples(struct trackDb *tdb)
+/* Return a hash of node IDs to highlight in the phylo tree display, or NULL if none specified. */
+{
+struct hash *highlightSamples = NULL;
+char *setting = cartOrTdbString(cart, tdb, "highlightIds", NULL);
+if (isNotEmpty(setting))
+    {
+    struct slName *list = slNameListFromComma(setting);
+    highlightSamples = hashFromSlNameList(list);
+    }
+return highlightSamples;
+}
+
 static void vcfGtHapTreeFileDraw(struct track *tg, int seqStart, int seqEnd,
                                  struct hvGfx *hvg, int xOff, int yOff, int width,
                                  MgFont *font, Color color, enum trackVisibility vis)
 /* Draw rows in the same fashion as vcfHapClusterDraw, but instead of clustering, use the
  * order in which samples appear in the VCF file. */
 {
 struct vcfFile *vcff = tg->extraUiData;
 enum hapColorMode colorMode;
 struct seqWindow *gSeqWin;
 struct txInfo *txiList;
 if (!vcfHapClusterDrawInit(tg, vcff, hvg, &colorMode, &gSeqWin, &txiList))
     return;
 struct phyloTree *tree = getTreeFromFile(tg->tdb);
 int gtHapCount;
 unsigned int *leafOrderToHapOrderStart, *leafOrderToHapOrderEnd;
 unsigned int *gtHapOrder = gtHapOrderFromTree(vcff, tree,
                                                 &leafOrderToHapOrderStart, &leafOrderToHapOrderEnd,
                                                 &gtHapCount);
+// Figure out rank (vertical position) and depth (horizontal position) of every node in tree:
+phyloTreeAddNodeCoords(tree, leafOrderToHapOrderStart, leafOrderToHapOrderEnd, 0);
+int extraPixel = (colorMode == altOnlyMode || colorMode == functionMode) ? 1 : 0;
+int hapHeight = tg->height - CLIP_PAD - 2*extraPixel;
+struct hash *highlightSamples = getHighlightSamples(tg->tdb);
+if (highlightSamples)
+    {
+    double pxPerHap = (double)hapHeight / gtHapCount;
+    rHighlightSampleRows(tree, hvg, yOff+extraPixel, pxPerHap, highlightSamples);
+    }
 struct vcfRecord *rec;
 for (rec = vcff->records;  rec != NULL;  rec = rec->next)
     {
     enum soTerm funcTerm = soUnknown;
     if (colorMode == functionMode)
         funcTerm = functionForRecord(rec, gSeqWin, txiList);
     drawOneRec(rec, gtHapOrder, gtHapCount, tg, hvg, xOff, yOff, width, FALSE, FALSE,
                colorMode, funcTerm);
     }
-int extraPixel = (colorMode == altOnlyMode || colorMode == functionMode) ? 1 : 0;
-int hapHeight = tg->height - CLIP_PAD - 2*extraPixel;
-char *treeAngle = cartOrTdbString(cart, tg->tdb, VCF_HAP_TREEANGLE_VAR, VCF_DEFAULT_HAP_TREEANGLE);
-boolean drawRectangle = sameString(treeAngle, VCF_HAP_TREEANGLE_RECTANGLE);
-drawPhyloTreeInLabelArea(tree, hvg, yOff+extraPixel, hapHeight, gtHapCount, font,
-                         drawRectangle, leafOrderToHapOrderStart, leafOrderToHapOrderEnd);
+drawPhyloTreeInLabelArea(tree, hvg, yOff+extraPixel, hapHeight, gtHapCount, font, highlightSamples);
 drawSampleTitles(vcff, yOff+extraPixel, hapHeight, gtHapOrder, gtHapCount, tg->track);
 }
 
 static int vcfHapClusterTotalHeight(struct track *tg, enum trackVisibility vis)
 /* Return height of haplotype graph (2 * #samples * lineHeight);
  * 2 because we're assuming diploid genomes here, no XXY, tetraploid etc. */
 {
 const struct vcfFile *vcff = tg->extraUiData;
 if (vcff->records == NULL)
     return 0;
 int ploidy = sameString(chromName, "chrY") ? 1 : 2;
 int simpleHeight = ploidy * vcff->genotypeCount * tg->lineHeight;
 int defaultHeight = min(simpleHeight, VCF_DEFAULT_HAP_HEIGHT);
 char *tdbHeight = trackDbSettingOrDefault(tg->tdb, VCF_HAP_HEIGHT_VAR, NULL);
 if (isNotEmpty(tdbHeight))