be36584718d57384b01657483422f51adf29f0bb
max
  Sat Jul 25 18:22:02 2026 -0700
vcfTrack: add minimum alternate allele count (minAc) filter, refs #37927

When a VCF INFO column includes AC, offer a 'minimum allele count' filter in the
track UI (e.g. 2 to hide singletons) and drop records whose largest alternate
allele count is below the threshold.

diff --git src/hg/lib/vcfUi.c src/hg/lib/vcfUi.c
index bb3a5188e0c..7ba16bd1580 100644
--- src/hg/lib/vcfUi.c
+++ src/hg/lib/vcfUi.c
@@ -430,30 +430,44 @@
 
 static void vcfCfgMinAlleleFreq(struct cart *cart, struct trackDb *tdb, struct vcfFile *vcff,
 				char *name, boolean parentLevel)
 /* Show input for minimum allele frequency, if we can extract it from the VCF INFO column. */
 {
 printf("<B>Minimum minor allele frequency (if INFO column includes AF or AC+AN):</B>\n");
 double cartMinFreq = cartOrTdbDouble(cart, tdb, VCF_MIN_ALLELE_FREQ_VAR,
 				     VCF_DEFAULT_MIN_ALLELE_FREQ);
 char varName[1024];
 safef(varName, sizeof(varName), "%s." VCF_MIN_ALLELE_FREQ_VAR, name);
 cgiMakeDoubleVarInRange(varName, cartMinFreq, "minor allele frequency between 0.0 and 0.5", 5,
 			"0.0", "0.5");
 puts("<BR>");
 }
 
+static void vcfCfgMinAc(struct cart *cart, struct trackDb *tdb, struct vcfFile *vcff,
+			char *name, boolean parentLevel)
+/* Show input for minimum alternate allele count, if INFO column includes AC.  This lets
+ * the user filter on a whole-number count (e.g. 2 to hide singletons) instead of having to
+ * enter a tiny frequency cutoff. */
+{
+printf("<B>Minimum allele count (if INFO column includes AC), e.g. 2 to hide singletons:</B>\n");
+int cartMinAc = cartOrTdbInt(cart, tdb, VCF_MIN_AC_VAR, VCF_DEFAULT_MIN_AC);
+char varName[1024];
+safef(varName, sizeof(varName), "%s." VCF_MIN_AC_VAR, name);
+cgiMakeIntVarWithMin(varName, cartMinAc, "minimum allele count", 5, 0);
+puts("<BR>");
+}
+
 static char *getChildSample(struct trackDb *tdb)
 /* Return just the VCF sample name of the phased trio child setting */
 {
 char *childSampleMaybeAlias = cloneString(trackDbLocalSetting(tdb, VCF_PHASED_CHILD_SAMPLE_SETTING));
 char *pt = strchr(childSampleMaybeAlias, '|');
 if (pt != NULL)
     *pt = '\0';
 return childSampleMaybeAlias;
 }
 
 static struct slPair *vcfPhasedGetSamplesFromTdb(struct trackDb *tdb, boolean hideOtherSamples)
 /* Get the different VCF Phased Trio setings out of trackDb onto a list */
 {
 // cloneString here because we will be munging the result if there are alternate labels
 char *childSampleMaybeAlias = cloneString(trackDbLocalSetting(tdb, VCF_PHASED_CHILD_SAMPLE_SETTING));
@@ -688,48 +702,51 @@
 printInfoIcon(phasedInfoText);
 }
 
 void vcfCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed)
 /* VCF: Variant Call Format.  redmine #3710 */
 {
 boxed = cfgBeginBoxAndTitle(tdb, boxed, title);
 printf("<TABLE%s><TR><TD>", boxed ? " width='100%'" : "");
 struct vcfFile *vcff = vcfHopefullyOpenHeader(cart, tdb);
 if (vcff != NULL)
     {
     boolean parentLevel = isNameAtParentLevel(tdb, name);
     boolean doVcfFilterUi = cartOrTdbBoolean(cart, tdb, VCF_DO_FILTER_UI, TRUE);
     boolean doVcfQualUi = cartOrTdbBoolean(cart, tdb, VCF_DO_QUAL_UI, TRUE);
     boolean doVcfMafUi = cartOrTdbBoolean(cart, tdb, VCF_DO_MAF_UI, TRUE);
+    boolean doVcfMinAcUi = cartOrTdbBoolean(cart, tdb, VCF_DO_MIN_AC_UI, TRUE);
     if (vcff->genotypeCount > 1 && !sameString(tdb->type, "vcfPhasedTrio"))
         {
         vcfCfgHapCluster(cart, tdb, vcff, name, parentLevel);
         }
     if (sameString(tdb->type, "vcfPhasedTrio"))
         {
         vcfCfgPhasedTrioUi(cart, tdb, vcff, name, parentLevel);
         }
     if (differentString(tdb->track,"evsEsp6500") && (doVcfFilterUi || doVcfQualUi))
         {
         puts("<H3>Filters</H3>");
         if (doVcfQualUi)
             vcfCfgMinQual(cart, tdb, vcff, name, parentLevel);
         if (doVcfFilterUi)
             vcfCfgFilterColumn(cart, tdb, vcff, name, parentLevel);
         }
     if (doVcfMafUi)
         vcfCfgMinAlleleFreq(cart, tdb, vcff, name, parentLevel);
+    if (doVcfMinAcUi)
+        vcfCfgMinAc(cart, tdb, vcff, name, parentLevel);
     }
 else
     {
     printf("Sorry, couldn't access VCF file.<BR>\n");
     }
 
 puts("</TD>");
 if (boxed && fileExists(hHelpFile("hgVcfTrackHelp")))
     printf("<TD style='text-align:right'><A HREF=\"../goldenPath/help/hgVcfTrackHelp.html\" "
            "TARGET=_BLANK>VCF configuration help</A></TD>");
 
 printf("</TR></TABLE>");
 wigOption(cart, name, title, tdb);
 
 if (!boxed && fileExists(hHelpFile("hgVcfTrackHelp")))