2e5a07597bfa95dedb669fef2a5e2b8048f2c644
angie
  Mon Dec 5 08:08:23 2011 -0800
Feature #3711 (VCF haplo-sorting display): Implemented Richard Durbin'ssuggestions as new defaults:

1. Instead of ref=blue, alt=red, simply ignore ref and draw only alt, in black.
Draw top & bottom bounds of variants in extra pixel rows.

2. Draw the tree using open triangles instead of open rectangles.

diff --git src/hg/hgTracks/vcfTrack.c src/hg/hgTracks/vcfTrack.c
index 7b2d5dc..5456212 100644
--- src/hg/hgTracks/vcfTrack.c
+++ src/hg/hgTracks/vcfTrack.c
@@ -1,23 +1,24 @@
 /* vcfTrack -- handlers for Variant Call Format data. */
 
 #include "common.h"
 #include "bigWarn.h"
 #include "dystring.h"
 #include "errCatch.h"
 #include "hacTree.h"
 #include "hdb.h"
+#include "hgColors.h"
 #include "hgTracks.h"
 #include "pgSnp.h"
 #include "trashDir.h"
 #include "vcf.h"
 #include "vcfUi.h"
 #if (defined USE_TABIX && defined KNETFILE_HOOKS)
 #include "knetUdc.h"
 #include "udc.h"
 #endif//def USE_TABIX && KNETFILE_HOOKS
 
 #ifdef USE_TABIX
 
 static boolean getMinQual(struct trackDb *tdb, double *retMinQual)
 /* Return TRUE and set retMinQual if cart contains minimum QUAL filter */
 {
@@ -503,130 +504,198 @@
     }
 dyStringPrintf(dy, "%s/%s:%d %s/%s:%d %s/%s:%d", rec->alleles[0], rec->alleles[0], gtRefRefCount,
 	       rec->alleles[0], rec->alleles[1], gtRefAltCount,
 	       rec->alleles[1], rec->alleles[1], gtAltAltCount);
 if (gtOtherCount > 0)
     dyStringPrintf(dy, " other:%d", gtOtherCount);
 // Restore original values of pooled strings.
 if (revCmplDisp)
     {
     for (i=0;  i < rec->alleleCount;  i++)
 	reverseComplement(rec->alleles[i], strlen(rec->alleles[i]));
     }
 return dy->string;
 }
 
-// This is initialized when we start drawing:
-static Color purple = 0;
-
 void mapBoxForCenterVariant(struct vcfRecord *rec, struct hvGfx *hvg, struct track *tg,
 			    int xOff, int yOff, int width)
 /* Special mouseover for center variant */
 {
 static struct dyString *dy = NULL;
 if (dy == NULL)
     dy = dyStringNew(0);
 dyStringClear(dy);
 dyStringPrintf(dy, "%s   Haplotypes sorted on ", gtSummaryString(rec));
 char *centerChrom = cartOptionalStringClosestToHome(cart, tg->tdb, FALSE, "centerVariantChrom");
 if (centerChrom == NULL || !sameString(chromName, centerChrom))
     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 'Use this variant' button below the variant name.");
 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)
     {
     x1--;
     w = 3;
     }
 mapBoxHgcOrHgGene(hvg, rec->chromStart, rec->chromEnd, x1, yOff, w, tg->height, tg->track,
 		  rec->name, dy->string, NULL, TRUE, NULL);
 }
 
+// These are initialized when we start drawing, then constant.
+static Color purple = 0;
+static Color undefYellow = 0;
+
+enum hapColorMode
+    {
+    altOnlyMode,
+    refAltMode,
+    baseMode
+    };
+
+static Color colorByAltOnly(int refs, int alts, int unks)
+/* Coloring alternate alleles only: shade by proportion of alt alleles to refs, unknowns */
+{
+if (unks > (refs + alts))
+    return undefYellow;
+int grayIx = hGrayInRange(alts, 0, alts+refs+unks, maxShade+1) - 1; // undo force to 1
+return shadesOfGray[grayIx];
+}
+
+static Color colorByRefAlt(int refs, int alts, int unks)
+/* Color blue for reference allele, red for alternate allele, gray for unknown, purple
+ * for reasonably mixed. */
+{
+const int fudgeFactor = 4; // Threshold factor for calling one color or the other when mixed
+if (unks > (refs + alts))
+    return undefYellow;
+if (alts > fudgeFactor * refs)
+    return MG_RED;
+if (refs > fudgeFactor * alts)
+    return MG_BLUE;
+return purple;
+}
+
+static Color colorByBase(int refs, int alts, int unks, char *refAl, char *altAl)
+/* Color gray for unknown or mixed, otherwise pgSnpColor of predominant allele. */
+{
+const int fudgeFactor = 4; // Threshold for calling for one color or the other when mixed
+if (unks > (refs + alts))
+    return undefYellow;
+if (alts > fudgeFactor * refs)
+    return pgSnpColor(altAl);
+if (refs > fudgeFactor * alts)
+    return pgSnpColor(refAl);
+return shadesOfGray[5];
+}
+
+// tg->height needs an extra pixel at the bottom; it's eaten by the clipping rectangle:
+#define CLIP_PAD 1
+
 static void drawOneRec(struct vcfRecord *rec, unsigned short *gtHapOrder, unsigned short gtHapCount,
 		       struct track *tg, struct hvGfx *hvg, int xOff, int yOff, int width,
-		       boolean isCenter, boolean colorByRefAlt)
+		       boolean isClustered, boolean isCenter, enum hapColorMode colorMode)
 /* Draw a stack of genotype bars for this record */
 {
 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)
     {
     x1--;
     w = 3;
     }
-double hapsPerPix = (double)gtHapCount / (tg->height-1);
+// When coloring mode is altOnly, we draw one extra pixel row at the top & one at bottom
+// to show the locations of variants, since the reference alleles are invisible:
+int extraPixel = 0;
+int hapHeight = tg->height - CLIP_PAD;
+if (colorMode == altOnlyMode)
+    {
+    hvGfxLine(hvg, x1, yOff, x2, yOff, (isClustered ? purple : shadesOfGray[5]));
+    extraPixel = 1;
+    hapHeight -= extraPixel*2;
+    }
+double hapsPerPix = (double)gtHapCount / hapHeight;
 int pixIx;
-for (pixIx = 0;  pixIx < tg->height-1;  pixIx++)
+for (pixIx = 0;  pixIx < hapHeight;  pixIx++)
     {
     int gtHapOrderIxStart = (int)(hapsPerPix * pixIx);
     int gtHapOrderIxEnd = round(hapsPerPix * (pixIx + 1));
     if (gtHapOrderIxEnd == gtHapOrderIxStart)
 	gtHapOrderIxEnd++;
     int unks = 0, refs = 0, alts = 0;
     int gtHapOrderIx;
     for (gtHapOrderIx = gtHapOrderIxStart;  gtHapOrderIx < gtHapOrderIxEnd;  gtHapOrderIx++)
 	{
 	int gtHapIx = gtHapOrder[gtHapOrderIx];
 	int hapIx = gtHapIx & 1;
 	int gtIx = gtHapIx >>1;
 	struct vcfGenotype *gt = &(rec->genotypes[gtIx]);
 	if (!gt->isPhased && gt->hapIxA != gt->hapIxB)
 	    unks++;
 	else
 	    {
 	    int alIx = hapIx ? gt->hapIxB : gt->hapIxA;
 	    if (alIx)
 		alts++;
 	    else
 		refs++;
 	    }
 	}
-    const int fudgeFactor = 4;
-    Color col = MG_BLACK;
-    if (unks > (refs + alts))
-	col = shadesOfGray[5];
-    else if (alts > fudgeFactor * refs)
-	col = colorByRefAlt ? MG_RED : pgSnpColor(rec->alleles[1]);
-    else if (refs > fudgeFactor * alts)
-	col = colorByRefAlt ? MG_BLUE : pgSnpColor(rec->alleles[0]);
+    int y = yOff + extraPixel + pixIx;
+    Color col;
+    if (colorMode == baseMode)
+	col = colorByBase(refs, alts, unks, rec->alleles[0], rec->alleles[1]);
+    else if (colorMode == refAltMode)
+	col = colorByRefAlt(refs, alts, unks);
     else
-	col = colorByRefAlt ? purple : shadesOfGray[5];
-    int y = yOff + pixIx;
+	col = colorByAltOnly(refs, alts, unks);
+    if (col != MG_WHITE)
     hvGfxLine(hvg, x1, y, x2, y, col);
     }
 char *mouseoverText = gtSummaryString(rec);
+int yBot = yOff + tg->height - CLIP_PAD - 1;
 if (isCenter)
     {
+    if (colorMode == altOnlyMode)
+	{
+	// Colorful outline to distinguish this variant:
+	hvGfxLine(hvg, x1-1, yOff, x1-1, yBot, purple);
+	hvGfxLine(hvg, x2+1, yOff, x2+1, yBot, purple);
+	hvGfxLine(hvg, x1-1, yOff, x2+1, yOff, purple);
+	hvGfxLine(hvg, x1-1, yBot, x2+1, yBot, purple);
+	}
+    else
+	{
     // 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, 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);
+	}
     // Mouseover is handled separately by mapBoxForCenterVariant
     }
 else
     mapBoxHgcOrHgGene(hvg, rec->chromStart, rec->chromEnd, x1, yOff, w, tg->height, tg->track,
 		      rec->name, mouseoverText, NULL, TRUE, NULL);
+if (colorMode == altOnlyMode)
+    hvGfxLine(hvg, x1, yBot, x2, yBot, (isClustered ? purple : shadesOfGray[5]));
 }
 
 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 *centerChrom = cartOptionalStringClosestToHome(cart, tg->tdb, FALSE, "centerVariantChrom");
 if (centerChrom != NULL && sameString(chromName, centerChrom))
     {
     int centerPos = cartUsualIntClosestToHome(cart, tg->tdb, FALSE, "centerVariantPos", -1);
     int winSize = seqEnd - seqStart;
     if (centerPos > (seqStart - winSize) && centerPos < (seqEnd + winSize))
 	{
@@ -695,98 +764,114 @@
 }
 
 /* Pixel y offset return type for recursive tree-drawing: */
 enum yRetType
     {
     yrtMidPoint,
     yrtStart,
     yrtEnd,
     };
 
 /* Callback for calculating y (in pixels) for a cluster node: */
 typedef int yFromNodeFunc(const struct slList *itemOrCluster, void *extraData,
 			  enum yRetType yType);
 
 static int rDrawTreeInLabelArea(struct hacTree *ht, struct hvGfx *hvg, enum yRetType yType, int x,
-				yFromNodeFunc *yFromNode, void *yh, struct titleHelper *th)
+				yFromNodeFunc *yFromNode, void *yh, struct titleHelper *th,
+				boolean drawRectangle)
 /* Recursively draw the haplotype clustering tree in the left label area.
  * Returns pixel height for use at non-leaf levels of tree. */
 {
 const int branchW = 4;
 int labelEnd = leftLabelX + leftLabelWidth;
 if (yType == yrtStart || yType == yrtEnd)
     {
     // We're just getting vertical span of a leaf cluster, not drawing any lines.
     int yLeft, yRight;
     if (ht->left)
-	yLeft = rDrawTreeInLabelArea(ht->left, hvg, yType, x, yFromNode, yh, th);
+	yLeft = rDrawTreeInLabelArea(ht->left, hvg, yType, x, yFromNode, yh, th, drawRectangle);
     else
 	yLeft = yFromNode(ht->itemOrCluster, yh, yType);
     if (ht->right)
-	yRight = rDrawTreeInLabelArea(ht->right, hvg, yType, x, yFromNode, yh, th);
+	yRight = rDrawTreeInLabelArea(ht->right, hvg, yType, x, yFromNode, yh, th, drawRectangle);
     else
 	yRight = yFromNode(ht->itemOrCluster, yh, yType);
     if (yType == yrtStart)
 	return min(yLeft, yRight);
     else
 	return max(yLeft, yRight);
     }
 // Otherwise yType is yrtMidPoint.  If we have 2 children, we'll be drawing some lines:
 if (ht->left != NULL && ht->right != NULL)
     {
     int midY;
     if (ht->childDistance == 0 || x+(2*branchW) > labelEnd)
 	{
 	// Treat this as a leaf cluster.
 	// Recursing twice is wasteful. Could be avoided if this, and yFromNode,
 	// returned both yStart and yEnd. However, the time to draw a tree of
 	// 2188 hap's (1kG phase1 interim) is in the noise, so I consider it
 	// not worth the effort of refactoring to save a sub-millisecond here.
 	int yStartLeft = rDrawTreeInLabelArea(ht->left, hvg, yrtStart, x+branchW,
-					      yFromNode, yh, th);
+					      yFromNode, yh, th, drawRectangle);
 	int yEndLeft = rDrawTreeInLabelArea(ht->left, hvg, yrtEnd, x+branchW,
-					    yFromNode, yh, th);
+					    yFromNode, yh, th, drawRectangle);
 	int yStartRight = rDrawTreeInLabelArea(ht->right, hvg, yrtStart, x+branchW,
-					       yFromNode, yh, th);
+					       yFromNode, yh, th, drawRectangle);
 	int yEndRight = rDrawTreeInLabelArea(ht->right, hvg, yrtEnd, x+branchW,
-					     yFromNode, yh, th);
+					     yFromNode, yh, th, drawRectangle);
 	int yStart = min(yStartLeft, yStartRight);
 	int yEnd = max(yEndLeft, yEndRight);
 	midY = (yStart + yEnd) / 2;
 	Color col = (ht->childDistance == 0) ? purple : MG_BLACK;
+	if (drawRectangle)
+	    {
 	hvGfxLine(hvg, x+branchW-1, yStart, x+branchW-1, yEnd-1, col);
 	hvGfxLine(hvg, x+branchW, yStart, labelEnd, yStart, col);
 	hvGfxLine(hvg, x+branchW, yEnd-1, labelEnd, yEnd-1, col);
+	    }
+	else
+	    {
+	    hvGfxLine(hvg, x, midY, labelEnd, yStart, col);
+	    hvGfxLine(hvg, x, midY, labelEnd, yEnd-1, col);
+	    }
 	addClusterMapItem(ht, x, yStart, labelEnd, yEnd-1, th);
 	}
     else
 	{
 	int leftMid = rDrawTreeInLabelArea(ht->left, hvg, yrtMidPoint, x+branchW,
-					   yFromNode, yh, th);
+					   yFromNode, yh, th, drawRectangle);
 	int rightMid = rDrawTreeInLabelArea(ht->right, hvg, yrtMidPoint, x+branchW,
-					    yFromNode, yh, th);
+					    yFromNode, yh, th, drawRectangle);
 	midY = (leftMid + rightMid) / 2;
+	if (drawRectangle)
 	hvGfxLine(hvg, x+branchW-1, leftMid, x+branchW-1, rightMid, MG_BLACK);
+	else
+	    {
+	    hvGfxLine(hvg, x, midY, x+branchW-1, leftMid, MG_BLACK);
+	    hvGfxLine(hvg, x, midY, x+branchW-1, rightMid, MG_BLACK);
+	    }
 	addClusterMapItem(ht, x, min(leftMid, rightMid), x+branchW-1, max(leftMid, rightMid), th);
 	}
+    if (drawRectangle)
     hvGfxLine(hvg, x, midY, x+branchW-1, midY, MG_BLACK);
     return midY;
     }
 else if (ht->left != NULL)
-    return rDrawTreeInLabelArea(ht->left, hvg, yType, x, yFromNode, yh, th);
+    return rDrawTreeInLabelArea(ht->left, hvg, yType, x, yFromNode, yh, th, drawRectangle);
 else if (ht->right != NULL)
-    return rDrawTreeInLabelArea(ht->right, hvg, yType, x, yFromNode, yh, th);
+    return rDrawTreeInLabelArea(ht->right, hvg, yType, x, yFromNode, yh, th, drawRectangle);
 // Leaf node -- return pixel height. Draw a line if yType is midpoint.
 int y = yFromNode(ht->itemOrCluster, yh, yType);
 if (yType == yrtMidPoint && x < labelEnd)
     {
     hvGfxLine(hvg, x, y, labelEnd, y, purple);
     addClusterMapItem(ht, x, y, labelEnd, y+1, th);
     }
 return y;
 }
 
 struct yFromNodeHelper
 /* Pre-computed mapping from cluster nodes' gtHapIx to pixel heights. */
     {
     unsigned short gtHapCount;
     unsigned short *gtHapIxToPxStart;
@@ -845,127 +930,156 @@
 int len = endIx - startIx;
 AllocArray(th->refs, len);
 AllocArray(th->alts, len);
 struct vcfRecord *rec;
 int i;
 for (rec = vcff->records, i = 0;  rec != NULL && i < endIx;  rec = rec->next, i++)
     {
     if (i < startIx)
 	continue;
     th->refs[i-startIx] = rec->alleles[0];
     th->alts[i-startIx] = cloneString(rec->alleles[1]);
     tolowers(th->alts[i-startIx]);
     }
 }
 
-static void drawTreeInLabelArea(struct hacTree *ht, struct hvGfx *hvg, int yOff, int height,
-				struct yFromNodeHelper *yHelper, struct titleHelper *titleHelper)
+static void drawTreeInLabelArea(struct hacTree *ht, struct hvGfx *hvg, int yOff, int clipHeight,
+				struct yFromNodeHelper *yHelper, struct titleHelper *titleHelper,
+				boolean drawRectangle)
 /* Draw the haplotype clustering in the left label area (as much as fits there). */
 {
 // Figure out which hvg to use, save current clipping, and clip to left label coords:
 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, height);
+hvGfxSetClip(hvgLL, leftLabelX, yOff, leftLabelWidth, clipHeight);
 // Draw the tree:
 int x = leftLabelX;
-(void)rDrawTreeInLabelArea(ht, hvgLL, yrtMidPoint, x, yFromHapNode, yHelper, titleHelper);
+(void)rDrawTreeInLabelArea(ht, hvgLL, yrtMidPoint, x, yFromHapNode, yHelper, titleHelper,
+			   drawRectangle);
 // Restore the prior clipping:
 hvGfxUnclip(hvgLL);
 hvGfxSetClip(hvgLL, clipXBak, clipYBak, clipWidthBak, clipHeightBak);
 }
 
 static void ignoreEm(char *format, va_list args)
 /* Ignore warnings from genotype parsing -- when there's one, there
  * are usually hundreds more just like it. */
 {
 }
 
+static enum hapColorMode getColorMode(struct trackDb *tdb)
+/* Get the hap-cluster coloring mode from cart & tdb. */
+{
+enum hapColorMode colorMode = altOnlyMode;
+char *colorBy = cartUsualStringClosestToHome(cart, tdb, FALSE,
+					     VCF_HAP_COLORBY_VAR, VCF_DEFAULT_HAP_COLORBY);
+if (sameString(colorBy, VCF_HAP_COLORBY_ALTONLY))
+    colorMode = altOnlyMode;
+else if (sameString(colorBy, VCF_HAP_COLORBY_REFALT))
+    colorMode = refAltMode;
+else if (sameString(colorBy, VCF_HAP_COLORBY_BASE))
+    colorMode = baseMode;
+return colorMode;
+}
+
 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;
 purple = hvGfxFindColorIx(hvg, 0x99, 0x00, 0xcc);
-char *colorBy = cartUsualStringClosestToHome(cart, tg->tdb, FALSE,
-					     VCF_HAP_COLORBY_VAR, VCF_HAP_COLORBY_REFALT);
-boolean colorByRefAlt = sameString(colorBy, VCF_HAP_COLORBY_REFALT);
+undefYellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
+enum hapColorMode colorMode = getColorMode(tg->tdb);
 pushWarnHandler(ignoreEm);
 struct vcfRecord *rec;
 for (rec = vcff->records;  rec != NULL;  rec = rec->next)
     vcfParseGenotypes(rec);
 popWarnHandler();
 unsigned short gtHapCount = 0;
 int nRecords = slCount(vcff->records);
 int centerIx = getCenterVariantIx(tg, seqStart, seqEnd, vcff->records);
 // Limit the number of variants that we compare, to keep from timing out:
 // (really what we should limit is the number of distinct haplo's passed to hacTree!)
-const int maxVariantsPerSide = 20;
+// In the meantime, this should at least be a cart var...
+int maxVariantsPerSide = 50;
 int startIx = max(0, centerIx - maxVariantsPerSide);
 int endIx = min(nRecords, centerIx+1 + maxVariantsPerSide);
 struct hacTree *ht = NULL;
 unsigned short *gtHapOrder = clusterHaps(vcff, centerIx, startIx, endIx, &gtHapCount, &ht);
 struct vcfRecord *centerRec = NULL;
 int ix;
 // Unlike drawing order (last drawn is on top), the first mapBox gets priority,
 // so map center variant before drawing & mapping other variants!
 for (rec = vcff->records, ix=0;  rec != NULL;  rec = rec->next, ix++)
     {
     if (ix == centerIx)
 	{
 	centerRec = rec;
 	mapBoxForCenterVariant(rec, hvg, tg, xOff, yOff, width);
 	break;
 	}
     }
 for (rec = vcff->records, ix=0;  rec != NULL;  rec = rec->next, ix++)
     {
+    boolean isClustered = (ix >= startIx && ix < endIx);
     if (ix != centerIx)
-	drawOneRec(rec, gtHapOrder, gtHapCount, tg, hvg, xOff, yOff, width, FALSE, colorByRefAlt);
+	drawOneRec(rec, gtHapOrder, gtHapCount, tg, hvg, xOff, yOff, width, isClustered, FALSE,
+		   colorMode);
     }
 // Draw the center rec on top, outlined with black lines, to make sure it is very visible:
-drawOneRec(centerRec, gtHapOrder, gtHapCount, tg, hvg, xOff, yOff, width, TRUE, colorByRefAlt);
+drawOneRec(centerRec, gtHapOrder, gtHapCount, tg, hvg, xOff, yOff, width, TRUE, TRUE,
+	   colorMode);
 // Draw as much of the tree as can fit in the left label area:
+int extraPixel = (colorMode == altOnlyMode) ? 1 : 0;
+int hapHeight = tg->height- CLIP_PAD - 2*extraPixel;
 struct yFromNodeHelper yHelper = {0, NULL, NULL};
-initYFromNodeHelper(&yHelper, yOff, tg->height-1, gtHapCount, gtHapOrder);
+initYFromNodeHelper(&yHelper, yOff+extraPixel, hapHeight, gtHapCount, gtHapOrder);
 struct titleHelper titleHelper = { NULL, 0, 0, 0, 0, NULL, NULL };
 initTitleHelper(&titleHelper, tg->track, startIx, centerIx, endIx, nRecords, vcff);
-drawTreeInLabelArea(ht, hvg, yOff, tg->height, &yHelper, &titleHelper);
+char *treeAngle = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, VCF_HAP_TREEANGLE_VAR,
+					       VCF_DEFAULT_HAP_TREEANGLE);
+boolean drawRectangle = sameString(treeAngle, VCF_HAP_TREEANGLE_RECTANGLE);
+drawTreeInLabelArea(ht, hvg, yOff+extraPixel, hapHeight+CLIP_PAD, &yHelper, &titleHelper,
+		    drawRectangle);
 }
 
 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 = 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))
     defaultHeight = atoi(tdbHeight);
 int cartHeight = cartUsualIntClosestToHome(cart, tg->tdb, FALSE, VCF_HAP_HEIGHT_VAR,
 					   defaultHeight);
-tg->height = min(cartHeight+1, maximumTrackHeight(tg));
+if (tg->visibility == tvSquish)
+    cartHeight /= 2;
+int extraPixel = (getColorMode(tg->tdb) == altOnlyMode) ? 1 : 0;
+int totalHeight = cartHeight + CLIP_PAD + 2*extraPixel;
+tg->height = min(totalHeight, maximumTrackHeight(tg));
 return tg->height;
 }
 
 static char *vcfHapClusterTrackName(struct track *tg, void *item)
 /* If someone asks for itemName/mapItemName, just send name of track like wiggle. */
 {
 return tg->track;
 }
 
 static void vcfHapClusterOverloadMethods(struct track *tg, struct vcfFile *vcff)
 /* If we confirm at load time that we can draw a haplotype graph, use
  * this to overwrite the methods for the rest of execution: */
 {
 tg->heightPer = (tg->visibility == tvSquish) ? (tl.fontHeight/4) : (tl.fontHeight / 2);
 tg->lineHeight = tg->heightPer + 1;