b8e7a2261f97338a614b7eed2aa6131da27510e1 chmalee Tue Sep 1 10:47:36 2020 -0700 Add bigBed support for trackDb constructed mouseOvers, refs #26160 diff --git src/hg/hgTracks/bigBedTrack.c src/hg/hgTracks/bigBedTrack.c index e45ad57..a5fa699 100644 --- src/hg/hgTracks/bigBedTrack.c +++ src/hg/hgTracks/bigBedTrack.c @@ -494,62 +494,76 @@ int seqTypeField = 0; if (sameString(track->tdb->type, "bigPsl")) { seqTypeField = bbExtraFieldIndex(bbi, "seqType"); } int mouseOverIdx = bbExtraFieldIndex(bbi, mouseOverField); track->bbiFile = NULL; struct bigBedFilter *filters = bigBedBuildFilters(cart, bbi, track->tdb) ; if (compositeChildHideEmptySubtracks(cart, track->tdb, NULL, NULL)) labelTrackAsHideEmpty(track); +// mouseOvers can be built constructed via trackDb settings instead +// of embedded directly in bigBed +char *mouseOverPattern = NULL; +char **fieldNames = NULL; +if (!mouseOverIdx) + { + mouseOverPattern = cartOrTdbString(cart, track->tdb, "mouseOver", NULL); + 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; for (bb = bbList; bb != NULL; bb = bb->next) { struct linkedFeatures *lf = NULL; + char *bedRow[bbi->fieldCount]; if (sameString(track->tdb->type, "bigPsl")) { 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 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; } 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); } else { char startBuf[16], endBuf[16]; - char *bedRow[bbi->fieldCount]; bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); if (bigBedFilterInterval(bedRow, filters)) { struct bed *bed = bedLoadN(bedRow, fieldCount); lf = bedMungToLinkedFeatures(&bed, tdb, fieldCount, scoreMin, scoreMax, useItemRgb); } if (track->visibility != tvDense && lf && doWindowSizeFilter && bb->start < winStart && bb->end > winEnd) { mergeCount++; struct bed *bed = bedLoadN(bedRow, fieldCount); struct linkedFeatures *tmp = bedMungToLinkedFeatures(&bed, tdb, fieldCount, scoreMin, scoreMax, useItemRgb); if (spannedLf) { @@ -563,54 +577,59 @@ struct rgbColor currColor = colorIxToRgb(spannedLf->filterColor); int r = currColor.r + round((itemColor.r - currColor.r) / mergeCount); int g = currColor.g + round((itemColor.g - currColor.g) / mergeCount); int b = currColor.b + round((itemColor.b - currColor.b) / mergeCount); spannedLf->filterColor = MAKECOLOR_32(r,g,b); } } else { // setting the label here protects against the case when only one item would // have been merged. When this happens we warn in the track longLabel that // nothing happened and essentially make the spanned item be what the actual // item would be. If multiple items are merged then the labels and mouseOvers // will get fixed up later tmp->label = bigBedMakeLabel(track->tdb, track->labelColumns, bb, chromName); + if (mouseOverIdx > 0) tmp->mouseOver = restField(bb, mouseOverIdx); + else if (mouseOverPattern) + 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) { filtered++; continue; } if (lf->label == NULL) lf->label = bigBedMakeLabel(track->tdb, track->labelColumns, bb, chromName); if (sameString(track->tdb->type, "bigGenePred") || startsWith("genePred", track->tdb->type)) { lf->original = genePredFromBigGenePred(chromName, bb); } if (lf->mouseOver == NULL) { - char* mouseOver = restField(bb, mouseOverIdx); - lf->mouseOver = mouseOver; // leaks some memory, cloneString handles NULL ifself + if (mouseOverIdx > 0) + lf->mouseOver = restField(bb, mouseOverIdx); + else if (mouseOverPattern) + lf->mouseOver = replaceFieldInPattern(mouseOverPattern, bbi->fieldCount, fieldNames, bedRow); } slAddHead(pLfList, lf); } if (filtered) labelTrackAsFilteredNumber(track, filtered); 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)");