5dc1d6e658ab009f27314e192340275a6bb70237 max Tue Jun 2 16:20:48 2026 -0700 Add colorFields trackDb setting for bigBed/bigGenePred color scheme switching Adds a new trackDb statement `colorFields` that renders a "Color by:" dropdown in the track controls page, letting users switch among multiple pre-computed color schemes stored as extra bigBed fields containing R,G,B strings. The `default="label"` key renames the standard itemRgb option in the dropdown. Other entries name extra bigBed fields whose R,G,B values override itemRgb when selected. When a non-default scheme is active, a "(Coloring by: label)" suffix appears in the track long label. Changes: - hui.c/hui.h: new colorFieldsCfgUi() rendered inside bedScoreCfgUi() for bigBed - bigBedTrack.c: colorFieldIdx lookup + per-item filterColor override + longLabel suffix - tagTypes.tab: register colorFields for bigBed and bigGenePred - trackDbLibrary.shtml, trackDbDoc.html, trackDbHub.v3.html, changes.html: documentation refs #26253 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> diff --git src/hg/hgTracks/bigBedTrack.c src/hg/hgTracks/bigBedTrack.c index 95edcc0f7b5..d48d1f4519b 100644 --- src/hg/hgTracks/bigBedTrack.c +++ src/hg/hgTracks/bigBedTrack.c @@ -710,30 +710,55 @@ boolean bigBedOnePath = cfgOptionBooleanDefault("bigBedOnePath", TRUE); if (bigBedOnePath && (fieldCount == 0)) track->bedSize = fieldCount = bbi->definedFieldCount; struct bigBedInterval *bb, *bbList; char *quickLiftFile = cloneString(trackDbSetting(track->tdb, "quickLiftUrl")); struct hash *chainHash = NULL; if (quickLiftFile) bbList = quickLiftGetIntervals(quickLiftFile, bbi, chromName, winStart, winEnd, &chainHash); else bbList = bigBedSelectRangeExt(track, chrom, start, end, lm, maxItems); char *squishField = cartOrTdbString(cart, track->tdb, "squishyPackField", NULL); int squishFieldIdx = bbExtraFieldIndex(bbi, squishField); +/* colorFields: optional alternative color scheme stored in a named extra field. */ +int colorFieldIdx = 0; +char *colorFieldsSetting = trackDbSettingClosestToHome(tdb, "colorFields"); +if (useItemRgb && colorFieldsSetting) + { + char *colorFieldName = cartOptionalStringClosestToHome(cart, tdb, FALSE, "colorField"); + if (!isEmpty(colorFieldName)) + { + colorFieldIdx = bbExtraFieldIndex(bbi, colorFieldName); + /* Append "(Coloring by: <label>)" to the track's longLabel. + * Look up the human-readable label from the colorFields key=value list. */ + char *label = colorFieldName; + struct slPair *pairs = slPairListFromString(colorFieldsSetting, TRUE); + if (pairs) + { + struct slPair *p = slPairFind(pairs, colorFieldName); + if (p && isNotEmpty((char *)p->val)) + label = (char *)p->val; + } + char suffix[256]; + safef(suffix, sizeof suffix, " (Coloring by: %s)", label); + track->longLabel = catTwoStrings(track->longLabel, suffix); + } + } + 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) ; struct bigBedFilter *highlights = bigBedBuildHighlights(cart, bbi, track->tdb) ; if (compositeChildHideEmptySubtracks(cart, track->tdb, NULL, NULL)) labelTrackAsHideEmpty(track); @@ -832,30 +857,33 @@ 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)); + if (lf && colorFieldIdx) + lf->filterColor = itemRgbColumn(restField(bb, colorFieldIdx)); + if (track->visibility != tvDense && lf && doWindowSizeFilter && (quickLiftFile ? lf->start : bb->start) < winStart && (quickLiftFile ? lf->end : bb->end) > winEnd) { mergeCount++; struct linkedFeatures *tmp; if (quickLiftFile) { struct bed *mergeBed = cloneBed(bedCopy); tmp = bedMungToLinkedFeatures(&mergeBed, tdb, fieldCount, scoreMin, scoreMax, useItemRgb); } else { struct bed *bed = bedLoadN(bedRow, fieldCount);