81d00f3eec6ea6978c9a71ed6a48c84a0bd0c987 braney Wed Apr 22 14:51:08 2026 -0700 hgFind: remap bigBed search hits from source to destination coords when the track is quickLifted. Previously a search for e.g. "BRCA2" on a quickLifted hub (hg38 tracks displayed on HG02257.pat) returned hits at hg38 chr13 coordinates; clicking the result errored with "Sorry, couldn't locate chr13:... in <dest>". Adds quickLiftLiftPos() in hg/lib/quickLift.c, which reads the source->dest liftOverChainFile and calls liftOverRemapRange. Called from bigBedIntervalListToHgPositions in hg/lib/bigBedFind.c whenever tdb has quickLiftUrl/quickLiftDb; hits that don't map through the chain are dropped. refs #36340 diff --git src/hg/lib/bigBedFind.c src/hg/lib/bigBedFind.c index 24b85d71d62..70f19589be0 100644 --- src/hg/lib/bigBedFind.c +++ src/hg/lib/bigBedFind.c @@ -1,40 +1,47 @@ #include "common.h" #include "bPlusTree.h" #include "bbiFile.h" #include "bigBed.h" #include "hgFind.h" #include "trix.h" #include "trackHub.h" #include "hubConnect.h" #include "hdb.h" #include "errCatch.h" #include "bigBedLabel.h" #include "bigBedFind.h" #include "genbank.h" +#include "quickLift.h" static struct hgPos *bigBedIntervalListToHgPositions(struct cart *cart, struct trackDb *tdb, struct bbiFile *bbi, char *term, struct bigBedInterval *intervalList, char *description, struct hgFindSpec *hfs, char *db) /* Given an open bigBed file, and an interval list, return a pointer to a list of hgPos structures. */ { struct hgPos *posList = NULL; char chromName[bbi->chromBpt->keySize+1]; int lastChromId = -1; struct bigBedInterval *interval; struct slInt *labelColumns = NULL; +// If this track is being quickLifted, the bigBed returns hits in the source +// assembly's coordinates; we need to remap them to the destination assembly. +char *quickLiftDb = trackDbSetting(tdb, "quickLiftDb"); +boolean quickLifted = (trackDbSetting(tdb, "quickLiftUrl") != NULL) && isNotEmpty(quickLiftDb); +char *destDb = trackHubSkipHubName(db); + // Generic searchItemLabel support: allows ${fieldName} patterns in hgFindSpec char *searchItemLabel = NULL; char **fieldNames = NULL; if (hfs) searchItemLabel = hgFindSpecSetting(hfs, "searchItemLabel"); if (searchItemLabel) { AllocArray(fieldNames, bbi->fieldCount); struct slName *field = NULL, *fields = bbFieldNames(bbi); int i = 0; for (field = fields; field != NULL && i < bbi->fieldCount; field = field->next) fieldNames[i++] = field->name; } // MANE/HGNC description support @@ -45,40 +52,51 @@ { as = bigBedAsOrDefault(bbi); if (sameString(hfs->searchName, "mane")) { conn = hAllocConn(db); ncbiIdIx = asColumnFindIx(as->columnList, "ncbiId"); } else if (sameString(hfs->searchName, "hgnc")) geneNameIx = asColumnFindIx(as->columnList, "geneName"); } bigBedLabelCalculateFields(cart, tdb, bbi, &labelColumns ); char startBuf[256], endBuf[256], *row[bbi->fieldCount]; for (interval = intervalList; interval != NULL; interval = interval->next) { + bbiCachedChromLookup(bbi, interval->chromId, lastChromId, chromName, sizeof(chromName)); + lastChromId = interval->chromId; + + char *posChrom = chromName; + int posStart = interval->start; + int posEnd = interval->end; + if (quickLifted) + { + // Remap source-assembly coords to destination-assembly coords; skip if unmappable. + if (!quickLiftLiftPos(quickLiftDb, destDb, chromName, interval->start, interval->end, + &posChrom, &posStart, &posEnd)) + continue; + } + struct hgPos *hgPos; AllocVar(hgPos); slAddHead(&posList, hgPos); - bbiCachedChromLookup(bbi, interval->chromId, lastChromId, chromName, sizeof(chromName)); - lastChromId = interval->chromId; - - hgPos->chrom = cloneString(chromName); - hgPos->chromStart = interval->start; - hgPos->chromEnd = interval->end; + hgPos->chrom = cloneString(posChrom); + hgPos->chromStart = posStart; + hgPos->chromEnd = posEnd; hgPos->description = cloneString(description); int rowFieldCount = bigBedIntervalToRow(interval, chromName, startBuf, endBuf, row, bbi->fieldCount); if (searchItemLabel) { hgPos->name = replaceFieldInPattern(searchItemLabel, bbi->fieldCount, fieldNames, row); } else { hgPos->name = bigBedMakeLabel(tdb, labelColumns, interval, chromName); } // browserName needs to correspond to tg->mapItemName() if (rowFieldCount > 3) hgPos->browserName = cloneString(row[3]); else