b53f0365865b5449ef209ea86c5220dd07dc8b28 braney Fri Aug 7 12:07:45 2026 -0700 quickLift: don't report items that failed to lift as filtered out, refs #38033 Items that could not be mapped through the chain were counted by the same variable the track filters use, so a lifted view claimed a number of items had been filtered out when no filter had removed anything. Count the two cases apart: failing a filter is a filter rejection, while passing the filters and then getting nothing back from the lift is a lift failure, and say so in the label. diff --git src/hg/hgTracks/bigBedTrack.c src/hg/hgTracks/bigBedTrack.c index 4431139ac4b..9fcef60b3b3 100644 --- src/hg/hgTracks/bigBedTrack.c +++ src/hg/hgTracks/bigBedTrack.c @@ -785,34 +785,38 @@ mouseOverPattern = cartOrTdbString(cart, track->tdb, "mouseOver", NULL); if (mouseOverPattern) { AllocArray(fieldNames, bbi->fieldCount); struct slName *field = NULL, *fields = bbFieldNames(bbi); int i = 0; for (field = fields; field != NULL; field = field->next) fieldNames[i++] = field->name; } } // a fake item that is the union of the items that span the current window struct linkedFeatures *spannedLf = NULL; unsigned filtered = 0; +unsigned notLifted = 0; struct bed *bed = NULL, *bedCopy = NULL; for (bb = bbList; bb != NULL; bb = bb->next) { struct linkedFeatures *lf = NULL; + // an item that passed the filters but has no clean mapping through the chain was + // dropped by the lift, not by a filter, and needs to be reported in its own words + boolean liftFailed = FALSE; bedCopy = NULL; char *bedRow[bbi->fieldCount]; if (sameString(track->tdb->type, "bigPsl")) { // fill out bedRow to support mouseOver pattern replacements char startBuf[16], endBuf[16]; bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); char *seq, *cds; struct psl *psl = pslFromBigPsl(chromName, bb, seqTypeField, &seq, &cds); int sizeMul = pslIsProtein(psl) ? 3 : 1; boolean isXeno = 0; // just affects grayIx boolean nameGetsPos = FALSE; // we want the name to stay the name if (sizeMul == 3) { @@ -841,30 +845,32 @@ } else { char startBuf[16], endBuf[16]; bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); if (bigBedFilterInterval(bbi, bedRow, filters)) { if (quickLiftFile) { if ((bed = quickLiftIntervalsToBed(bbi, chainHash, bb)) != NULL) { bedCopy = cloneBed(bed); lf = bedMungToLinkedFeatures(&bed, tdb, fieldCount, scoreMin, scoreMax, useItemRgb); } + else + liftFailed = TRUE; } else { bed = bedLoadN(bedRow, fieldCount == 7 ? 6 : fieldCount); bedCopy = cloneBed(bed); lf = bedMungToLinkedFeatures(&bed, tdb, fieldCount, scoreMin, scoreMax, useItemRgb); } } if (lf && highlights) addHighlightToLinkedFeature(lf, highlights, bbi, bedRow, track->tdb); if (lf && squishFieldIdx) lf->squishyPackVal = atof(restField(bb, squishFieldIdx)); @@ -921,30 +927,33 @@ else if (mouseOverPattern) { char qStartBuf[16], qEndBuf[16]; if (quickLiftFile && bedCopy) quickLiftSetCoordFields(bedRow, bedCopy, qStartBuf, qEndBuf, sizeof qStartBuf); tmp->mouseOver = replaceFieldInPattern(mouseOverPattern, bbi->fieldCount, fieldNames, bedRow); } slAddHead(&spannedLf, tmp); } continue; // lf will be NULL, but these items aren't "filtered", they're merged } } if (lf == NULL) { + if (liftFailed) + notLifted++; + else filtered++; continue; } if (lf->label == NULL) lf->label = bigBedMakeLabel(track->tdb, track->labelColumns, bb, chromName); if (startsWith("bigGenePred", track->tdb->type) || startsWith("genePred", track->tdb->type)) { // bedRow[5] has original strand in it, bedCopy has new strand. If they're different we want to reverse exonFrames boolean changedStrand = FALSE; if (quickLiftFile) { if (*bedRow[5] != *bedCopy->strand) changedStrand = TRUE; } @@ -968,30 +977,33 @@ lf->mouseOver = restField(bb, mouseOverIdx); else if (mouseOverPattern) { char qStartBuf[16], qEndBuf[16]; if (quickLiftFile && bedCopy) quickLiftSetCoordFields(bedRow, bedCopy, qStartBuf, qEndBuf, sizeof qStartBuf); lf->mouseOver = replaceFieldInPattern(mouseOverPattern, bbi->fieldCount, fieldNames, bedRow); } } slAddHead(pLfList, lf); } if (filtered) labelTrackAsFilteredNumber(track, filtered); +if (notLifted) + track->longLabel = labelAsNotLiftedNumber(track->longLabel, notLifted); + if (doWindowSizeFilter) // add the number of merged items to the track longLabel { char labelBuf[256]; if (mergeCount > 1) safef(labelBuf, sizeof(labelBuf), " (Merged %d items)", mergeCount); else safef(labelBuf, sizeof(labelBuf), " (No Items Merged in window)"); track->longLabel = catTwoStrings(track->longLabel, labelBuf); } if (spannedLf) { // if two or more items were merged together, fix up the label of the special merged item, // otherwise the label and mouseOver will be the normal bed one