544f7054d812254a0883a412b98a08dcd78f1b84 braney Fri Sep 4 11:39:41 2026 -0700 hgTracks: draw quickLifted psl and bigPsl tracks pslTrack.c had no quickLift path at all. It now reads the alignments out of the assembly the track came from through quickLiftSql and maps them onto the reference. The chromFilter clause and the sort-and-filter tail moved into helpers so the two loaders cannot drift apart. bigBedTrack.c built the alignment out of the source interval but labelled it with the reference sequence name and never lifted it, so a quickLifted bigPsl track drew its items in the wrong place. It now takes the real source name out of the bigBed, lifts, counts a failure the way the bed path does, and rewrites the coordinate fields so a $chromStart in a mouseOver reports where the item is drawn. cds.c asked the assembly on screen for the CDS and for the sequence the alignment is to. Both belong to the assembly the alignment came from. This was already the wrong answer for a quickLifted track on any target, and on a hub-backed target it fails outright, because the name of such an assembly is not a database. The table-exists answer is now remembered per assembly rather than once for the process, since one page can hold both native and lifted alignment tracks. The mRNA filter reads the same source assembly, for the same reason: the accessions and the gbCdnaInfo ids are the source assembly's. refs #38249 diff --git src/hg/hgTracks/bigBedTrack.c src/hg/hgTracks/bigBedTrack.c index 12d645ce302..c5cdac79997 100644 --- src/hg/hgTracks/bigBedTrack.c +++ src/hg/hgTracks/bigBedTrack.c @@ -12,30 +12,31 @@ #include "hdb.h" #include "bedCart.h" #include "hgTracks.h" #include "hmmstats.h" #include "localmem.h" #include "wigCommon.h" #include "bbiFile.h" #include "obscure.h" #include "bigWig.h" #include "bigBed.h" #include "bigWarn.h" #include "errCatch.h" #include "trackHub.h" #include "net.h" #include "bigPsl.h" +#include "bPlusTree.h" // for the chrom-name key size of the bigBed we are reading #include "bigBedFilter.h" #include "bigBedLabel.h" #include "variation.h" #include "chromAlias.h" #include "quickLift.h" #include "hgConfig.h" #include "heatmap.h" static unsigned getFieldNum(struct bbiFile *bbi, char *field) // get field number for field name in bigBed. errAbort if field not found. { int fieldNum = bbFieldIndex(bbi, field); if (fieldNum < 0) fieldNum = defaultFieldLocation(field); if (fieldNum < 0) @@ -786,67 +787,106 @@ 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; +struct hash *mapPsls = NULL; // mapping alignments quickLift reuses across items +int lastChromId = -1; +char otherChrom[bbi->chromBpt->keySize+1]; +char startBuf[16], endBuf[16]; 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; + // Under quickLift the interval came out of the other assembly's file, so the + // alignment has to carry that assembly's sequence name: chromName is the name on + // the reference, and the chains are looked up by the name on the other side. + char *pslChrom = chromName; + if (quickLiftFile) + { + bbiCachedChromLookup(bbi, bb->chromId, lastChromId, otherChrom, sizeof otherChrom); + lastChromId = bb->chromId; + pslChrom = otherChrom; + } + struct psl *psl = pslFromBigPsl(pslChrom, bb, seqTypeField, &seq, &cds); + boolean isProt = pslIsProtein(psl); boolean isXeno = 0; // just affects grayIx boolean nameGetsPos = FALSE; // we want the name to stay the name - if (sizeMul == 3) + if (isProt) { // these tags are not currently supported by the drawing engine for protein psl hashRemove(track->tdb->settingsHash, "showDiffBasesAllScales"); hashRemove(track->tdb->settingsHash, "baseColorUseSequence"); hashRemove(track->tdb->settingsHash, "baseColorDefault"); } + if (quickLiftFile) + { + // Move the alignment's target side onto the reference. Ask the lifted + // alignment about its own block sizes rather than reusing isProt: the lift + // puts a protein alignment into nucleotide space on the way through. + struct psl *lifted = quickLiftPsl(chainHash, &mapPsls, psl); + pslFree(&psl); + psl = lifted; + } + + if (psl == NULL) + liftFailed = TRUE; + else + { + if (quickLiftFile) + { + // bedRow still holds the pre-lift position, and a $chrom or $chromStart in + // a mouseOver has to report where the item is drawn. + safef(startBuf, sizeof startBuf, "%d", psl->tStart); + safef(endBuf, sizeof endBuf, "%d", psl->tEnd); + bedRow[0] = psl->tName; + bedRow[1] = startBuf; + bedRow[2] = endBuf; + } + int sizeMul = pslIsProtein(psl) ? 3 : 1; lf = lfFromPslx(psl, sizeMul, isXeno, nameGetsPos, track); lf->original = psl; if ((seq != NULL) && (lf->orientation == -1)) reverseComplement(seq, strlen(seq)); lf->extra = seq; lf->cds = cds; lf->useItemRgb = useItemRgb; if ( lf->useItemRgb ) lf->filterColor = itemRgbColumn(bedRow[8]); } + } else if (sameString(tdb->type, "bigDbSnp")) { // bigDbSnp does not have a score field, but I want to compute the freqSourceIx from // trackDb and settings one time instead of for each item, so I'm overloading scoreMin. int freqSourceIx = scoreMin; lf = lfFromBigDbSnp(tdb, bb, filters, freqSourceIx, bbi, chainHash); } else { char startBuf[16], endBuf[16]; bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); if (bigBedFilterInterval(bbi, bedRow, filters)) { if (quickLiftFile) {