42d91822ec103cfcc74e9f69b39d3ad8d886c278
angie
  Wed Mar 18 15:25:15 2020 -0700
Add a new trackDb setting hapClusterMethod and corresponding UI option for drawing haplotypes in VCF file order instead of clustering.  refs #25197
Applied the new setting to mm10 strainSNPs and increased its default height so that strain labels appear in the left label area.

diff --git src/hg/lib/vcfUi.c src/hg/lib/vcfUi.c
index 8b6c592..d4c94e6 100644
--- src/hg/lib/vcfUi.c
+++ src/hg/lib/vcfUi.c
@@ -36,100 +36,123 @@
 char ctrPosStr[16];
 safef(ctrPosStr, sizeof(ctrPosStr), "%d", ctrPos);
 cgiMakeHiddenVar(cartVar, ctrPosStr);
 safef(cartVar, sizeof(cartVar), "%s.centerVariantName", track);
 cgiMakeHiddenVar(cartVar, ctrName);
 }
 
 void vcfCfgHaplotypeCenter(struct cart *cart, struct trackDb *tdb, char *track,
 			   boolean parentLevel, struct vcfFile *vcff,
 			   char *thisName, char *thisChrom, int thisPos, char *formName)
 /* If vcff has genotype data, show status and controls for choosing the center variant
  * for haplotype clustering/sorting in hgTracks. */
 {
 if (vcff != NULL && vcff->genotypeCount > 1)
     {
-    printf("<TABLE cellpadding=0><TR><TD>"
-	   "<B>Haplotype sorting order:</B> using ");
+    printf("using ");
     char *centerChrom = cartOptionalStringClosestToHome(cart, tdb, parentLevel,
 							"centerVariantChrom");
     if (isEmpty(centerChrom))
 	{
 	// Unspecified in cart -- describe the default action
 	printf(VCF_HAPLOSORT_DEFAULT_DESC " as anchor.</TD></TR>\n");
 	if (isNotEmpty(thisChrom))
 	    {
 	    // but we do have a candidate, so offer to make it the center:
-	    puts("<TR><TD>");
+	    puts("<TR><TD></TD><TD>");
 	    vcfCfgHaplotypeCenterHiddens(track, thisName, thisChrom, thisPos);
 	    char label[256];
 	    safef(label, sizeof(label), "Use %s", nameOrDefault(thisName, "this variant"));
 	    cgiMakeButton("setCenterSubmit", label);
 	    printf(" as anchor</TD></TR>\n");
 	    }
 	else
-	    printf("<TR><TD>To anchor the sorting to a particular variant, "
+	    printf("<TR><TD></TD><TD>To anchor the sorting to a particular variant, "
 		   "click on the variant in the genome browser, "
 		   "and then click on the 'Use this variant' button on the next page."
 		   "</TD></TR>\n");
 	}
     else
 	{
 	// Describe the one specified in cart.
 	int centerPos = cartUsualIntClosestToHome(cart, tdb, parentLevel, "centerVariantPos",
 						  -1);
 	char *centerName = cartStringClosestToHome(cart, tdb, parentLevel, "centerVariantName");
 	if (isNotEmpty(thisChrom))
 	    {
 	    // These form inputs are for either "use me" or clear:
 	    vcfCfgHaplotypeCenterHiddens(track, thisName, thisChrom, thisPos);
 	    // Is this variant the same as the center variant specified in cart?
 	    if (sameString(thisChrom, centerChrom) && sameString(thisName, centerName) &&
 		thisPos == centerPos)
 		printf("this variant as anchor.</TD></TR>\n");
 	    else
 		{
 		// make a "use me" button
-		printf("%s at %s:%d as anchor.</TD></TR>\n<TR><TD>\n",
+		printf("%s at %s:%d as anchor.</TD></TR>\n<TR><TD></TD><TD>\n",
 		       nameOrDefault(centerName, "variant"), centerChrom, centerPos+1);
 		char label[256];
 		safef(label, sizeof(label), "Use %s", nameOrDefault(thisName, "this variant"));
 		cgiMakeButton("replaceCenterSubmit", label);
 		printf(" as anchor</TD></TR>\n");
 		}
 	    }
 	else
 	    {
 	    // Form inputs (in case the clear button is clicked)
 	    vcfCfgHaplotypeCenterHiddens(track, centerName, centerChrom, centerPos);
 	    printf("%s at %s:%d as anchor.</TD></TR>\n",
 		   nameOrDefault(centerName, "variant"), centerChrom, centerPos+1);
 	    }
 	// Make a clear button that modifies the hiddens using onClick
-	puts("<TR><TD>");
+	puts("<TR><TD></TD><TD>");
 	struct dyString *onClick = dyStringNew(0);
 	dyStringPrintf(onClick, "updateOrMakeNamedVariable(%s, '%s.centerVariantChrom', ''); ",
 		       formName, track);
 	dyStringPrintf(onClick, "updateOrMakeNamedVariable(%s, '%s.centerVariantName', ''); ",
 		       formName, track);
 	dyStringPrintf(onClick, "updateOrMakeNamedVariable(%s, '%s.centerVariantPos', 0);",
 		       formName, track);
 	dyStringPrintf(onClick, "document.%s.submit(); return false;", formName);
 	cgiMakeButtonWithOnClick("clearCenterSubmit", "Clear selection", NULL, onClick->string);
 	printf(" (use " VCF_HAPLOSORT_DEFAULT_DESC ")</TD></TR>\n");
 	}
-    puts("</TABLE>");
+    }
+}
+
+static void vcfCfgHaplotypeMethod(struct cart *cart, struct trackDb *tdb, char *track,
+                                  boolean parentLevel, struct vcfFile *vcff)
+/* If vcff has genotype data, offer the option of whether to cluster or just use the order
+ * of genotypes in the VCF file.  For clustering, show status and controls for choosing the
+ * center variant for haplotype clustering/sorting in hgTracks. */
+{
+if (vcff != NULL && vcff->genotypeCount > 1)
+    {
+    printf("<TABLE cellpadding=0><TR><TD colspan=2>"
+	   "<B>Haplotype sorting order:</B></TD></TR><TR><TD>\n");
+    char *hapMethod = cartOrTdbString(cart, tdb, VCF_HAP_METHOD_VAR, VCF_DEFAULT_HAP_METHOD);
+    char varName[1024];
+    safef(varName, sizeof(varName), "%s." VCF_HAP_METHOD_VAR, track);
+    cgiMakeRadioButton(varName, VCF_HAP_METHOD_CENTER_WEIGHTED,
+                       sameString(hapMethod, VCF_HAP_METHOD_CENTER_WEIGHTED));
+    printf("</TD><TD>");
+    vcfCfgHaplotypeCenter(cart, tdb, track, parentLevel, vcff, NULL, NULL, 0, "mainForm");
+    puts("<TR><TD>");
+    cgiMakeRadioButton(varName, VCF_HAP_METHOD_FILE_ORDER,
+                       sameString(hapMethod, VCF_HAP_METHOD_FILE_ORDER));
+    puts("</TD><TD>Using the order in which samples appear in the underlying VCF file");
+    puts("</TR></TD></TABLE>");
     }
 }
 
 //TODO: share this code w/hgTracks, hgc in hg/lib/vcfFile.c
 static struct vcfFile *vcfHopefullyOpenHeader(struct cart *cart, struct trackDb *tdb)
 /* Defend against network errors and return the vcfFile object with header data, or NULL. */
 {
 knetUdcInstall();
 if (udcCacheTimeout() < 300)
     udcSetCacheTimeout(300);
 char *fileOrUrl = trackDbSetting(tdb, "bigDataUrl");
 if (isEmpty(fileOrUrl))
     {
     char *db = cartString(cart, "db");
     char *table = tdb->table;
@@ -224,31 +247,31 @@
     printf("<B>Haplotype sorting display height:</B> \n");
     int cartHeight = cartOrTdbInt(cart, tdb, VCF_HAP_HEIGHT_VAR, VCF_DEFAULT_HAP_HEIGHT);
     char varName[1024];
     safef(varName, sizeof(varName), "%s." VCF_HAP_HEIGHT_VAR, name);
     cgiMakeIntVarInRange(varName, cartHeight, "Height (in pixels) of track", 5, "4", "2500");
     puts("<BR>");
     }
 }
 
 static void vcfCfgHapCluster(struct cart *cart, struct trackDb *tdb, struct vcfFile *vcff,
 			     char *name, boolean parentLevel)
 /* Show controls for haplotype-sorting display, which only makes sense to do when
  * the VCF file describes multiple genotypes. */
 {
 vcfCfgHapClusterEnable(cart, tdb, name, parentLevel);
-vcfCfgHaplotypeCenter(cart, tdb, name, parentLevel, vcff, NULL, NULL, 0, "mainForm");
+vcfCfgHaplotypeMethod(cart, tdb, name, parentLevel, vcff);
 vcfCfgHapClusterColor(cart, tdb, name, parentLevel);
 vcfCfgHapClusterTreeAngle(cart, tdb, name, parentLevel);
 vcfCfgHapClusterHeight(cart, tdb, vcff, name, parentLevel);
 }
 
 static void vcfCfgMinQual(struct cart *cart, struct trackDb *tdb, struct vcfFile *vcff,
 			  char *name, boolean parentLevel)
 /* If checkbox is checked, apply minimum value filter to QUAL column. */
 {
 char cartVar[1024];
 safef(cartVar, sizeof(cartVar), "%s." VCF_APPLY_MIN_QUAL_VAR, name);
 boolean applyFilter = cartOrTdbBoolean(cart, tdb, VCF_APPLY_MIN_QUAL_VAR,
 				       VCF_DEFAULT_APPLY_MIN_QUAL);
 cgiMakeCheckBox(cartVar, applyFilter);
 printf("<B>Exclude variants with Quality/confidence score (QUAL) score less than</B>\n");