0d3b8feb6074f6caccc2d4aadd020961fbd7eb82
chmalee
Wed Jun 10 14:39:38 2020 -0700
Add drag reorder of VCF samples to VCF trio display. Also fixes bug in haplotype sort that I didn't discover until adding drag reorder. Sometimes when sorting haplotypes it is the case that the initial best match to a child allele is the same for each parent. Previously I would just advance the first drawn parent to the next best match but now I also check whether advancing the first drawn is actually the best idea and potentially advance the other parent instead, refs #25582
diff --git src/hg/lib/vcfUi.c src/hg/lib/vcfUi.c
index 4d579eb..f5b777e 100644
--- src/hg/lib/vcfUi.c
+++ src/hg/lib/vcfUi.c
@@ -372,30 +372,40 @@
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("Minimum minor allele frequency (if INFO column includes AF or AC+AN):\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("
");
}
+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));
char *parentSamplesMaybeAlias = cloneString(trackDbLocalSetting(tdb, VCF_PHASED_PARENTS_SAMPLE_SETTING));
char *samples[VCF_PHASED_MAX_OTHER_SAMPLES+1]; // for now only allow at most two parents
int numOthers = 0;
if (parentSamplesMaybeAlias && !hideOtherSamples)
{
numOthers = chopCommas(cloneString(parentSamplesMaybeAlias), samples);
if (numOthers > VCF_PHASED_MAX_OTHER_SAMPLES)
{
warn("More than %d other samples specified for phased trio", VCF_PHASED_MAX_OTHER_SAMPLES);
numOthers = VCF_PHASED_MAX_OTHER_SAMPLES;
@@ -419,67 +429,165 @@
if (val != NULL)
{
if (foundAlias != gotAlias)
errAbort("Either all samples have aliases or none.");
else
*val++ = 0;
}
char *name = samples[i];
struct slPair *temp = slPairNew(cloneString(name), cloneString(val));
slAddHead(&ret, temp);
}
slReverse(&ret);
return ret;
}
-struct slPair *vcfPhasedGetSampleOrder(struct cart *cart, struct trackDb *tdb, boolean parentLevel)
-/* Parse out a trio sample order from either trackDb or the cart */
+struct slPair *vcfPhasedGetSampleOrder(struct cart *cart, struct trackDb *tdb, boolean parentLevel, boolean hideOtherSamples)
+/* Parse out a trio sample order from either trackDb or the cart.
+ * If the trackName.sortChildBelow cart variable is true, then ensure
+ * the vcfChildSample sample is last in the order, otherwise, use what's
+ * in the trackName.vcfSampleOrder cart variable. */
{
-char sampleOrderVar[1028],hideParentsVar[1028];
+char sampleOrderVar[1024];
safef(sampleOrderVar, sizeof(sampleOrderVar), "%s.%s", tdb->track, VCF_PHASED_SAMPLE_ORDER_VAR);
-safef(hideParentsVar, sizeof(hideParentsVar), "%s.%s", tdb->track, VCF_PHASED_HIDE_OTHER_VAR);
-boolean hideOtherSamples = cartUsualBooleanClosestToHome(cart, tdb, parentLevel, VCF_PHASED_HIDE_OTHER_VAR, FALSE);
char *cartOrder = cartOptionalString(cart, sampleOrderVar);
+boolean childBelow = cartUsualBooleanClosestToHome(cart, tdb, parentLevel, VCF_PHASED_CHILD_BELOW_VAR, FALSE);
struct slPair *tdbOrder = vcfPhasedGetSamplesFromTdb(tdb, hideOtherSamples);
-if (cartOrder != NULL && !hideOtherSamples)
+if (!hideOtherSamples)
+ {
+ // if the user used drag and drop to reorder the trios then that takes precedence
+ // over the childBelow checkbox
+ if (cartOrder != NULL)
{
- struct slName *name;
- struct slName *fromCart = slNameListFromComma(cartOrder);
+ struct slName *name, *fromCart = slNameListFromComma(cartOrder);
struct slPair *ret = NULL;
for (name = fromCart; name != NULL; name = name->next)
{
struct slPair *temp = slPairFind(tdbOrder, name->name);
- slAddHead(&ret, temp);
+ struct slPair *toAdd = slPairNew(temp->name, temp->val);
+ slAddHead(&ret, toAdd);
}
- slReverse(ret);
+ slReverse(&ret);
return ret;
}
+ else if (childBelow)
+ {
+ char *childName = getChildSample(tdb);
+ struct slPair *ret = NULL, *child = NULL, *temp = NULL;
+ for (temp = tdbOrder; temp != NULL; temp = temp->next)
+ {
+ struct slPair *toAdd = slPairNew(temp->name, temp->val);
+ if (sameString(temp->name, childName))
+ child = toAdd;
else
+ slAddHead(&ret, toAdd);
+ }
+ if (child)
+ slAddHead(&ret, child);
+ slReverse(&ret);
+ return ret;
+ }
+ }
+// we're hiding the parents OR (we unchecked the childBelow checkbox AND we didn't drag reorder)
return tdbOrder;
}
static boolean hasSampleAliases(struct trackDb *tdb)
/* Check whether trackDb has aliases for the sample names */
{
struct slPair *nameVals = vcfPhasedGetSamplesFromTdb(tdb,FALSE);
return nameVals->val != NULL;
}
+static void vcfPhasedSampleSortUi(struct cart *cart, struct trackDb *tdb, struct vcfFile *vcff, char *name,
+ boolean parentLevel)
+/* Put up the UI for sorting the samples */
+{
+struct dyString *sortOrder = dyStringNew(0);
+struct slPair *pair, *tdbOrder = vcfPhasedGetSampleOrder(cart, tdb, parentLevel, FALSE);
+if (slCount(tdbOrder) == 1) // no sorting if there are no parents
+ return;
+char childBelowSortOrder[1024];
+safef(childBelowSortOrder, sizeof(childBelowSortOrder), "%s.%s", name, VCF_PHASED_CHILD_BELOW_VAR);
+boolean isBelowChecked = cartUsualBooleanClosestToHome(cart, tdb, parentLevel, VCF_PHASED_CHILD_BELOW_VAR, FALSE);
+printf("Show child haplotypes below parents:\n");
+cgiMakeCheckBox(childBelowSortOrder, isBelowChecked);
+char *infoText = "Check this box to sort the child haplotypes below the parents, leave unchecked"
+ " to use the default sort order of the child in the middle. Click into each subtrack to arbitrarily"
+ " order the samples which overrides this setting.";
+printInfoIcon(infoText);
+printf("
");
+if (!parentLevel)
+ {
+ printf("or:
\n");
+ printf("Click and drag to change order:\n");
+ printf("
%s - %s |