60c2f9b22552a66b86e65a922da72a6b18fa5d10
angie
  Mon May 23 15:56:43 2011 -0700
Feature #3711 (VCF haplotype clustering): David's suggestion:add mouseover text for the variant used as the center.

diff --git src/hg/hgTracks/vcfTrack.c src/hg/hgTracks/vcfTrack.c
index 420ade8..cf61389 100644
--- src/hg/hgTracks/vcfTrack.c
+++ src/hg/hgTracks/vcfTrack.c
@@ -360,32 +360,41 @@
 if (revCmplDisp)
     {
     reverseComplement(rec->ref, strlen(rec->ref));
     for (i=0;  i < altCount;  i++)
 	reverseComplement(altAlleles[i], strlen(altAlleles[i]));
     }
 
 dyStringPrintf(dy, "%s/%s:%d %s/%s:%d %s/%s:%d", rec->ref, rec->ref, gtRefRefCount,
 	       rec->ref, altAlleles[0], gtRefAltCount,
 	       altAlleles[0], altAlleles[0], gtAltAltCount);
 if (gtOtherCount > 0)
     dyStringPrintf(dy, " other:%d", gtOtherCount);
 return dy->string;
 }
 
+static char *centerPosCartVarName(struct trackDb *tdb)
+// Return track.centerVariantPos setting (may be NULL)
+{
+static char cartVar[512];
+safef(cartVar, sizeof(cartVar), "%s.centerVariantPos", tdb->track);
+return cartVar;
+}
+
 static void drawOneRec(struct vcfRecord *rec, unsigned short *gtHapOrder, int gtHapEnd,
-		       struct track *tg, struct hvGfx *hvg, int xOff, int yOff, int width)
+		       struct track *tg, struct hvGfx *hvg, int xOff, int yOff, int width,
+		       boolean isCenter)
 /* Draw a stack of genotype bars for this record */
 {
 static struct dyString *tmp = NULL;
 if (tmp == NULL)
     tmp = dyStringNew(0);
 char *altAlleles[256];
 int altCount;
 const int lineHeight = tg->lineHeight;
 const int itemHeight = tg->heightPer;
 const double scale = scaleForPixels(width);
 int x1 = round((double)(rec->chromStart-winStart)*scale) + xOff;
 int x2 = round((double)(rec->chromEnd-winStart)*scale) + xOff;
 int w = x2-x1;
 if (w <= 1)
     {
@@ -394,43 +403,65 @@
     }
 int y = yOff;
 dyStringClear(tmp);
 dyStringAppend(tmp, rec->alt);
 altCount = chopCommas(tmp->string, altAlleles);
 int gtHapOrderIx;
 for (gtHapOrderIx = 0;  gtHapOrderIx < gtHapEnd;  gtHapOrderIx++)
     {
     int gtHapIx = gtHapOrder[gtHapOrderIx];
     int hapIx = gtHapIx & 1;
     int gtIx = gtHapIx >>1;
     struct vcfGenotype *gt = &(rec->genotypes[gtIx]);
     y = drawOneHap(gt, hapIx, rec->ref, altAlleles, altCount,
 		   hvg, x1, y, w, itemHeight, lineHeight);
     }
+char *mouseoverText = gtSummaryString(rec, altAlleles, altCount);
+if (isCenter)
+    {
+    // Thick black lines to distinguish this variant:
+    int yBot = yOff + tg->height - 2;
+    hvGfxBox(hvg, x1-3, yOff, 3, tg->height, MG_BLACK);
+    hvGfxBox(hvg, x2+1, yOff, 3, tg->height, MG_BLACK);
+    hvGfxLine(hvg, x1-2, yOff, x2+2, yOff, MG_BLACK);
+    hvGfxLine(hvg, x1-2, yBot, x2+2, yBot, MG_BLACK);
+    // Special mouseover instructions:
+    static struct dyString *dy = NULL;
+    if (dy == NULL)
+	dy = dyStringNew(0);
+    dyStringPrintf(dy, "%s   Haplotypes sorted on ", mouseoverText);
+    char *cartVar = centerPosCartVarName(tg->tdb);
+    char *centerPos = cartOptionalString(cart, cartVar);
+    if (centerPos == NULL)
+	dyStringAppend(dy, "middle variant by default. ");
+    else
+	dyStringAppend(dy, "this variant. ");
+    dyStringAppend(dy, "To anchor sorting to a different variant, click on that variant and "
+		   "then click on the link below the variant name.");
+    mouseoverText = dy->string;
+    }
 mapBoxHgcOrHgGene(hvg, rec->chromStart, rec->chromEnd, x1, yOff, w, tg->height, tg->track,
-		  rec->name, gtSummaryString(rec, altAlleles, altCount),
-		  NULL, TRUE, NULL);
+		  rec->name, mouseoverText, NULL, TRUE, NULL);
 }
 
 static int getCenterVariantIx(struct track *tg, int seqStart, int seqEnd,
 			      struct vcfRecord *records)
 // If the user hasn't specified a local variant/position to use as center,
 // just use the median variant in window.
 {
 int defaultIx = (slCount(records)-1) / 2;
-char cartVar[512];
-safef(cartVar, sizeof(cartVar), "%s.centerVariantPos", tg->tdb->track);
+char *cartVar = centerPosCartVarName(tg->tdb);
 char *centerPos = cartOptionalString(cart, cartVar);
 if (centerPos != NULL)
     {
     char *words[3];
     int wordCount = chopByChar(cloneString(centerPos), ':', words, sizeof(words));
     if (wordCount != 2)
 	errAbort("Cart variable %s format error: expected 'chrom:pos', got %s",
 		 cartVar, centerPos);
     if (sameString(chromName, words[0]))
 	{
 	int pos = sqlUnsigned(words[1]);
 	int winSize = seqEnd - seqStart;
 	if (pos > (seqStart - winSize) && pos < (seqEnd + winSize))
 	    {
 	    int i;
@@ -448,44 +479,37 @@
 static void vcfHapClusterDraw(struct track *tg, int seqStart, int seqEnd,
 			      struct hvGfx *hvg, int xOff, int yOff, int width,
 			      MgFont *font, Color color, enum trackVisibility vis)
 /* Split samples' chromosomes (haplotypes), cluster them by center-weighted
  * alpha similarity, and draw in the order determined by clustering. */
 {
 const struct vcfFile *vcff = tg->extraUiData;
 if (vcff->records == NULL)
     return;
 unsigned short gtHapEnd = 0;
 int ix, centerIx = getCenterVariantIx(tg, seqStart, seqEnd, vcff->records);
 unsigned short *gtHapOrder = clusterChroms(vcff, centerIx, &gtHapEnd);
 struct vcfRecord *rec, *centerRec = NULL;
 for (rec = vcff->records, ix=0;  rec != NULL;  rec = rec->next, ix++)
     {
-    drawOneRec(rec, gtHapOrder, gtHapEnd, tg, hvg, xOff, yOff, width);
     if (ix == centerIx)
 	centerRec = rec;
+    else
+	drawOneRec(rec, gtHapOrder, gtHapEnd, tg, hvg, xOff, yOff, width, FALSE);
     }
 // Draw the center rec on top, outlined with black lines, to make sure it is very visible:
-drawOneRec(centerRec, gtHapOrder, gtHapEnd, tg, hvg, xOff, yOff, width);
-const double scale = scaleForPixels(width);
-int x1 = round((double)(centerRec->chromStart-winStart)*scale) + xOff;
-int x2 = round((double)(centerRec->chromEnd-winStart)*scale) + xOff;
-int yBot = yOff + tg->height - 2;
-hvGfxBox(hvg, x1-4, yOff, 3, tg->height, color);
-hvGfxBox(hvg, x2+2, yOff, 3, tg->height, color);
-hvGfxLine(hvg, x1-2, yOff, x2+2, yOff, MG_BLACK);
-hvGfxLine(hvg, x1-2, yBot, x2+2, yBot, MG_BLACK);
+drawOneRec(centerRec, gtHapOrder, gtHapEnd, tg, hvg, xOff, yOff, width, TRUE);
 }
 
 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. */
 {
 // Should we make it single-height when on chrY?
 const struct vcfFile *vcff = tg->extraUiData;
 if (vcff->records == NULL)
     return 0;
 int ploidy = 2;
 tg->height = ploidy * vcff->genotypeCount * tg->lineHeight;
 return tg->height;
 }