98572a57d651f8256c0d21e690f5df23fc1ce3c7 braney Tue Jun 23 16:05:31 2026 -0700 hgTracks: show lifted (target) coordinates in quickLift bigBed mouseOvers, refs #37615 Under quickLift the bedRow used for mouseOver substitution is loaded from the source-assembly interval, so $chrom/${chromStart}/${chromEnd} reported the pre-lift position while the position bar showed the lifted position. Overwrite those three coordinate fields with the lifted bed's target coordinates before substituting, so the tooltip matches where the item is drawn. Replaces the earlier disclaimer note that flagged the discrepancy. diff --git src/hg/hgTracks/bigBedTrack.c src/hg/hgTracks/bigBedTrack.c index d48d1f4519b..4431139ac4b 100644 --- src/hg/hgTracks/bigBedTrack.c +++ src/hg/hgTracks/bigBedTrack.c @@ -1,1157 +1,1167 @@ /* bigBed - stuff to handle loading and display of bigBed type tracks in browser. * Mostly just links to bed code, but handles a few things itself, like the dense * drawing code. */ /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "hash.h" #include "linefile.h" #include "jksql.h" #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 "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) errAbort("error building filter with field %s. Field not found.", field); return fieldNum; } struct bigBedFilter *bigBedMakeNumberFilter(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb, char *filter, char *defaultLimits, char *field, boolean isHighlight) /* Make a filter/highlight on this column if the trackDb or cart wants us to. */ { struct bigBedFilter *ret = NULL; char *setting = trackDbSettingClosestToHome(tdb, filter); int fieldNum = getFieldNum(bbi, field); if (setting) { boolean invalid = FALSE; double minValueTdb = 0,maxValueTdb = NO_VALUE; double minLimit=NO_VALUE,maxLimit=NO_VALUE,min = minValueTdb,max = maxValueTdb; colonPairToDoubles(setting,&minValueTdb,&maxValueTdb); colonPairToDoubles(defaultLimits,&minLimit,&maxLimit); getScoreFloatRangeFromCart(cart,tdb,FALSE,filter,&minLimit,&maxLimit,&min,&max); if ((int)minLimit != NO_VALUE || (int)maxLimit != NO_VALUE) { // assume tdb default values within range! // (don't give user errors that have no consequence) if ((min != minValueTdb && (((int)minLimit != NO_VALUE && min < minLimit) || ((int)maxLimit != NO_VALUE && min > maxLimit))) || (max != maxValueTdb && (((int)minLimit != NO_VALUE && max < minLimit) || ((int)maxLimit != NO_VALUE && max > maxLimit)))) { invalid = TRUE; char value[64]; if ((int)max == NO_VALUE) // min only is allowed, but max only is not safef(value, sizeof(value), "entered minimum (%g)", min); else safef(value, sizeof(value), "entered range (min:%g and max:%g)", min, max); char limits[64]; if ((int)minLimit != NO_VALUE && (int)maxLimit != NO_VALUE) safef(limits, sizeof(limits), "violates limits (%g to %g)", minLimit, maxLimit); else if ((int)minLimit != NO_VALUE) safef(limits, sizeof(limits), "violates lower limit (%g)", minLimit); else //if ((int)maxLimit != NO_VALUE) safef(limits, sizeof(limits), "violates uppper limit (%g)", maxLimit); warn("invalid filter by %s: %s %s for track %s", field, value, limits, tdb->track); } } if (invalid) { char filterLimitName[64]; safef(filterLimitName, sizeof(filterLimitName), "%s%s", filter, _MIN); cartRemoveVariableClosestToHome(cart,tdb,FALSE,filterLimitName); safef(filterLimitName, sizeof(filterLimitName), "%s%s", filter, _MAX); cartRemoveVariableClosestToHome(cart,tdb,FALSE,filterLimitName); } else if (((int)min != NO_VALUE && ((int)minLimit == NO_VALUE || minLimit != min)) || ((int)max != NO_VALUE && ((int)maxLimit == NO_VALUE || maxLimit != max))) // Assumes min==NO_VALUE or min==minLimit is no filter // Assumes max==NO_VALUE or max==maxLimit is no filter! { AllocVar(ret); ret->fieldNum = fieldNum; if ((int)max == NO_VALUE || ((int)maxLimit != NO_VALUE && maxLimit == max)) { ret->comparisonType = COMPARE_MORE; ret->value1 = min; } else if ((int)min == NO_VALUE || ((int)minLimit != NO_VALUE && minLimit == min)) { ret->comparisonType = COMPARE_LESS; ret->value1 = max; } else { ret->comparisonType = COMPARE_BETWEEN; ret->value1 = min; ret->value2 = max; } if (isHighlight) ret->isHighlight = TRUE; } } return ret; } struct bigBedFilter *bigBedMakeFilterText(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb, char *filterName, char *field, boolean isHighlight) /* Add a bigBed filter using a trackDb filterText statement. */ { struct bigBedFilter *filter; char *setting = trackDbSettingClosestToHome(tdb, filterName); char *value = cartUsualStringClosestToHome(cart, tdb, FALSE, filterName, setting); if (isEmpty(value)) return NULL; char *typeValue = getFilterType(cart, tdb, field, FILTERTEXT_WILDCARD); AllocVar(filter); filter->fieldNum = getFieldNum(bbi, field); if (sameString(typeValue, FILTERTEXT_REGEXP) ) { filter->comparisonType = COMPARE_REGEXP; regcomp(&filter->regEx, value, REG_NOSUB); } else { filter->comparisonType = COMPARE_WILDCARD; filter->wildCardString = cloneString(value); } filter->isHighlight = isHighlight; return filter; } char *getHighlightType(struct cart *cart, struct trackDb *tdb, char *field, char *def) { char settingString[4096]; safef(settingString, sizeof settingString, "%s.%s", HIGHLIGHT_TYPE_NAME_LOW, field); char *setting = cartOrTdbString(cart, tdb, settingString, NULL); if (setting == NULL) { safef(settingString, sizeof settingString, "%s.%s", field, HIGHLIGHT_TYPE_NAME_CAP); setting = cartOrTdbString(cart, tdb, settingString, NULL); } if (setting == NULL) { safef(settingString, sizeof settingString, "%s%s", field, HIGHLIGHT_TYPE_NAME_CAP); setting = cartOrTdbString(cart, tdb, settingString, def); } return setting; } struct bigBedFilter *bigBedMakeFilterBy(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb, char *field, struct slName *choices, boolean isHighlight) /* Add a bigBed filter using a trackDb filterBy statement. */ { struct bigBedFilter *filter; char *setting = NULL; if (isHighlight) setting = getHighlightType(cart, tdb, field, HIGHLIGHTBY_DEFAULT); else setting = getFilterType(cart, tdb, field, FILTERBY_DEFAULT); AllocVar(filter); filter->fieldNum = getFieldNum(bbi, field); filter->comparisonType = COMPARE_HASH; if (setting) { if (sameString(setting, FILTERBY_SINGLE_LIST) || sameString(setting, FILTERBY_MULTIPLE_LIST_OR) || sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_OR) || sameString(setting, HIGHLIGHTBY_SINGLE_LIST) || sameString(setting, HIGHLIGHTBY_MULTIPLE_LIST_OR) || sameString(setting, HIGHLIGHTBY_MULTIPLE_LIST_ONLY_OR)) filter->comparisonType = COMPARE_HASH_LIST_OR; else if (sameString(setting, FILTERBY_MULTIPLE_LIST_AND) || sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_AND) || sameString(setting, HIGHLIGHTBY_MULTIPLE_LIST_AND) || sameString(setting, HIGHLIGHTBY_MULTIPLE_LIST_ONLY_AND)) filter->comparisonType = COMPARE_HASH_LIST_AND; } filter->valueHash = newHash(5); filter->numValuesInHash = slCount(choices); for(; choices; choices = choices->next) hashStore(filter->valueHash, choices->name); filter->isHighlight = isHighlight; return filter; } static void addGencodeFilters(struct cart *cart, struct trackDb *tdb, struct bigBedFilter **pFilters) /* Add GENCODE custom bigBed filters. */ { struct bigBedFilter *filter; char varName[64]; struct hash *hash; /* canonical */ safef(varName, sizeof(varName), "%s.show.spliceVariants", tdb->track); boolean option = cartUsualBoolean(cart, varName, TRUE); if (!option) { AllocVar(filter); slAddHead(pFilters, filter); filter->fieldNum = 25; filter->comparisonType = COMPARE_HASH_LIST_OR; hash = newHash(5); filter->valueHash = hash; filter->numValuesInHash = 1; hashStore(hash, "canonical" ); } /* transcript class */ AllocVar(filter); slAddHead(pFilters, filter); filter->fieldNum = 20; filter->comparisonType = COMPARE_HASH; hash = newHash(5); filter->valueHash = hash; filter->numValuesInHash = 1; hashStore(hash,"coding"); // coding is always included safef(varName, sizeof(varName), "%s.show.noncoding", tdb->track); if (cartUsualBoolean(cart, varName, TRUE)) { filter->numValuesInHash++; hashStore(hash,"nonCoding"); } safef(varName, sizeof(varName), "%s.show.pseudo", tdb->track); if (cartUsualBoolean(cart, varName, FALSE)) { filter->numValuesInHash++; hashStore(hash,"pseudo"); } /* tagged sets */ safef(varName, sizeof(varName), "%s.show.set", tdb->track); char *setString = cartUsualString(cart, varName, "basic"); if (differentString(setString, "all")) { AllocVar(filter); slAddHead(pFilters, filter); filter->fieldNum = 23; filter->comparisonType = COMPARE_HASH_LIST_OR; hash = newHash(5); filter->valueHash = hash; filter->numValuesInHash = 1; hashStore(hash, setString); } } struct bigBedFilter *bigBedBuildFilters(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb) /* Build all the numeric and filterBy filters for a bigBed */ { struct bigBedFilter *filters = NULL, *filter; struct trackDbFilter *tdbFilters = tdbGetTrackNumFilters(tdb); if ((tdbFilters == NULL) && !trackDbSettingOn(tdb, "noScoreFilter") && (bbi->definedFieldCount >= 5)) { AllocVar(filter); slAddHead(&filters, filter); filter->fieldNum = 4; filter->comparisonType = COMPARE_MORE; char buffer[2048]; safef(buffer, sizeof buffer, "%s.scoreFilter", tdb->track); filter->value1 = cartUsualDouble(cart, buffer, 0.0); } for(; tdbFilters; tdbFilters = tdbFilters->next) { if ((filter = bigBedMakeNumberFilter(cart, bbi, tdb, tdbFilters->name, NULL, tdbFilters->fieldName, FALSE)) != NULL) slAddHead(&filters, filter); } tdbFilters = tdbGetTrackTextFilters(tdb); for(; tdbFilters; tdbFilters = tdbFilters->next) { if ((filter = bigBedMakeFilterText(cart, bbi, tdb, tdbFilters->name, tdbFilters->fieldName, FALSE)) != NULL) slAddHead(&filters, filter); } filterBy_t *filterBySet = filterBySetGet(tdb, cart,NULL); filterBy_t *filterBy = filterBySet; for (;filterBy != NULL; filterBy = filterBy->next) { if (filterBy->slChoices && differentString(filterBy->slChoices->name, "All")) { if ((filter = bigBedMakeFilterBy(cart, bbi, tdb, filterBy->column, filterBy->slChoices, FALSE)) != NULL) slAddHead(&filters, filter); } } /* custom gencode filters */ boolean isGencode3 = trackDbSettingOn(tdb, "isGencode3"); if (isGencode3) addGencodeFilters(cart, tdb, &filters); return filters; } struct bigBedFilter *bigBedBuildHighlights(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb) /* Build all the numeric and highlights for a bigBed */ { struct bigBedFilter *highlights = NULL, *highlight; struct trackDbFilter *tdbHighlights = tdbGetTrackNumHighlights(tdb); for(; tdbHighlights; tdbHighlights = tdbHighlights->next) { if ((highlight = bigBedMakeNumberFilter(cart, bbi, tdb, tdbHighlights->name, NULL, tdbHighlights->fieldName, TRUE)) != NULL) slAddHead(&highlights, highlight); } tdbHighlights = tdbGetTrackTextHighlights(tdb); for(; tdbHighlights; tdbHighlights = tdbHighlights->next) { if ((highlight = bigBedMakeFilterText(cart, bbi, tdb, tdbHighlights->name, tdbHighlights->fieldName, TRUE)) != NULL) slAddHead(&highlights, highlight); } filterBy_t *filterBySet = highlightBySetGet(tdb, cart,NULL); filterBy_t *filterBy = filterBySet; for (;filterBy != NULL; filterBy = filterBy->next) { if (filterBy->slChoices && differentString(filterBy->slChoices->name, "All")) { if ((highlight = bigBedMakeFilterBy(cart, bbi, tdb, filterBy->column, filterBy->slChoices, TRUE)) != NULL) slAddHead(&highlights, highlight); } } return highlights; } boolean bigBedFilterOne(struct bigBedFilter *filter, char **bedRow, struct bbiFile *bbi) /* Return TRUE if a bedRow passes one filter or is in hgFindMatches */ { if ((bbi->definedFieldCount > 3) && (hgFindMatches != NULL) && (bedRow[3] != NULL) && hashLookup(hgFindMatches, bedRow[3]) != NULL) return TRUE; double val = atof(bedRow[filter->fieldNum]); switch(filter->comparisonType) { case COMPARE_WILDCARD: if ( !wildMatch(filter->wildCardString, bedRow[filter->fieldNum])) return FALSE; break; case COMPARE_REGEXP: if (regexec(&filter->regEx,bedRow[filter->fieldNum], 0, NULL,0 ) != 0) return FALSE; break; case COMPARE_HASH_LIST_AND: case COMPARE_HASH_LIST_OR: { struct slName *values = commaSepToSlNames(bedRow[filter->fieldNum]); unsigned found = 0; struct hash *seenHash = newHash(3); for(; values; values = values->next) { if (hashLookup(seenHash, values->name)) continue; hashStore(seenHash, values->name); if (hashLookup(filter->valueHash, values->name)) { found++; if (filter->comparisonType == COMPARE_HASH_LIST_OR) break; } } if (filter->comparisonType == COMPARE_HASH_LIST_AND) { if (found < filter->numValuesInHash) return FALSE; } else if (!found) return FALSE; } break; case COMPARE_HASH: if (!hashLookup(filter->valueHash, bedRow[filter->fieldNum])) return FALSE; break; case COMPARE_LESS: if (!(val <= filter->value1)) return FALSE; break; case COMPARE_MORE: if (!(val >= filter->value1)) return FALSE; break; case COMPARE_BETWEEN: if (!((val >= filter->value1) && (val <= filter->value2))) return FALSE; break; } return TRUE; } boolean bigBedFilterInterval(struct bbiFile *bbi, char **bedRow, struct bigBedFilter *filters) /* Go through a row and filter based on filters. Return TRUE if all filters are passed. */ { if ((bbi->definedFieldCount > 3) && (hgFindMatches != NULL) && (bedRow[3] != NULL) && hashLookup(hgFindMatches, bedRow[3]) != NULL) return TRUE; struct bigBedFilter *filter; for(filter = filters; filter; filter = filter->next) if (!bigBedFilterOne(filter, bedRow, bbi)) return FALSE; return TRUE; } struct bbiFile *fetchBbiForTrack(struct track *track) /* Fetch bbiFile from track, opening it if it is not already open. */ { struct bbiFile *bbi = track->bbiFile; if (bbi == NULL) { char *fileName = NULL; if (track->parallelLoading) // do not use mysql during parallel fetch { fileName = hReplaceGbdb(trackDbSetting(track->tdb, "bigDataUrl")); if (fileName == NULL) fileName = hReplaceGbdb(trackDbSetting(track->tdb, "bigGeneDataUrl")); } else { struct sqlConnection *conn = NULL; if (!trackHubDatabase(database)) conn = hAllocConnTrack(database, track->tdb); fileName = bbiNameFromSettingOrTable(track->tdb, conn, track->table); hFreeConn(&conn); } #ifdef USE_GBIB_PWD #include "gbib.c" #endif bbi = track->bbiFile = bigBedFileOpenAlias(fileName, chromAliasFindAliases); } return bbi; } static unsigned bigBedMaxItems() /* Get the maximum number of items to grab from a bigBed file. Defaults to ten thousand . */ { static boolean set = FALSE; static unsigned maxItems = 0; if (!set) { char *maxItemsStr = cfgOptionDefault("bigBedMaxItems", "10000"); maxItems = sqlUnsigned(maxItemsStr); set = TRUE; } return maxItems; } static boolean hasOverflowedInWindow(struct track *track) /* has it overlowed in the given track? */ { uint resultCount = 0; // do not use -1, it messes up the compare of signed resultsCount with unsigned bigMaxItems. char *resultCountString = trackDbSetting(track->tdb, "bigBedItemsCount"); if (resultCountString) resultCount = sqlUnsigned(resultCountString); return (resultCount > bigBedMaxItems()); } static void loadBigBedSummary(struct track *track) /* Check if summary loading needed for bigBed */ { if (track->subtracks) // do tracks or subtracks but not parents. { return; } struct lm *lm = lmInit(0); char *chrom = chromName; int start = winStart; int end = winEnd; /* protect against temporary network error */ struct errCatch *errCatch = errCatchNew(); boolean filtering = FALSE; // for the moment assume we're not filtering if (errCatchStart(errCatch)) { // scan all windows for errors and overflows boolean errorsInWindows = FALSE; boolean overFlowedInWindows = FALSE; struct track *thisTrack; for(thisTrack=track->prevWindow; thisTrack; thisTrack=thisTrack->prevWindow) { if (hasOverflowedInWindow(thisTrack)) overFlowedInWindows = TRUE; if (thisTrack->drawItems == bigDrawWarning) errorsInWindows = TRUE; } for(thisTrack=track->nextWindow; thisTrack; thisTrack=thisTrack->nextWindow) { if (hasOverflowedInWindow(thisTrack)) overFlowedInWindows = TRUE; if (thisTrack->drawItems == bigDrawWarning) errorsInWindows = TRUE; } if (hasOverflowedInWindow(track)) overFlowedInWindows = TRUE; if (!errorsInWindows && overFlowedInWindows) { if (filtering) errAbort("Too many items in window to filter.Zoom in or remove filters to view track."); else { struct bbiFile *bbi = fetchBbiForTrack(track); if (bbi) { // use summary levels if (track->visibility != tvDense) { track->limitedVis = tvFull; track->limitWiggle = TRUE; track->limitedVisSet = TRUE; } else { track->limitedVis = tvDense; track->limitedVisSet = TRUE; } AllocArray(track->summary, insideWidth); if (bigBedSummaryArrayExtended(bbi, chrom, start, end, insideWidth, track->summary)) { char *denseCoverage = trackDbSettingClosestToHome(track->tdb, "denseCoverage"); if (denseCoverage != NULL) { double endVal = atof(denseCoverage); if (endVal <= 0) { AllocVar(track->sumAll); *track->sumAll = bbiTotalSummary(bbi); } } } else freez(&track->summary); } } } } errCatchEnd(errCatch); if (errCatch->gotError) { track->networkErrMsg = cloneString(errCatch->message->string); track->drawItems = bigDrawWarning; track->totalHeight = bigWarnTotalHeight; } errCatchFree(&errCatch); lmCleanup(&lm); track->bbiFile = NULL; } struct bigBedInterval *bigBedSelectRangeExt(struct track *track, char *chrom, int start, int end, struct lm *lm, int maxItems) /* Return list of intervals in range. */ { struct bigBedInterval *result = NULL; /* protect against temporary network error */ struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) { struct bbiFile *bbi = fetchBbiForTrack(track); result = bigBedIntervalQuery(bbi, chrom, start, end, bigBedMaxItems() + 1, lm); // pass in desired limit or 0 for all. char resultCount[32]; safef(resultCount, sizeof resultCount, "%u", slCount(result)); trackDbAddSetting(track->tdb, "bigBedItemsCount", resultCount); if (slCount(result) > bigBedMaxItems()) { result = NULL; // IS Having it return NULL a critical part of this? } track->bbiFile = NULL; } errCatchEnd(errCatch); if (errCatch->gotError) { track->networkErrMsg = cloneString(errCatch->message->string); track->drawItems = bigDrawWarning; track->totalHeight = bigWarnTotalHeight; result = NULL; } errCatchFree(&errCatch); return result; } char* restField(struct bigBedInterval *bb, int fieldIdx) /* return a given field from the bb->rest field, NULL on error */ { if (fieldIdx==0) // we don't return the first(=name) field of bigBed return NULL; char *rest = cloneString(bb->rest); char *restFields[1024]; int restCount = chopTabs(rest, restFields); char *field = NULL; if (fieldIdx < restCount) field = cloneString(restFields[fieldIdx]); freeMem(rest); return field; } void addHighlightToLinkedFeature(struct linkedFeatures *lf, struct bigBedFilter *highlights, struct bbiFile *bbi, char **bedRow, struct trackDb *tdb) /* Fill out the lf->highlightColor if the cart says to highlight this item. The color will * be the 'average' of all the highlight colors specified */ { struct bigBedFilter *highlight; char *cartHighlightColor = cartOrTdbString(cart, tdb, HIGHLIGHT_COLOR_CART_VAR, HIGHLIGHT_COLOR_DEFAULT); for (highlight = highlights; highlight != NULL; highlight = highlight->next) { if (bigBedFilterOne(highlight, bedRow, bbi)) { unsigned rgb = bedParseColor(cartHighlightColor); Color color = bedColorToGfxColor(rgb); lf->highlightColor = color; lf->highlightMode = highlightBackground; } } } +static void quickLiftSetCoordFields(char **bedRow, struct bed *liftedBed, + char *startBuf, char *endBuf, int bufSize) +/* Overwrite the chrom/chromStart/chromEnd entries (the first three bigBed fields) of bedRow + * with the lifted, target-assembly coordinates from liftedBed. Under quickLift bedRow is + * loaded from the source-assembly interval, so without this a $chrom/${chromStart}/${chromEnd} + * mouseOver substitution would report the pre-lift position instead of where the item is drawn. */ +{ +safef(startBuf, bufSize, "%u", liftedBed->chromStart); +safef(endBuf, bufSize, "%u", liftedBed->chromEnd); +bedRow[0] = liftedBed->chrom; +bedRow[1] = startBuf; +bedRow[2] = endBuf; +} + void bigBedAddLinkedFeaturesFromExt(struct track *track, char *chrom, int start, int end, int scoreMin, int scoreMax, boolean useItemRgb, int fieldCount, struct linkedFeatures **pLfList, int maxItems) /* Read in items in chrom:start-end from bigBed file named in track->bbiFileName, convert * them to linkedFeatures, and add to head of list. */ { struct lm *lm = lmInit(0); struct trackDb *tdb = track->tdb; char *mouseOverField = cartOrTdbString(cart, track->tdb, "mouseOverField", NULL); // check if this track can merge large items, this setting must be allowed in the trackDb // stanza for the track, but can be enabled/disabled via trackUi/right click menu so // we also need to check the cart for the current status int mergeCount = 0; boolean doWindowSizeFilter = trackDbSettingOn(track->tdb, MERGESPAN_TDB_SETTING); if (doWindowSizeFilter) { char hasMergedItemsSetting[256]; safef(hasMergedItemsSetting, sizeof(hasMergedItemsSetting), "%s.%s", track->track, MERGESPAN_CART_SETTING); if (cartVarExists(cart, hasMergedItemsSetting)) doWindowSizeFilter = cartInt(cart, hasMergedItemsSetting) == 1; else // save the cart var so javascript can offer the right toggle cartSetInt(cart, hasMergedItemsSetting, 1); } /* protect against temporary network error */ struct bbiFile *bbi = NULL; struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) { bbi = fetchBbiForTrack(track); } errCatchEnd(errCatch); if (errCatch->gotError) { track->networkErrMsg = cloneString(errCatch->message->string); track->drawItems = bigDrawWarning; track->totalHeight = bigWarnTotalHeight; return; } errCatchFree(&errCatch); fieldCount = track->bedSize; 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: